Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband:
  IB/mlx4: Add a driver Mellanox ConnectX InfiniBand adapters
  IB: Put rlimit accounting struct in struct ib_umem
  IB/uverbs: Export ib_umem_get()/ib_umem_release() to modules
diff --git a/CREDITS b/CREDITS
index 80e2413..6829e91 100644
--- a/CREDITS
+++ b/CREDITS
@@ -380,7 +380,7 @@
 S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG
 S: United Kingdom
 
-N: Thomas Bogendörfer
+N: Thomas Bogendörfer
 E: tsbogend@alpha.franken.de
 D: PCnet32 driver, SONIC driver, JAZZ_ESP driver
 D: newport abscon driver, g364 framebuffer driver
@@ -400,7 +400,7 @@
 D: Configuration help text support
 D: Linux CD and Support Giveaway List
 
-N: Erik Inge Bolsø
+N: Erik Inge Bolsø
 E: knan@mo.himolde.no
 D: Misc kernel hacks
 
@@ -428,7 +428,7 @@
 S: Montreal, Quebec
 S: Canada
 
-N: Zoltán Böszörményi
+N: Zoltán Böszörményi
 E: zboszor@mail.externet.hu
 D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
 
@@ -1029,11 +1029,11 @@
 D: APM driver (early port)
 D: DRM drivers (author of several)
 
-N: János Farkas
+N: János Farkas
 E: chexum@shadow.banki.hu
 D: romfs, various (mostly networking) fixes
 P: 1024/F81FB2E1 41 B7 E4 E6 3E D4 A6 71  6D 9C F3 9F F2 BF DF 6E
-S: Madarász Viktor utca 25
+S: Madarász Viktor utca 25
 S: 1131 Budapest
 S: Hungary
 
@@ -1044,10 +1044,10 @@
 S: (ask for current address)
 S: USA
 
-N: Jürgen Fischer
-E: fischer@norbit.de (=?iso-8859-1?q?J=FCrgen?= Fischer)
+N: Jürgen Fischer
+E: fischer@norbit.de
 D: Author of Adaptec AHA-152x SCSI driver
-S: Schulstraße 18
+S: Schulstraße 18
 S: 26506 Norden
 S: Germany
 
@@ -1113,7 +1113,7 @@
 D: random kernel hacker, ZF MachZ Watchdog driver
 S: Conectiva S.A.
 S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
 N: Kumar Gala
@@ -1258,12 +1258,12 @@
 S: Toronto, Ontario, M4Y 2W4
 S: Canada
 
-N: Richard Günther
+N: Richard Günther
 E: rguenth@tat.physik.uni-tuebingen.de
 W: http://www.tat.physik.uni-tuebingen.de/~rguenth
 P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2  93 7A 32 42 45 37 23 57
 D: binfmt_misc
-S: 72074 Tübingen
+S: 72074 Tübingen
 S: Germany
 
 N: Justin Guyett
@@ -1287,7 +1287,7 @@
 E: haible@ma2s2.mathematik.uni-karlsruhe.de
 D: SysV FS, shm swapping, memory management fixes
 S: 17 rue Danton
-S: F - 94270 Le Kremlin-Bicêtre
+S: F - 94270 Le Kremlin-Bicêtre
 S: France
 
 N: Greg Hankins
@@ -1701,7 +1701,7 @@
 N: Jakob Kemi
 E: jakob.kemi@telia.com
 D: V4L W9966 Webcam driver
-S: Forsbyvägen 33
+S: Forsbyvägen 33
 S: 74143 Knivsta
 S: Sweden
 
@@ -2065,7 +2065,7 @@
 S: Cambridge, MA 02139
 S: USA
 
-N: Martin von Löwis
+N: Martin von Löwis
 E: loewis@informatik.hu-berlin.de
 D: script binary format
 D: NTFS driver
@@ -2142,7 +2142,7 @@
 S: Halifax, Nova Scotia
 S: Canada B3J 3C8
 
-N: Kai Mäkisara
+N: Kai Mäkisara
 E: Kai.Makisara@kolumbus.fi
 D: SCSI Tape Driver
 
@@ -2785,10 +2785,10 @@
 E: quintela@fi.udc.es
 D: Memory Management hacking
 S: LFCIA
-S: Departamento de Computación
-S: Universidade da Coruña
+S: Departamento de Computación
+S: Universidade da Coruña
 S: E-15071
-S: A Coruña
+S: A Coruña
 S: Spain
 
 N: Augusto Cesar Radtke
@@ -2939,7 +2939,7 @@
 D: Support for EtherExpress 10 ISA (i82595) in eepro driver
 D: User level driver support for input
 S: R. Jose Serrato, 130 - Santa Candida
-S: 82640-320 - Curitiba - Paraná
+S: 82640-320 - Curitiba - Paraná
 S: Brazil
 
 N: Alessandro Rubini
@@ -3345,15 +3345,15 @@
 D: rcutorture maintainer
 D: lock annotations, finding and fixing lock bugs
 
-N: Winfried Trümper
+N: Winfried Trümper
 E: winni@xpilot.org
 W: http://www.shop.de/~winni/
 D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
 D: CD-Writing HOWTO, various mini-HOWTOs
 D: One-week tutorials on Linux twice a year (free of charge)
-D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
+D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
 S: Tacitusstr. 6
-S: D-50968 Köln
+S: D-50968 Köln
 
 N: Tsu-Sheng Tsao
 E: tsusheng@scf.usc.edu
diff --git a/Documentation/ABI/removed/devfs b/Documentation/ABI/removed/devfs
index 8195c4e..8ffd28b 100644
--- a/Documentation/ABI/removed/devfs
+++ b/Documentation/ABI/removed/devfs
@@ -6,7 +6,7 @@
 	races, contains a naming policy within the kernel that is
 	against the LSB, and can be replaced by using udev.
 	The files fs/devfs/*, include/linux/devfs_fs*.h were removed,
-	along with the the assorted devfs function calls throughout the
+	along with the assorted devfs function calls throughout the
 	kernel tree.
 
 Users:
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index a2b2b4d..38f88b6 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -84,6 +84,10 @@
 !Ekernel/rcupdate.c
      </sect1>
 
+     <sect1><title>Device Resource Management</title>
+!Edrivers/base/devres.c
+     </sect1>
+
   </chapter>
 
   <chapter id="adt">
diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt
index d389388..0d82407 100644
--- a/Documentation/MSI-HOWTO.txt
+++ b/Documentation/MSI-HOWTO.txt
@@ -480,8 +480,8 @@
 
 6.1. Disabling MSI on a single device
 
-Under some circumstances, it might be required to disable MSI on a
-single device, It may be achived by either not calling pci_enable_msi()
+Under some circumstances it might be required to disable MSI on a
+single device.  This may be achieved by either not calling pci_enable_msi()
 or all, or setting the pci_dev->no_msi flag before (most of the time
 in a quirk).
 
@@ -492,7 +492,7 @@
 disabled on all devices behind this bridge. It is achieves by setting
 the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
 subordinate bus. There is no need to set the same flag on bridges that
-are below the broken brigde. When pci_enable_msi() is called to enable
+are below the broken bridge. When pci_enable_msi() is called to enable
 MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
 flag in all parent busses of the device.
 
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index bd23dc0..6491b2c 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -80,3 +80,7 @@
 23: Tested after it has been merged into the -mm patchset to make sure
     that it still works with all of the other queued patches and various
     changes in the VM, VFS, and other subsystems.
+
+24: Avoid whitespace damage such as indenting with spaces or whitespace
+    at the end of lines.  You can test this by feeding the patch to
+    "git apply --check --whitespace=error-all"
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index b0d0043..a417b25 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -363,7 +363,8 @@
 The "summary phrase" in the email's Subject should concisely
 describe the patch which that email contains.  The "summary
 phrase" should not be a filename.  Do not use the same "summary
-phrase" for every patch in a whole patch series.
+phrase" for every patch in a whole patch series (where a "patch
+series" is an ordered sequence of multiple, related patches).
 
 Bear in mind that the "summary phrase" of your email becomes
 a globally-unique identifier for that patch.  It propagates
diff --git a/Documentation/arm/Interrupts b/Documentation/arm/Interrupts
index 72c93de..0d3dbf1 100644
--- a/Documentation/arm/Interrupts
+++ b/Documentation/arm/Interrupts
@@ -149,7 +149,7 @@
 
 3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
 
-4. Direct access to SA1111 INTPOL is depreciated.  Use set_irq_type instead.
+4. Direct access to SA1111 INTPOL is deprecated.  Use set_irq_type instead.
 
 5. A handler is expected to perform any necessary acknowledgement of the
    parent IRQ via the correct chip specific function.  For instance, if
diff --git a/Documentation/arm/Samsung-S3C24XX/H1940.txt b/Documentation/arm/Samsung-S3C24XX/H1940.txt
index d6b1de9..f4a7b22 100644
--- a/Documentation/arm/Samsung-S3C24XX/H1940.txt
+++ b/Documentation/arm/Samsung-S3C24XX/H1940.txt
@@ -23,7 +23,7 @@
 
     http://handhelds.org/moin/moin.cgi/HpIpaqH1940
 
-  Herbert Pötzl pages:
+  Herbert Pötzl pages:
 
     http://vserver.13thfloor.at/H1940/
 
@@ -32,7 +32,7 @@
 -----------
 
   This project is being maintained and developed by a variety
-  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
 
   Thanks to the many others who have also provided support.
 
diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b
index 3572b98..b714183 100644
--- a/Documentation/auxdisplay/cfag12864b
+++ b/Documentation/auxdisplay/cfag12864b
@@ -78,9 +78,9 @@
 Ground (18)---[GND]              [+5v]---(19) LED +
 Ground (19)---[GND]
 Ground (20)---[GND]              E    A             Values:
-Ground (21)---[GND]       [GND]---[P1]---(18) Vee    · R = Resistor = 22 ohm
-Ground (22)---[GND]                |                 · P1 = Preset = 10 Kohm
-Ground (23)---[GND]       ----   S ------( 3) V0     · P2 = Preset = 1 Kohm
+Ground (21)---[GND]       [GND]---[P1]---(18) Vee    - R = Resistor = 22 ohm
+Ground (22)---[GND]                |                 - P1 = Preset = 10 Kohm
+Ground (23)---[GND]       ----   S ------( 3) V0     - P2 = Preset = 1 Kohm
 Ground (24)---[GND]       |  |
 Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED -
 
diff --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt
index d097f09ee..f609ebf 100644
--- a/Documentation/binfmt_misc.txt
+++ b/Documentation/binfmt_misc.txt
@@ -113,4 +113,4 @@
 There is a web page about binfmt_misc at
 http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
 
-Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
+Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
index 96ccf68..1b930ef 100644
--- a/Documentation/block/ioprio.txt
+++ b/Documentation/block/ioprio.txt
@@ -6,10 +6,10 @@
 -----
 
 With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
-priorities is supported for reads on files. This enables users to io nice
-processes or process groups, similar to what has been possible to cpu
-scheduling for ages. This document mainly details the current possibilites
-with cfq, other io schedulers do not support io priorities so far.
+priorities are supported for reads on files.  This enables users to io nice
+processes or process groups, similar to what has been possible with cpu
+scheduling for ages.  This document mainly details the current possibilities
+with cfq; other io schedulers do not support io priorities thus far.
 
 Scheduling classes
 ------------------
diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt
index 53d62c1..fc64749 100644
--- a/Documentation/cpu-freq/cpufreq-stats.txt
+++ b/Documentation/cpu-freq/cpufreq-stats.txt
@@ -17,7 +17,7 @@
 
 1. Introduction
 
-cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
+cpufreq-stats is a driver that provides CPU frequency statistics for each CPU.
 These statistics are provided in /sysfs as a bunch of read_only interfaces. This
 interface (when configured) will appear in a separate directory under cpufreq
 in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index cc60d29..b6d24c2 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -217,14 +217,17 @@
 A: The following happen, listed in no particular order :-)
 
 - A notification is sent to in-kernel registered modules by sending an event
-  CPU_DOWN_PREPARE
+  CPU_DOWN_PREPARE or CPU_DOWN_PREPARE_FROZEN, depending on whether or not the
+  CPU is being offlined while tasks are frozen due to a suspend operation in
+  progress
 - All process is migrated away from this outgoing CPU to a new CPU
 - All interrupts targeted to this CPU is migrated to a new CPU
 - timers/bottom half/task lets are also migrated to a new CPU
 - Once all services are migrated, kernel calls an arch specific routine
   __cpu_disable() to perform arch specific cleanup.
 - Once this is successful, an event for successful cleanup is sent by an event
-  CPU_DEAD.
+  CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the
+  CPU is being offlined).
 
   "It is expected that each service cleans up when the CPU_DOWN_PREPARE
   notifier is called, when CPU_DEAD is called its expected there is nothing
@@ -242,9 +245,11 @@
 
 		switch (action) {
 		case CPU_ONLINE:
+		case CPU_ONLINE_FROZEN:
 			foobar_online_action(cpu);
 			break;
 		case CPU_DEAD:
+		case CPU_DEAD_FROZEN:
 			foobar_dead_action(cpu);
 			break;
 		}
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index 9b84b805..a2ac6d2 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -177,7 +177,7 @@
 and;
   
   Nettle (http://www.lysator.liu.se/~nisse/nettle/)
-    Niels Möller
+    Niels Möller
 
 Original developers of the crypto algorithms:
 
@@ -200,8 +200,8 @@
   
 DES algorithm contributors:
   Raimar Falke
-  Gisle Sælensminde
-  Niels Möller
+  Gisle Sælensminde
+  Niels Möller
 
 Blowfish algorithm contributors:
   Herbert Valerio Riedel
diff --git a/Documentation/device-mapper/delay.txt b/Documentation/device-mapper/delay.txt
new file mode 100644
index 0000000..15adc55
--- /dev/null
+++ b/Documentation/device-mapper/delay.txt
@@ -0,0 +1,26 @@
+dm-delay
+========
+
+Device-Mapper's "delay" target delays reads and/or writes
+and maps them to different devices.
+
+Parameters:
+    <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+
+With separate write parameters, the first set is only used for reads.
+Delays are specified in milliseconds.
+
+Example scripts
+===============
+[[
+#!/bin/sh
+# Create device delaying rw operation for 500ms
+echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
+]]
+
+[[
+#!/bin/sh
+# Create device delaying only write operation for 500ms and
+# splitting reads and writes to different devices $1 $2
+echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
+]]
diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
index f7c9262..19c4a6e 100644
--- a/Documentation/driver-model/platform.txt
+++ b/Documentation/driver-model/platform.txt
@@ -16,7 +16,7 @@
 into system-on-chip platforms.  What they usually have in common
 is direct addressing from a CPU bus.  Rarely, a platform_device will
 be connected through a segment of some other kind of bus; but its
-registers will still be directly addressible.
+registers will still be directly addressable.
 
 Platform devices are given a name, used in driver binding, and a
 list of resources such as addresses and IRQs.
@@ -125,7 +125,7 @@
       usually register later during booting, or by module loading.
 
     - Registering a driver using platform_driver_probe() works just like
-      using platform_driver_register(), except that the the driver won't
+      using platform_driver_register(), except that the driver won't
       be probed later if another device registers.  (Which is OK, since
       this interface is only for use with non-hotpluggable devices.)
 
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index 46b78b7..bf2a9cd 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -228,5 +228,5 @@
 
    Ulf Hermenau for helping me out with traditional chinese.
 
-   André Smoktun and Christian Frömmel for supporting me with
+   André Smoktun and Christian Frömmel for supporting me with
     hardware and listening to my problems very patiently.
diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt
index 4c33cce..4865add 100644
--- a/Documentation/dvb/contributors.txt
+++ b/Documentation/dvb/contributors.txt
@@ -66,7 +66,7 @@
 Andreas 'randy' Weinberger
   for the support of the Fujitsu-Siemens Activy budget DVB-S
 
-Kenneth Aafløy <ke-aa@frisurf.no>
+Kenneth Aafløy <ke-aa@frisurf.no>
   for adding support for Typhoon DVB-S budget card
 
 Ernst Peinlich <e.peinlich@inode.at>
diff --git a/Documentation/fb/arkfb.txt b/Documentation/fb/arkfb.txt
new file mode 100644
index 0000000..e8487a9
--- /dev/null
+++ b/Documentation/fb/arkfb.txt
@@ -0,0 +1,68 @@
+
+	arkfb - fbdev driver for ARK Logic chips
+	========================================
+
+
+Supported Hardware
+==================
+
+	ARK 2000PV chip
+	ICS 5342 ramdac
+
+	- only BIOS initialized VGA devices supported
+	- probably not working on big endian
+
+
+Supported Features
+==================
+
+	*  4 bpp pseudocolor modes (with 18bit palette, two variants)
+	*  8 bpp pseudocolor mode (with 18bit palette)
+	* 16 bpp truecolor modes (RGB 555 and RGB 565)
+	* 24 bpp truecolor mode (RGB 888)
+	* 32 bpp truecolor mode (RGB 888)
+	* text mode (activated by bpp = 0)
+	* doublescan mode variant (not available in text mode)
+	* panning in both directions
+	* suspend/resume support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (i got maximum about 70 MHz, it is dependent on specific
+hardware). This limitation is not enforced by driver. Text mode supports 8bit
+wide fonts only (hardware limitation) and 16bit tall fonts (driver
+limitation). Unfortunately character attributes (like color) in text mode are
+broken for unknown reason, so its usefulness is limited.
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+	* secondary (not initialized by BIOS) device support
+   	* big endian support
+	* DPMS support
+	* MMIO support
+	* interlaced mode variant
+	* support for fontwidths != 8 in 4 bpp modes
+	* support for fontheight != 16 in text mode
+	* hardware cursor
+	* vsync synchronization
+	* feature connector support
+	* acceleration support (8514-like 2D)
+
+
+Known bugs
+==========
+
+	* character attributes (and cursor) in text mode are broken
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/fb/aty128fb.txt b/Documentation/fb/aty128fb.txt
index 069262f..b605204 100644
--- a/Documentation/fb/aty128fb.txt
+++ b/Documentation/fb/aty128fb.txt
@@ -54,8 +54,8 @@
 
 noaccel  - do not use acceleration engine. It is default.
 accel    - use acceleration engine. Not finished.
-vmode:x  - chooses PowerMacintosh video mode <x>. Depreciated.
-cmode:x  - chooses PowerMacintosh colour mode <x>. Depreciated.
+vmode:x  - chooses PowerMacintosh video mode <x>. Deprecated.
+cmode:x  - chooses PowerMacintosh colour mode <x>. Deprecated.
 <XxX@X>  - selects startup videomode. See modedb.txt for detailed
 	   explanation. Default is 640x480x8bpp.
 
diff --git a/Documentation/fb/framebuffer.txt b/Documentation/fb/framebuffer.txt
index 610e780..b3e3a03 100644
--- a/Documentation/fb/framebuffer.txt
+++ b/Documentation/fb/framebuffer.txt
@@ -215,11 +215,11 @@
 vsync length.
 
   +----------+---------------------------------------------+----------+-------+
-  |          |                ^                            |          |       |
+  |          |                ↑                            |          |       |
   |          |                |upper_margin                |          |       |
-  |          |                ¥                            |          |       |
+  |          |                ↓                            |          |       |
   +----------###############################################----------+-------+
-  |          #                ^                            #          |       |
+  |          #                ↑                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
@@ -238,15 +238,15 @@
   |          #                |                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
-  |          #                ¥                            #          |       |
+  |          #                ↓                            #          |       |
   +----------###############################################----------+-------+
-  |          |                ^                            |          |       |
+  |          |                ↑                            |          |       |
   |          |                |lower_margin                |          |       |
-  |          |                ¥                            |          |       |
+  |          |                ↓                            |          |       |
   +----------+---------------------------------------------+----------+-------+
-  |          |                ^                            |          |       |
+  |          |                ↑                            |          |       |
   |          |                |vsync_len                   |          |       |
-  |          |                ¥                            |          |       |
+  |          |                ↓                            |          |       |
   +----------+---------------------------------------------+----------+-------+
 
 The frame buffer device expects all horizontal timings in number of dotclocks
diff --git a/Documentation/fb/imacfb.txt b/Documentation/fb/imacfb.txt
index 7590285..316ec9b 100644
--- a/Documentation/fb/imacfb.txt
+++ b/Documentation/fb/imacfb.txt
@@ -17,7 +17,7 @@
 ==============
 
 Imacfb does not have any kind of autodetection of your machine.
-You have to add the fillowing kernel parameters in your elilo.conf:
+You have to add the following kernel parameters in your elilo.conf:
 	Macbook :
 		video=imacfb:macbook
 	MacMini :
diff --git a/Documentation/fb/sstfb.txt b/Documentation/fb/sstfb.txt
index df27f5b..550ca77 100644
--- a/Documentation/fb/sstfb.txt
+++ b/Documentation/fb/sstfb.txt
@@ -2,9 +2,9 @@
 Introduction
 
 	  This is a frame buffer device driver for 3dfx' Voodoo Graphics 
-	(aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based 
+	(aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based 
 	video boards. It's highly experimental code, but is guaranteed to work
-	on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
+	on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
 	and with me "between chair and keyboard". Some people tested other
 	combinations and it seems that it works.
 	  The main page is located at <http://sstfb.sourceforge.net>, and if
diff --git a/Documentation/fb/vt8623fb.txt b/Documentation/fb/vt8623fb.txt
new file mode 100644
index 0000000..f654576
--- /dev/null
+++ b/Documentation/fb/vt8623fb.txt
@@ -0,0 +1,64 @@
+
+	vt8623fb - fbdev driver for graphics core in VIA VT8623 chipset
+	===============================================================
+
+
+Supported Hardware
+==================
+
+	VIA VT8623 [CLE266] chipset and	its graphics core
+		(known as CastleRock or Unichrome)
+
+I tested vt8623fb on VIA EPIA ML-6000
+
+
+Supported Features
+==================
+
+	*  4 bpp pseudocolor modes (with 18bit palette, two variants)
+	*  8 bpp pseudocolor mode (with 18bit palette)
+	* 16 bpp truecolor mode (RGB 565)
+	* 32 bpp truecolor mode (RGB 888)
+	* text mode (activated by bpp = 0)
+	* doublescan mode variant (not available in text mode)
+	* panning in both directions
+	* suspend/resume support
+	* DPMS support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (maximum about 100 MHz). This limitation is not enforced by
+driver. Text mode supports 8bit wide fonts only (hardware limitation) and
+16bit tall fonts (driver limitation).
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+	* secondary (not initialized by BIOS) device support
+	* MMIO support
+	* interlaced mode variant
+	* support for fontwidths != 8 in 4 bpp modes
+	* support for fontheight != 16 in text mode
+	* hardware cursor
+	* video overlay support
+	* vsync synchronization
+	* acceleration support (8514-like 2D, busmaster transfers)
+
+
+Known bugs
+==========
+
+	* cursor disable in text mode doesn't work
+
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 2291ff6..676b798 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -59,6 +59,15 @@
 
 ---------------------------
 
+What:	old NCR53C9x driver
+When:	October 2007
+Why:	Replaced by the much better esp_scsi driver.  Actual low-level
+	driver can ported over almost trivially.
+Who:	David Miller <davem@davemloft.net>
+	Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
 What:	Video4Linux API 1 ioctls and video_decoder.h from Video devices.
 When:	December 2006
 Why:	V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 59c1415..d866551 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -54,7 +54,7 @@
 
 locking rules:
 	all may block, none have BKL
-		i_sem(inode)
+		i_mutex(inode)
 lookup:		yes
 create:		yes
 link:		yes (both)
@@ -74,7 +74,7 @@
 getxattr:	no
 listxattr:	no
 removexattr:	yes
-	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on
+	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
 	cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
 	->truncate() is never called directly - it's a callback, not a
@@ -461,7 +461,7 @@
 ->read on directories probably must go away - we should just enforce -EISDIR
 in sys_read() and friends.
 
-->fsync() has i_sem on inode.
+->fsync() has i_mutex on inode.
 
 --------------------------- dquot_operations -------------------------------
 prototypes:
diff --git a/Documentation/filesystems/hpfs.txt b/Documentation/filesystems/hpfs.txt
index 38aba03..fa45c3b 100644
--- a/Documentation/filesystems/hpfs.txt
+++ b/Documentation/filesystems/hpfs.txt
@@ -290,7 +290,7 @@
 2.07 More fixes for Warp Server. Now it really works
 2.08 Creating new files is not so slow on large disks
      An attempt to sync deleted file does not generate filesystem error
-2.09 Fixed error on extremly fragmented files
+2.09 Fixed error on extremely fragmented files
 
 
  vim: set textwidth=80:
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 8177906..8ee10ec 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -349,7 +349,7 @@
 Note the "Should sync?" parameter "nosync" means that the two mirrors are
 already in sync which will be the case on a clean shutdown of Windows.  If the
 mirrors are not clean, you can specify the "sync" option instead of "nosync"
-and the Device-Mapper driver will then copy the entirey of the "Source Device"
+and the Device-Mapper driver will then copy the entirety of the "Source Device"
 to the "Target Device" or if you specified multipled target devices to all of
 them.
 
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 4f3e84c..8756a07 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -229,7 +229,7 @@
  mounts      Mounted filesystems                               
  net         Networking info (see text)                        
  partitions  Table of partitions known to the system           
- pci	     Depreciated info of PCI bus (new way -> /proc/bus/pci/, 
+ pci	     Deprecated info of PCI bus (new way -> /proc/bus/pci/,
              decoupled by lspci					(2.4)
  rtc         Real time clock                                   
  scsi        SCSI info (see text)                              
diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt
index 7fbb6ff..18d23f9 100644
--- a/Documentation/filesystems/relay.txt
+++ b/Documentation/filesystems/relay.txt
@@ -351,7 +351,7 @@
 the callback returns 0 to indicate that the buffer switch should not
 occur yet, i.e. until the consumer has had a chance to read the
 current set of ready sub-buffers.  For the relay_buf_full() function
-to make sense, the consumer is reponsible for notifying the relay
+to make sense, the consumer is responsible for notifying the relay
 interface when sub-buffers have been consumed via
 relay_subbufs_consumed().  Any subsequent attempts to write into the
 buffer will again invoke the subbuf_start() callback with the same
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
index 6c0cef1..3cc4010 100644
--- a/Documentation/filesystems/xip.txt
+++ b/Documentation/filesystems/xip.txt
@@ -19,7 +19,7 @@
 directly from/to the memory backed storage device. For file mappings, the
 storage device itself is mapped directly into userspace.
 
-This implementation was initialy written for shared memory segments between
+This implementation was initially written for shared memory segments between
 different virtual machines on s390 hardware to allow multiple machines to
 share the same binaries and libraries.
 
diff --git a/Documentation/fujitsu/frv/gdbstub.txt b/Documentation/fujitsu/frv/gdbstub.txt
index 9304fb3..b92bfd9 100644
--- a/Documentation/fujitsu/frv/gdbstub.txt
+++ b/Documentation/fujitsu/frv/gdbstub.txt
@@ -126,5 +126,5 @@
 
 Furthermore, the GDB stub will intercept a number of exceptions automatically
 if they are caused by kernel execution. It will also intercept BUG() macro
-invokation.
+invocation.
 
diff --git a/Documentation/hwmon/adm1026 b/Documentation/hwmon/adm1026
index 473c689..f4327db 100644
--- a/Documentation/hwmon/adm1026
+++ b/Documentation/hwmon/adm1026
@@ -80,7 +80,7 @@
 used to control fan speed. Usually only one of these two outputs will be
 used. Write the minimum PWM or DAC value to the appropriate control
 register. Then set the low temperature limit in the tmin values for each
-temperature sensor. The range of control is fixed at 20 °C, and the
+temperature sensor. The range of control is fixed at 20 °C, and the
 largest difference between current and tmin of the temperature sensors sets
 the control output. See the datasheet for several example circuits for
 controlling fan speed with the PWM and DAC outputs. The fan speed sensors
diff --git a/Documentation/hwmon/gl518sm b/Documentation/hwmon/gl518sm
index ce08818..229f8b7 100644
--- a/Documentation/hwmon/gl518sm
+++ b/Documentation/hwmon/gl518sm
@@ -13,7 +13,7 @@
 
 Authors:
         Frodo Looijaard <frodol@dds.nl>,
-        Kyösti Mälkki <kmalkki@cc.hut.fi>
+        Kyösti Mälkki <kmalkki@cc.hut.fi>
         Hong-Gunn Chew <hglinux@gunnet.org>
         Jean Delvare <khali@linux-fr.org>
 
diff --git a/Documentation/hwmon/lm83 b/Documentation/hwmon/lm83
index f7aad14..a04d1fe 100644
--- a/Documentation/hwmon/lm83
+++ b/Documentation/hwmon/lm83
@@ -45,7 +45,7 @@
 The LM82 is confirmed to have been found on most AMD Geode reference
 designs and test platforms.
 
-The driver has been successfully tested by Magnus Forsström, who I'd
+The driver has been successfully tested by Magnus Forsström, who I'd
 like to thank here. More testers will be of course welcome.
 
 The fact that the LM83 is only scarcely used can be easily explained.
diff --git a/Documentation/hwmon/sis5595 b/Documentation/hwmon/sis5595
index b7ae36b..4f8877a 100644
--- a/Documentation/hwmon/sis5595
+++ b/Documentation/hwmon/sis5595
@@ -8,7 +8,7 @@
     Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
 
 Authors:
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
         Mark D. Studebaker <mdsxyz123@yahoo.com>,
         Aurelien Jarno <aurelien@aurel32.net> 2.6 port
 
diff --git a/Documentation/hwmon/via686a b/Documentation/hwmon/via686a
index a936fb3..d651b25 100644
--- a/Documentation/hwmon/via686a
+++ b/Documentation/hwmon/via686a
@@ -8,7 +8,7 @@
     Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
 
 Authors:
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
         Mark D. Studebaker <mdsxyz123@yahoo.com>
         Bob Dougherty <bobd@stanford.edu>
         (Some conversion-factor data were contributed by
diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d
index 8171c28..14a668e 100644
--- a/Documentation/hwmon/w83792d
+++ b/Documentation/hwmon/w83792d
@@ -107,7 +107,7 @@
 	  by CR[0x49h].
 	- The function of vid and vrm has not been finished, because I'm NOT
 	  very familiar with them. Adding support is welcome.
- 	- The function of chassis open detection needs more tests.
+ 	- The function of chassis open detection needs more tests.
 	- If you have ASUS server board and chip was not found: Then you will
 	  need to upgrade to latest (or beta) BIOS. If it does not help please
 	  contact us.
diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810
index 83c3b97..778210e 100644
--- a/Documentation/i2c/busses/i2c-i810
+++ b/Documentation/i2c/busses/i2c-i810
@@ -7,7 +7,7 @@
 Authors: 
 	Frodo Looijaard <frodol@dds.nl>, 
 	Philip Edelbrock <phil@netroedge.com>,
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
 	Ralph Metzler <rjkm@thp.uni-koeln.de>,
 	Mark D. Studebaker <mdsxyz123@yahoo.com>
 
diff --git a/Documentation/i2c/busses/i2c-sis96x b/Documentation/i2c/busses/i2c-sis96x
index 08d7b2d..266481f 100644
--- a/Documentation/i2c/busses/i2c-sis96x
+++ b/Documentation/i2c/busses/i2c-sis96x
@@ -60,7 +60,7 @@
  - design hints and bug fixes
 Alexander Maylsh <amalysh@web.de>
  - ditto, plus an important datasheet... almost the one I really wanted
-Hans-Günter Lütke Uphues <hg_lu@t-online.de>
+Hans-Günter Lütke Uphues <hg_lu@t-online.de>
  - patch for SiS735
 Robert Zwerus <arzie@dds.nl>
  - testing for SiS645DX
diff --git a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via
index 55edfe1..3438706 100644
--- a/Documentation/i2c/busses/i2c-via
+++ b/Documentation/i2c/busses/i2c-via
@@ -4,7 +4,7 @@
   * VIA Technologies, InC. VT82C586B
     Datasheet: Publicly available at the VIA website
 
-Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
 
 Description
 -----------
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 775f489..06b4be3 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -17,7 +17,7 @@
     Datasheet: available on request and under NDA from VIA
 
 Authors:
-	Kyösti Mälkki <kmalkki@cc.hut.fi>,
+	Kyösti Mälkki <kmalkki@cc.hut.fi>,
 	Mark D. Studebaker <mdsxyz123@yahoo.com>,
 	Jean Delvare <khali@linux-fr.org>
 
diff --git a/Documentation/i2c/i2c-protocol b/Documentation/i2c/i2c-protocol
index b4022c9..579b92d 100644
--- a/Documentation/i2c/i2c-protocol
+++ b/Documentation/i2c/i2c-protocol
@@ -68,7 +68,7 @@
 
   Flags I2C_M_IGNORE_NAK
     Normally message is interrupted immediately if there is [NA] from the
-    client. Setting this flag treats any [NA] as [A], and all of
+    client. Setting this flag treats any [NA] as [A], and all of
     message is sent.
     These messages may still fail to SCL lo->hi timeout.
 
diff --git a/Documentation/i2o/README b/Documentation/i2o/README
index 9aa6ddb..0ebf58c 100644
--- a/Documentation/i2o/README
+++ b/Documentation/i2o/README
@@ -30,13 +30,13 @@
 	Bug fixes
 	Core code extensions
 
-Auvo Häkkinen, University of Helsinki Finland
+Auvo Häkkinen, University of Helsinki Finland
 	LAN OSM code
 	/Proc interface to LAN class
 	Bug fixes
 	Core code extensions
 
-Taneli Vähäkangas, University of Helsinki Finland
+Taneli Vähäkangas, University of Helsinki Finland
 	Fixes to i2o_config
 
 CREDITS
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 6498666..d01b7a2 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -2,7 +2,7 @@
 		     ----------------------------
 
 		    H. Peter Anvin <hpa@zytor.com>
-			Last update 2007-03-06
+			Last update 2007-05-07
 
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
@@ -11,7 +11,7 @@
 expectations in the PC industry caused by the effective demise of
 real-mode DOS as a mainstream operating system.
 
-Currently, four versions of the Linux/i386 boot protocol exist.
+Currently, the following versions of the Linux/i386 boot protocol exist.
 
 Old kernels:	zImage/Image support only.  Some very early kernels
 		may not even support a command line.
@@ -183,9 +183,9 @@
 	a version number.  Otherwise, enter 0xFF here.
 
 	Assigned boot loader ids:
-	0  LILO
+	0  LILO			(0x00 reserved for pre-2.00 bootloader)
 	1  Loadlin
-	2  bootsect-loader
+	2  bootsect-loader	(0x20, all other values reserved)
 	3  SYSLINUX
 	4  EtherBoot
 	5  ELILO
@@ -210,6 +210,9 @@
 	additional data (such as the kernel command line) moved in
 	addition to the real-mode kernel itself.
 
+	The unit is bytes starting with the beginning of the boot
+	sector.
+
   ramdisk_image, ramdisk_size:
 	If your boot loader has loaded an initial ramdisk (initrd),
 	set ramdisk_image to the 32-bit pointer to the ramdisk data
@@ -278,14 +281,54 @@
 	field.
 
 
+**** MEMORY LAYOUT OF THE REAL-MODE CODE
+
+The real-mode code requires a stack/heap to be set up, as well as
+memory allocated for the kernel command line.  This needs to be done
+in the real-mode accessible memory in bottom megabyte.
+
+It should be noted that modern machines often have a sizable Extended
+BIOS Data Area (EBDA).  As a result, it is advisable to use as little
+of the low megabyte as possible.
+
+Unfortunately, under the following circumstances the 0x90000 memory
+segment has to be used:
+
+	- When loading a zImage kernel ((loadflags & 0x01) == 0).
+	- When loading a 2.01 or earlier boot protocol kernel.
+
+	  -> For the 2.00 and 2.01 boot protocols, the real-mode code
+	     can be loaded at another address, but it is internally
+	     relocated to 0x90000.  For the "old" protocol, the
+	     real-mode code must be loaded at 0x90000.
+
+When loading at 0x90000, avoid using memory above 0x9a000.
+
+For boot protocol 2.02 or higher, the command line does not have to be
+located in the same 64K segment as the real-mode setup code; it is
+thus permitted to give the stack/heap the full 64K segment and locate
+the command line above it.
+
+The kernel command line should not be located below the real-mode
+code, nor should it be located in high memory.
+
+
 **** SAMPLE BOOT CONFIGURATION
 
 As a sample configuration, assume the following layout of the real
-mode segment (this is a typical, and recommended layout):
+mode segment:
 
-	0x0000-0x7FFF	Real mode kernel
-	0x8000-0x8FFF	Stack and heap
-	0x9000-0x90FF	Kernel command line
+    When loading below 0x90000, use the entire segment:
+
+	0x0000-0x7fff	Real mode kernel
+	0x8000-0xdfff	Stack and heap
+	0xe000-0xffff	Kernel command line
+
+    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+	0x0000-0x7fff	Real mode kernel
+	0x8000-0x97ff	Stack and heap
+	0x9800-0x9fff	Kernel command line
 
 Such a boot loader should enter the following fields in the header:
 
@@ -301,22 +344,33 @@
 			ramdisk_image = <initrd_address>;
 			ramdisk_size = <initrd_size>;
 		}
+
+		if ( protocol >= 0x0202 && loadflags & 0x01 )
+			heap_end = 0xe000;
+		else
+			heap_end = 0x9800;
+
 		if ( protocol >= 0x0201 ) {
-			heap_end_ptr = 0x9000 - 0x200;
+			heap_end_ptr = heap_end - 0x200;
 			loadflags |= 0x80; /* CAN_USE_HEAP */
 		}
+
 		if ( protocol >= 0x0202 ) {
-			cmd_line_ptr = base_ptr + 0x9000;
+			cmd_line_ptr = base_ptr + heap_end;
+			strcpy(cmd_line_ptr, cmdline);
 		} else {
 			cmd_line_magic	= 0xA33F;
-			cmd_line_offset = 0x9000;
-			setup_move_size = 0x9100;
+			cmd_line_offset = heap_end;
+			setup_move_size = heap_end + strlen(cmdline)+1;
+			strcpy(base_ptr+cmd_line_offset, cmdline);
 		}
 	} else {
 		/* Very old kernel */
 
+		heap_end = 0x9800;
+
 		cmd_line_magic	= 0xA33F;
-		cmd_line_offset = 0x9000;
+		cmd_line_offset = heap_end;
 
 		/* A very old kernel MUST have its real-mode code
 		   loaded at 0x90000 */
@@ -324,12 +378,11 @@
 		if ( base_ptr != 0x90000 ) {
 			/* Copy the real-mode kernel */
 			memcpy(0x90000, base_ptr, (setup_sects+1)*512);
-			/* Copy the command line */
-			memcpy(0x99000, base_ptr+0x9000, 256);
-
 			base_ptr = 0x90000;		 /* Relocated */
 		}
 
+		strcpy(0x90000+cmd_line_offset, cmdline);
+
 		/* It is recommended to clear memory up to the 32K mark */
 		memset(0x90000 + (setup_sects+1)*512, 0,
 		       (64-(setup_sects+1))*512);
@@ -375,10 +428,11 @@
 	line is parsed.
 
   mem=<size>
-	<size> is an integer in C notation optionally followed by K, M
-	or G (meaning << 10, << 20 or << 30).  This specifies the end
-	of memory to the kernel. This affects the possible placement
-	of an initrd, since an initrd should be placed near end of
+	<size> is an integer in C notation optionally followed by
+	(case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
+	<< 30, << 40, << 50 or << 60).  This specifies the end of
+	memory to the kernel. This affects the possible placement of
+	an initrd, since an initrd should be placed near end of
 	memory.  Note that this is an option to *both* the kernel and
 	the bootloader!
 
@@ -428,7 +482,7 @@
 
 	/* Set up the real-mode kernel stack */
 	_SS = seg;
-	_SP = 0x9000;	/* Load SP immediately after loading SS! */
+	_SP = heap_end;
 
 	_DS = _ES = _FS = _GS = seg;
 	jmp_far(seg+0x20, 0);	/* Run the kernel */
@@ -460,8 +514,9 @@
   code32_start:
 	A 32-bit flat-mode routine *jumped* to immediately after the
 	transition to protected mode, but before the kernel is
-	uncompressed.  No segments, except CS, are set up; you should
-	set them up to KERNEL_DS (0x18) yourself.
+	uncompressed.  No segments, except CS, are guaranteed to be
+	set up (current kernels do, but older ones do not); you should
+	set them up to BOOT_DS (0x18) yourself.
 
 	After completing your hook, you should jump to the address
 	that was in this field before your boot loader overwrote it.
diff --git a/Documentation/input/atarikbd.txt b/Documentation/input/atarikbd.txt
index 668f4d0..ab05062 100644
--- a/Documentation/input/atarikbd.txt
+++ b/Documentation/input/atarikbd.txt
@@ -179,9 +179,9 @@
 the mouse. After any joystick command, the ikbd assumes that joysticks are
 connected to both Joystick0 and Joystick1. Any mouse command (except MOUSE
 DISABLE) then causes port 0 to again be scanned as if it were a mouse, and
-both buttons are logically connected to it. If a mouse diable command is
+both buttons are logically connected to it. If a mouse disable command is
 received while port 0 is presumed to be a mouse, the button is logically
-assigned to Joystick1 ( until the mouse is reenabled by another mouse command).
+assigned to Joystick1 (until the mouse is reenabled by another mouse command).
 
 9. ikbd Command Set
 
diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
index 5427bdf..aae0d40 100644
--- a/Documentation/input/xpad.txt
+++ b/Documentation/input/xpad.txt
@@ -65,15 +65,15 @@
 I've tested this with Stepmania, and it works quite well.
 
 
-0.3 Unkown Controllers
+0.3 Unknown Controllers
 ----------------------
-If you have an unkown xbox controller, it should work just fine with
+If you have an unknown xbox controller, it should work just fine with
 the default settings.
 
 HOWEVER if you have an unknown dance pad not listed below, it will not
 work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
 
-PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with
+PLEASE, if you have an unknown controller, email Dom <binary1230@yahoo.com> with
 a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
 whether it is a dance pad or normal controller) so that we can add your pad
 to the list of supported devices, ensuring that it will work out of the
diff --git a/Documentation/isdn/CREDITS b/Documentation/isdn/CREDITS
index e1b3023..7c17c83 100644
--- a/Documentation/isdn/CREDITS
+++ b/Documentation/isdn/CREDITS
@@ -2,7 +2,7 @@
 I want to thank all who contributed to this project and especially to:
 (in alphabetical order)
 
-Thomas Bogendörfer (tsbogend@bigbug.franken.de)
+Thomas Bogendörfer (tsbogend@bigbug.franken.de)
   Tester, lots of bugfixes and hints.
 
 Alan Cox (alan@redhat.com)
@@ -11,7 +11,7 @@
 Henner Eisen (eis@baty.hanse.de)
   For X.25 implementation.
 
-Volker Götz (volker@oops.franken.de)
+Volker Götz (volker@oops.franken.de)
   For contribution of man-pages, the imontty-tool and a perfect
   maintaining of the mailing-list at hub-wue.
 
diff --git a/Documentation/isdn/README b/Documentation/isdn/README
index 7615952..6783437 100644
--- a/Documentation/isdn/README
+++ b/Documentation/isdn/README
@@ -402,7 +402,7 @@
      the script tools/tcltk/isdnmon. You can add actions for line-status
      changes. See the comments at the beginning of the script for how to
      do that. There are other tty-based tools in the tools-subdirectory
-     contributed by Michael Knigge (imon), Volker Götz (imontty) and
+     contributed by Michael Knigge (imon), Volker Götz (imontty) and
      Andreas Kool (isdnmon).
 
    l) For initial testing, you can set the verbose-level to 2 (default: 0).
diff --git a/Documentation/isdn/README.icn b/Documentation/isdn/README.icn
index a5f55ea..13f833d 100644
--- a/Documentation/isdn/README.icn
+++ b/Documentation/isdn/README.icn
@@ -3,8 +3,8 @@
 You can get the ICN-ISDN-card from:
 
 Thinking Objects Software GmbH
-Versbacher Röthe 159
-97078 Würzburg
+Versbacher Röthe 159
+97078 Würzburg
 Tel: +49 931 2877950
 Fax: +49 931 2877951
 
diff --git a/Documentation/java.txt b/Documentation/java.txt
index c768dc6..3cce3fb 100644
--- a/Documentation/java.txt
+++ b/Documentation/java.txt
@@ -390,7 +390,7 @@
 
 
 originally by Brian A. Lantz, brian@lantz.com
-heavily edited for binfmt_misc by Richard Günther
+heavily edited for binfmt_misc by Richard Günther
 new scripts by Colin J. Watson <cjw44@cam.ac.uk>
 added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
 
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index c68dafe..d9e3b19 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -236,7 +236,7 @@
 
      * Title: "Design and Implementation of the Second Extended
        Filesystem"
-       Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
+       Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
        URL: http://web.mit.edu/tytso/www/linux/ext2intro.html
        Keywords: ext2, linux fs history, inode, directory, link, devices,
        VFS, physical structure, performance, benchmarks, ext2fs library,
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6b8ad06..09220a1 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -754,14 +754,6 @@
 	inport.irq=	[HW] Inport (ATI XL and Microsoft) busmouse driver
 			Format: <irq>
 
-	combined_mode=	[HW] control which driver uses IDE ports in combined
-			mode: legacy IDE driver, libata, or both
-			(in the libata case, libata.atapi_enabled=1 may be
-			useful as well).  Note that using the ide or libata
-			options may affect your device naming (e.g. by
-			changing hdc to sdb).
-			Format: combined (default), ide, or libata
-
 	inttest=	[IA64]
 
 	io7=		[HW] IO7 for Marvel based alpha systems
diff --git a/Documentation/m68k/README.buddha b/Documentation/m68k/README.buddha
index ef484a7..3ea9827 100644
--- a/Documentation/m68k/README.buddha
+++ b/Documentation/m68k/README.buddha
@@ -204,7 +204,7 @@
 the  third  IDE  port  are  going into data's Nirwana on the
 Buddha.
 
-			    Jens Schönfeld february 19th, 1997
+			    Jens Schönfeld february 19th, 1997
 					updated may 27th, 1997
 			     eMail: sysop@nostlgic.tng.oche.de
 
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index 0e740c8..bd450e7 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -129,7 +129,7 @@
 GDA_MAGIC             0x58464552  gda               include/asm-mips64/sn/gda.h
 RED_MAGIC1            0x5a2cf071  (any)             mm/slab.c
 STL_PORTMAGIC         0x5a7182c9  stlport           include/linux/stallion.h
-EEPROM_MAGIC_VALUE    0X5ab478d2  lanai_dev         drivers/atm/lanai.c
+EEPROM_MAGIC_VALUE    0x5ab478d2  lanai_dev         drivers/atm/lanai.c
 HDLCDRV_MAGIC         0x5ac6e778  hdlcdrv_state     include/linux/hdlcdrv.h
 EPCA_MAGIC            0x5c6df104  channel           include/linux/epca.h
 PCXX_MAGIC            0x5c6df104  channel           drivers/char/pcxx.h
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 2202f5d..5818628 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -178,6 +178,21 @@
      The size should be at least PAGE_SIZE (4k) and should be a power
      of 2.  This can only be set while assembling an array
 
+  layout
+     The "layout" for the array for the particular level.  This is
+     simply a number that is interpretted differently by different
+     levels.  It can be written while assembling an array.
+
+  reshape_position
+     This is either "none" or a sector number within the devices of
+     the array where "reshape" is up to.  If this is set, the three
+     attributes mentioned above (raid_disks, chunk_size, layout) can
+     potentially have 2 values, an old and a new value.  If these
+     values differ, reading the attribute returns
+        new (old)
+     and writing will effect the 'new' value, leaving the 'old'
+     unchanged.
+
   component_size
      For arrays with data redundancy (i.e. not raid0, linear, faulty,
      multipath), all components must be the same size - or at least
@@ -193,11 +208,6 @@
      1.2 (newer format in varying locations) or "none" indicating that
      the kernel isn't managing metadata at all.
 
-  layout
-     The "layout" for the array for the particular level.  This is
-     simply a number that is interpretted differently by different
-     levels.  It can be written while assembling an array.
-
   resync_start
      The point at which resync should start.  If no resync is needed,
      this will be a very large number.  At array creation it will
@@ -259,29 +269,6 @@
          like active, but no writes have been seen for a while (safe_mode_delay).
 
 
-   sync_speed_min
-   sync_speed_max
-     This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
-     however they only apply to the particular array.
-     If no value has been written to these, of if the word 'system'
-     is written, then the system-wide value is used.  If a value,
-     in kibibytes-per-second is written, then it is used.
-     When the files are read, they show the currently active value
-     followed by "(local)" or "(system)" depending on whether it is
-     a locally set or system-wide value.
-
-   sync_completed
-     This shows the number of sectors that have been completed of
-     whatever the current sync_action is, followed by the number of
-     sectors in total that could need to be processed.  The two
-     numbers are separated by a '/'  thus effectively showing one
-     value, a fraction of the process that is complete.
-
-   sync_speed
-     This shows the current actual speed, in K/sec, of the current
-     sync_action.  It is averaged over the last 30 seconds.
-
-
 As component devices are added to an md array, they appear in the 'md'
 directory as new directories named
       dev-XXX
@@ -412,6 +399,35 @@
       Note that the numbers are 'bit' numbers, not 'block' numbers.
       They should be scaled by the bitmap_chunksize.
 
+   sync_speed_min
+   sync_speed_max
+     This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
+     however they only apply to the particular array.
+     If no value has been written to these, of if the word 'system'
+     is written, then the system-wide value is used.  If a value,
+     in kibibytes-per-second is written, then it is used.
+     When the files are read, they show the currently active value
+     followed by "(local)" or "(system)" depending on whether it is
+     a locally set or system-wide value.
+
+   sync_completed
+     This shows the number of sectors that have been completed of
+     whatever the current sync_action is, followed by the number of
+     sectors in total that could need to be processed.  The two
+     numbers are separated by a '/'  thus effectively showing one
+     value, a fraction of the process that is complete.
+
+   sync_speed
+     This shows the current actual speed, in K/sec, of the current
+     sync_action.  It is averaged over the last 30 seconds.
+
+   suspend_lo
+   suspend_hi
+     The two values, given as numbers of sectors, indicate a range
+     within the array where IO will be blocked.  This is currently
+     only supported for raid4/5/6.
+
+
 Each active md device may also have attributes specific to the
 personality module that manages it.
 These are specific to the implementation of the module and could
diff --git a/Documentation/netlabel/introduction.txt b/Documentation/netlabel/introduction.txt
index a4ffba1..5ecd8d1 100644
--- a/Documentation/netlabel/introduction.txt
+++ b/Documentation/netlabel/introduction.txt
@@ -30,7 +30,7 @@
 from user space.  The NetLabel communication layer uses a message based
 protocol built on top of the Generic NETLINK transport mechanism.  The exact
 formatting of these NetLabel messages as well as the Generic NETLINK family
-names can be found in the the 'net/netlabel/' directory as comments in the
+names can be found in the 'net/netlabel/' directory as comments in the
 header files as well as in 'include/net/netlabel.h'.
 
  * Security Module API
diff --git a/Documentation/networking/6pack.txt b/Documentation/networking/6pack.txt
index 48ed2b7..d0777a1 100644
--- a/Documentation/networking/6pack.txt
+++ b/Documentation/networking/6pack.txt
@@ -1,6 +1,6 @@
 This is the 6pack-mini-HOWTO, written by
 
-Andreas Könsgen DG3KQ
+Andreas Könsgen DG3KQ
 Internet: ajk@iehk.rwth-aachen.de
 AMPR-net: dg3kq@db0pra.ampr.org
 AX.25:    dg3kq@db0ach.#nrw.deu.eu
diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt
index fb8dc64..7907435 100644
--- a/Documentation/networking/NAPI_HOWTO.txt
+++ b/Documentation/networking/NAPI_HOWTO.txt
@@ -160,7 +160,7 @@
 it completes its work. The device cannot be out of poll list at this
 call, if it is then clearly it is a BUG(). You'll know ;->
 
-All these above nethods are used below. So keep reading for clarity.
+All of the above methods are used below, so keep reading for clarity.
 
 Device driver changes to be made when porting NAPI
 ==================================================
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 5a232d9..db0cd51 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -13,7 +13,7 @@
 
 Please send me your comments to
 
-    Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
+    Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
 
 -------------------------------------------------------------------------------
 + Why use PACKET_MMAP
diff --git a/Documentation/networking/slicecom.hun b/Documentation/networking/slicecom.hun
index 5acf191..bed2f04 100644
--- a/Documentation/networking/slicecom.hun
+++ b/Documentation/networking/slicecom.hun
@@ -1,7 +1,7 @@
 
 SliceCOM adapter felhasznaloi dokumentacioja - 0.51 verziohoz
 
-Bartók István <bartoki@itc.hu>
+Bartók István <bartoki@itc.hu>
 Utolso modositas: Wed Aug 29 17:26:58 CEST 2001
 
 -----------------------------------------------------------------
diff --git a/Documentation/networking/slicecom.txt b/Documentation/networking/slicecom.txt
index 32d3b91..c82c0cf 100644
--- a/Documentation/networking/slicecom.txt
+++ b/Documentation/networking/slicecom.txt
@@ -1,9 +1,9 @@
 
 SliceCOM adapter user's documentation - for the 0.51 driver version
 
-Written by Bartók István <bartoki@itc.hu>
+Written by Bartók István <bartoki@itc.hu>
 
-English translation: Lakatos György <gyuri@itc.hu>
+English translation: Lakatos György <gyuri@itc.hu>
 Mon Dec 11 15:28:42 CET 2000
 
 Last modified: Wed Aug 29 17:25:37 CEST 2001
diff --git a/Documentation/networking/tms380tr.txt b/Documentation/networking/tms380tr.txt
index c169a57..1f73e13 100644
--- a/Documentation/networking/tms380tr.txt
+++ b/Documentation/networking/tms380tr.txt
@@ -71,24 +71,24 @@
   CHAPTER 1     LOCATION OF DIP-SWITCH
   ==============================================================
 
-UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-þUÄÄÄÄÄÄ¿                         UÄÄÄÄÄ¿            UÄÄÄ¿         þ
-þAÄÄÄÄÄÄU                      W1 AÄÄÄÄÄU     UÄÄÄÄ¿ þ   þ         þ
-þUÄÄÄÄÄÄ¿                                     þ    þ þ   þ      UÄÄÅ¿
-þAÄÄÄÄÄÄU              UÄÄÄÄÄÄÄÄÄÄÄ¿          AÄÄÄÄU þ   þ      þ  þþ
-þUÄÄÄÄÄÄ¿              þ           þ          UÄÄÄ¿  AÄÄÄU      AÄÄÅU
-þAÄÄÄÄÄÄU              þ TMS380C26 þ          þ   þ                þ
-þUÄÄÄÄÄÄ¿              þ           þ          AÄÄÄU                AÄ¿
-þAÄÄÄÄÄÄU              þ           þ                               þ þ
-þ                      AÄÄÄÄÄÄÄÄÄÄÄU                               þ þ
-þ                                                                  þ þ
-þ                                                                  AÄU
-þ                                                                  þ
-þ                                                                  þ
-þ                                                                  þ
-þ                                                                  þ
-AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
-             AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU  AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
+UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+þUÄÄÄÄÄÄ¿                         UÄÄÄÄÄ¿            UÄÄÄ¿         þ
+þAÄÄÄÄÄÄU                      W1 AÄÄÄÄÄU     UÄÄÄÄ¿ þ   þ         þ
+þUÄÄÄÄÄÄ¿                                     þ    þ þ   þ      UÄÄÅ¿
+þAÄÄÄÄÄÄU              UÄÄÄÄÄÄÄÄÄÄÄ¿          AÄÄÄÄU þ   þ      þ  þþ
+þUÄÄÄÄÄÄ¿              þ           þ          UÄÄÄ¿  AÄÄÄU      AÄÄÅU
+þAÄÄÄÄÄÄU              þ TMS380C26 þ          þ   þ                þ
+þUÄÄÄÄÄÄ¿              þ           þ          AÄÄÄU                AÄ¿
+þAÄÄÄÄÄÄU              þ           þ                               þ þ
+þ                      AÄÄÄÄÄÄÄÄÄÄÄU                               þ þ
+þ                                                                  þ þ
+þ                                                                  AÄU
+þ                                                                  þ
+þ                                                                  þ
+þ                                                                  þ
+þ                                                                  þ
+AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
+             AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU  AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
 
   ==============================================================
   CHAPTER 2     DEFAULT SETTINGS
@@ -108,9 +108,9 @@
   CHAPTER 3     DIP SWITCH W1 DESCRIPTION
   ==============================================================
 
-      UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿  ON
-      þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
-      AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU  OFF
+      UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿  ON
+      þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
+      AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU  OFF
       |AD | BootROM Addr. |  I/O      |
       +-+-+-------+-------+-----+-----+
         |         |             |
diff --git a/Documentation/networking/udplite.txt b/Documentation/networking/udplite.txt
index dd6f46b..6be09ba 100644
--- a/Documentation/networking/udplite.txt
+++ b/Documentation/networking/udplite.txt
@@ -139,7 +139,7 @@
   3) Disabling the Checksum Computation
 
   On both sender and receiver, checksumming will always be performed
-  and can not be disabled using SO_NO_CHECK. Thus
+  and cannot be disabled using SO_NO_CHECK. Thus
 
         setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK,  ... );
 
diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
index 07dd6d9..bc2ab41 100644
--- a/Documentation/networking/wan-router.txt
+++ b/Documentation/networking/wan-router.txt
@@ -335,7 +335,7 @@
 				creating applications using BiSync
    				streaming.        
 
-2.0.5   Aug 04, 1999 		CHDLC initializatin bug fix.
+2.0.5   Aug 04, 1999 		CHDLC initialization bug fix.
 				PPP interrupt driven driver: 
   				Fix to the PPP line hangup problem.
 				New PPP firmware
@@ -372,7 +372,7 @@
 				o cfgft1 GUI csu/dsu configurator
 				o wancfg GUI configuration file 
 				  configurator.
-				o Architectual directory changes.
+				o Architectural directory changes.
 
 beta-2.1.4 Jul 2000		o Dynamic interface configuration:
 					Network interfaces reflect the state
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index e2c9d0a..d38261b 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -373,7 +373,7 @@
 
 3.6 Register IRQ handler
 ~~~~~~~~~~~~~~~~~~~~~~~~
-While calling request_irq() is the the last step described here,
+While calling request_irq() is the last step described here,
 this is often just another intermediate step to initialize a device.
 This step can often be deferred until the device is opened for use.
 
diff --git a/Documentation/pcieaer-howto.txt b/Documentation/pcieaer-howto.txt
index 16c2512..d5da861 100644
--- a/Documentation/pcieaer-howto.txt
+++ b/Documentation/pcieaer-howto.txt
@@ -13,7 +13,7 @@
 well as how to enable the drivers of endpoint devices to conform with
 PCI Express AER driver.
 
-1.2 Copyright © Intel Corporation 2006.
+1.2 Copyright © Intel Corporation 2006.
 
 1.3 What is the PCI Express AER Driver?
 
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
index 28037aa..481faf5 100644
--- a/Documentation/pnp.txt
+++ b/Documentation/pnp.txt
@@ -140,7 +140,7 @@
 Requirements for a Linux PnP protocol:
 1.) the protocol must use EISA IDs
 2.) the protocol must inform the PnP Layer of a devices current configuration
-- the ability to set resources is optional but prefered.
+- the ability to set resources is optional but preferred.
 
 The following are PnP protocol related functions:
 
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index c55bd50..5b8d695 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -48,7 +48,7 @@
 
 Article about goals and implementation of Software Suspend for Linux
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Author: G‚ábor Kuti
+Author: G‚ábor Kuti
 Last revised: 2003-10-20 by Pavel Machek
 
 Idea and goals to achieve
diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 000556c..e00c6cf 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -93,21 +93,23 @@
 	to resume the system from RAM if there's enough battery power or restore
 	its state on the basis of the saved suspend image otherwise)
 
-SNAPSHOT_PMOPS - enable the usage of the pmops->prepare, pmops->enter and
-	pmops->finish methods (the in-kernel swsusp knows these as the "platform
-	method") which are needed on many machines to (among others) speed up
-	the resume by letting the BIOS skip some steps or to let the system
-	recognise the correct state of the hardware after the resume (in
-	particular on many machines this ensures that unplugged AC
-	adapters get correctly detected and that kacpid does not run wild after
-	the resume).  The last ioctl() argument can take one of the three
-	values, defined in kernel/power/power.h:
+SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
+	hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
+	swsusp knows these as the "platform method") which are needed on many
+	machines to (among others) speed up the resume by letting the BIOS skip
+	some steps or to let the system recognise the correct state of the
+	hardware after the resume (in particular on many machines this ensures
+	that unplugged AC adapters get correctly detected and that kacpid does
+	not run wild after the resume).  The last ioctl() argument can take one
+	of the three values, defined in kernel/power/power.h:
 	PMOPS_PREPARE - make the kernel carry out the
-		pm_ops->prepare(PM_SUSPEND_DISK) operation
+		hibernation_ops->prepare() operation
 	PMOPS_ENTER - make the kernel power off the system by calling
-		pm_ops->enter(PM_SUSPEND_DISK)
+		hibernation_ops->enter()
 	PMOPS_FINISH - make the kernel carry out the
-		pm_ops->finish(PM_SUSPEND_DISK) operation
+		hibernation_ops->finish() operation
+	Note that the actual constants are misnamed because they surface
+	internal kernel implementation details that have changed.
 
 The device's read() operation can be used to transfer the snapshot image from
 the kernel.  It has the following limitations:
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index d4bfae7..b49ce16 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1444,7 +1444,7 @@
    Basically, it is a bus of devices, that could act more or less
    as a complete entity (UCC, USB etc ). All of them should be siblings on
    the "root" qe node, using the common properties from there.
-   The description below applies to the the qe of MPC8360 and
+   The description below applies to the qe of MPC8360 and
    more nodes and properties would be extended in the future.
 
    i) Root QE device
@@ -1633,7 +1633,7 @@
      - assignment : function number of the pin according to the Pin Assignment
        tables in User Manual.  Each pin can have up to 4 possible functions in
        QE and two options for CPM.
-     - has_irq : indicates if the pin is used as source of exteral
+     - has_irq : indicates if the pin is used as source of external
        interrupts.
 
    Example:
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 09939696..d30a281 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -2209,7 +2209,7 @@
 #3  0x5167e6 in readline_internal_char () at readline.c:454
 #4  0x5168ee in readline_internal_charloop () at readline.c:507
 #5  0x51692c in readline_internal () at readline.c:521
-#6  0x5164fe in readline (prompt=0x7ffff810 "\177ÿøx\177ÿ÷Ø\177ÿøxÀ")
+#6  0x5164fe in readline (prompt=0x7ffff810 "\177ÿøx\177ÿ÷Ø\177ÿøxÀ")
     at readline.c:349
 #7  0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1,
     annotation_suffix=0x4d6b44 "prompt") at top.c:2091
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index 2368e7e..ce3cb42 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -98,8 +98,8 @@
 	9005:0285:9005:02b0		(Sunrise Lake ARK)
 	9005:0285:9005:02b1	Adaptec	(Voodoo 8 internal 8 external)
 	9005:0285:108e:7aac	SUN	STK RAID REM (Voodoo44 Coyote)
-	9005:0285:108e:0286	SUN	SG-XPCIESAS-R-IN (Cougar)
-	9005:0285:108e:0287	SUN	SG-XPCIESAS-R-EX (Prometheus)
+	9005:0285:108e:0286	SUN	STK RAID INT (Cougar)
+	9005:0285:108e:0287	SUN	STK RAID EXT (Prometheus)
 
 People
 -------------------------
diff --git a/Documentation/scsi/aha152x.txt b/Documentation/scsi/aha152x.txt
index 2ce022c..29ce6d8 100644
--- a/Documentation/scsi/aha152x.txt
+++ b/Documentation/scsi/aha152x.txt
@@ -1,7 +1,7 @@
 $Id: README.aha152x,v 1.2 1999/12/25 15:32:30 fischer Exp fischer $
 Adaptec AHA-1520/1522 SCSI driver for Linux (aha152x)
 
-Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
+Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
 TC1550 patches by Luuk van Dijk (ldz@xs4all.nl)
 
 
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index 9b894f1..5f34d2b 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -40,7 +40,7 @@
    2.   Multi-function Twin Channel Device - Two controllers on one chip.
    3.   Command Channel Secondary DMA Engine - Allows scatter gather list
         and SCB prefetch.
-   4.   64 Byte SCB Support - Allows disconnected, unttagged request table
+   4.   64 Byte SCB Support - Allows disconnected, untagged request table
         for all possible target/lun combinations.
    5.   Block Move Instruction Support - Doubles the speed of certain
         sequencer operations.
diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt
index 05667e7..7bd210a 100644
--- a/Documentation/scsi/aic7xxx_old.txt
+++ b/Documentation/scsi/aic7xxx_old.txt
@@ -356,7 +356,7 @@
         or enable Tagged Command Queueing (TCQ) on specific devices.  As of
 	driver version 5.1.11, TCQ is now either on or off by default
 	according to the setting you choose during the make config process.
-	In order to en/disable TCQ for certian devices at boot time, a user
+	In order to en/disable TCQ for certain devices at boot time, a user
 	may use this boot param.  The driver will then parse this message out
         and en/disable the specific device entries that are present based upon
         the value given.  The param line is parsed in the following manner:
diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
index 88ef88b..39d409a8 100644
--- a/Documentation/scsi/ncr53c8xx.txt
+++ b/Documentation/scsi/ncr53c8xx.txt
@@ -1260,7 +1260,7 @@
 15.1 Problem tracking
 
 Most SCSI problems are due to a non conformant SCSI bus or to buggy
-devices.  If infortunately you have SCSI problems, you can check the
+devices.  If unfortunately you have SCSI problems, you can check the
 following things:
 
 - SCSI bus cables
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index 3c12422..b7be95b 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-The driver is currently maintained by Kai Mäkisara (email
+The driver is currently maintained by Kai Mäkisara (email
 Kai.Makisara@kolumbus.fi)
 
 Last modified: Mon Mar  7 21:14:44 2005 by kai.makisara
diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
index 2c1745a..3d9f06b 100644
--- a/Documentation/scsi/sym53c8xx_2.txt
+++ b/Documentation/scsi/sym53c8xx_2.txt
@@ -587,7 +587,7 @@
 15.1 Problem tracking
 
 Most SCSI problems are due to a non conformant SCSI bus or too buggy
-devices.  If infortunately you have SCSI problems, you can check the
+devices.  If unfortunately you have SCSI problems, you can check the
 following things:
 
 - SCSI bus cables
diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt
index 8b2168a..61c0531 100644
--- a/Documentation/scsi/tmscsim.txt
+++ b/Documentation/scsi/tmscsim.txt
@@ -426,7 +426,7 @@
 all the others for the wonderful OS and software.
 Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
 release and support.
-Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
+Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
 Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
 Tonneau) for intensively testing the driver (and even risking data loss
 doing this during early revisions).
diff --git a/Documentation/sonypi.txt b/Documentation/sonypi.txt
index c1237a92..4857acf 100644
--- a/Documentation/sonypi.txt
+++ b/Documentation/sonypi.txt
@@ -1,7 +1,7 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
 	Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
-	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
 	Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
 	Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
diff --git a/Documentation/sound/oss/mwave b/Documentation/sound/oss/mwave
index 858334bb..5fbcb16 100644
--- a/Documentation/sound/oss/mwave
+++ b/Documentation/sound/oss/mwave
@@ -163,7 +163,7 @@
 Default=SBPRO
 
 Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure
-the sound modules and voilà - ThinkPad sound with Linux.
+the sound modules and voilà - ThinkPad sound with Linux.
 
 Now the gotchas - you can either have CD sound OR Mixers but not both. That's a
 problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 5922e84..111fd28 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -221,14 +221,14 @@
 
 0: try to continue operation
 
-1: panic immediatly.  If the `panic' sysctl is also non-zero then the
+1: panic immediately.  If the `panic' sysctl is also non-zero then the
    machine will be rebooted.
 
 ==============================================================
 
 pid_max:
 
-PID allocation wrap value.  When the kenrel's next PID value
+PID allocation wrap value.  When the kernel's next PID value
 reaches this value, it wraps back to a minimum PID value.
 PIDs of value pid_max or larger are not allocated.
 
diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS
index 27a7216..67c59cd 100644
--- a/Documentation/usb/CREDITS
+++ b/Documentation/usb/CREDITS
@@ -65,7 +65,7 @@
           will sell keyboards to some of the 3 million (at least)
           Linux users.
 
-        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
           It was almost impossible to get a PC backplate USB connector
           for the motherboard here at Europe (mine, home-made, was
           quite lousy :). Now I know where to acquire nice USB stuff!
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index b18e86a..5b635ae 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -45,9 +45,9 @@
   Connect Tech's Support Department at support@connecttech.com
 
 
-HandSpring Visor, Palm USB, and Clié USB driver
+HandSpring Visor, Palm USB, and Clié USB driver
 
-  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
+  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
   devices.
 
   Only when the device tries to connect to the host, will the device show
@@ -69,7 +69,7 @@
   the port to use for the HotSync transfer. The "Generic" port can be used
   for other device communication, such as a PPP link.
 
-  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
+  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
   device.  This is true for all OS version 3.5 devices, and most devices
   that have had a flash upgrade to a newer version of the OS.  See the
   kernel system log for information on which is the correct port to use.
diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
index a4b7ae8..a747200 100644
--- a/Documentation/video4linux/README.pvrusb2
+++ b/Documentation/video4linux/README.pvrusb2
@@ -8,7 +8,7 @@
 
   This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
   is a USB 2.0 hosted TV Tuner.  This driver is a work in progress.
-  Its history started with the reverse-engineering effort by Björn
+  Its history started with the reverse-engineering effort by Björn
   Danielsson <pvrusb2@dax.nu> whose web page can be found here:
 
     http://pvrusb2.dax.nu/
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 85c575ac..295462b 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -242,7 +242,7 @@
 
 Conexant bt866 TV encoder
 is used in AVS6EYES, and
-can generate: NTSC/PAL, PAL­M, PAL­N
+can generate: NTSC/PAL, PAL­M, PAL­N
 
 The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index 5e51c59..bf3af5f 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -1,7 +1,7 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
 	Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
-	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
diff --git a/Documentation/video4linux/ov511.txt b/Documentation/video4linux/ov511.txt
index 79af610..b3326b1 100644
--- a/Documentation/video4linux/ov511.txt
+++ b/Documentation/video4linux/ov511.txt
@@ -195,11 +195,11 @@
   NAME: bandingfilter
   TYPE: integer (Boolean)
   DEFAULT: 0 (off)
-  DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
+  DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
 	or stabilizes the "banding" caused by some artificial light sources
 	(especially fluorescent). You might have to set lightfreq correctly for
 	this to work right. As an added bonus, this sometimes makes it
-	possible to capture your monitor´s output.
+	possible to capture your monitor´s output.
 
   NAME: fastset
   TYPE: integer (Boolean)
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
index 41710cc..686a8e0 100644
--- a/Documentation/vm/slabinfo.c
+++ b/Documentation/vm/slabinfo.c
@@ -16,6 +16,7 @@
 #include <stdarg.h>
 #include <getopt.h>
 #include <regex.h>
+#include <errno.h>
 
 #define MAX_SLABS 500
 #define MAX_ALIASES 500
@@ -41,12 +42,15 @@
 } aliasinfo[MAX_ALIASES];
 
 int slabs = 0;
+int actual_slabs = 0;
 int aliases = 0;
 int alias_targets = 0;
 int highest_node = 0;
 
 char buffer[4096];
 
+int show_empty = 0;
+int show_report = 0;
 int show_alias = 0;
 int show_slab = 0;
 int skip_zero = 1;
@@ -59,6 +63,15 @@
 int show_single_ref = 0;
 int show_totals = 0;
 int sort_size = 0;
+int set_debug = 0;
+int show_ops = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
 
 int page_size;
 
@@ -76,20 +89,33 @@
 
 void usage(void)
 {
-	printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
+	printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
+		"slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
 		"-a|--aliases           Show aliases\n"
+		"-d<options>|--debug=<options> Set/Clear Debug options\n"
+		"-e|--empty		Show empty slabs\n"
+		"-f|--first-alias       Show first alias\n"
 		"-h|--help              Show usage information\n"
+		"-i|--inverted          Inverted list\n"
+		"-l|--slabs             Show slabs\n"
 		"-n|--numa              Show NUMA information\n"
+		"-o|--ops		Show kmem_cache_ops\n"
 		"-s|--shrink            Shrink slabs\n"
-		"-v|--validate          Validate slabs\n"
+		"-r|--report		Detailed report on single slabs\n"
+		"-S|--Size              Sort by size\n"
 		"-t|--tracking          Show alloc/free information\n"
 		"-T|--Totals            Show summary information\n"
-		"-l|--slabs             Show slabs\n"
-		"-S|--Size              Sort by size\n"
+		"-v|--validate          Validate slabs\n"
 		"-z|--zero              Include empty slabs\n"
-		"-f|--first-alias       Show first alias\n"
-		"-i|--inverted          Inverted list\n"
 		"-1|--1ref              Single reference\n"
+		"\nValid debug options (FZPUT may be combined)\n"
+		"a / A          Switch on all debug options (=FZUP)\n"
+		"-              Switch off all debug options\n"
+		"f / F          Sanity Checks (SLAB_DEBUG_FREE)\n"
+		"z / Z          Redzoning\n"
+		"p / P          Poisoning\n"
+		"u / U          Tracking\n"
+		"t / T          Tracing\n"
 	);
 }
 
@@ -143,11 +169,10 @@
 void set_obj(struct slabinfo *s, char *name, int n)
 {
 	char x[100];
+	FILE *f;
 
 	sprintf(x, "%s/%s", s->name, name);
-
-	FILE *f = fopen(x, "w");
-
+	f = fopen(x, "w");
 	if (!f)
 		fatal("Cannot write to %s\n", x);
 
@@ -155,6 +180,26 @@
 	fclose(f);
 }
 
+unsigned long read_slab_obj(struct slabinfo *s, char *name)
+{
+	char x[100];
+	FILE *f;
+	int l;
+
+	sprintf(x, "%s/%s", s->name, name);
+	f = fopen(x, "r");
+	if (!f) {
+		buffer[0] = 0;
+		l = 0;
+	} else {
+		l = fread(buffer, 1, sizeof(buffer), f);
+		buffer[l] = 0;
+		fclose(f);
+	}
+	return l;
+}
+
+
 /*
  * Put a size string together
  */
@@ -226,7 +271,7 @@
 
 void first_line(void)
 {
-	printf("Name                 Objects   Objsize    Space "
+	printf("Name                   Objects Objsize    Space "
 		"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
 }
 
@@ -246,10 +291,7 @@
 					return best;
 			}
 	}
-	if (best)
-		return best;
-	fatal("Cannot find alias for %s\n", find->name);
-	return NULL;
+	return best;
 }
 
 unsigned long slab_size(struct slabinfo *s)
@@ -257,6 +299,126 @@
 	return 	s->slabs * (page_size << s->order);
 }
 
+void slab_numa(struct slabinfo *s, int mode)
+{
+	int node;
+
+	if (strcmp(s->name, "*") == 0)
+		return;
+
+	if (!highest_node) {
+		printf("\n%s: No NUMA information available.\n", s->name);
+		return;
+	}
+
+	if (skip_zero && !s->slabs)
+		return;
+
+	if (!line) {
+		printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
+		for(node = 0; node <= highest_node; node++)
+			printf(" %4d", node);
+		printf("\n----------------------");
+		for(node = 0; node <= highest_node; node++)
+			printf("-----");
+		printf("\n");
+	}
+	printf("%-21s ", mode ? "All slabs" : s->name);
+	for(node = 0; node <= highest_node; node++) {
+		char b[20];
+
+		store_size(b, s->numa[node]);
+		printf(" %4s", b);
+	}
+	printf("\n");
+	if (mode) {
+		printf("%-21s ", "Partial slabs");
+		for(node = 0; node <= highest_node; node++) {
+			char b[20];
+
+			store_size(b, s->numa_partial[node]);
+			printf(" %4s", b);
+		}
+		printf("\n");
+	}
+	line++;
+}
+
+void show_tracking(struct slabinfo *s)
+{
+	printf("\n%s: Kernel object allocation\n", s->name);
+	printf("-----------------------------------------------------------------------\n");
+	if (read_slab_obj(s, "alloc_calls"))
+		printf(buffer);
+	else
+		printf("No Data\n");
+
+	printf("\n%s: Kernel object freeing\n", s->name);
+	printf("------------------------------------------------------------------------\n");
+	if (read_slab_obj(s, "free_calls"))
+		printf(buffer);
+	else
+		printf("No Data\n");
+
+}
+
+void ops(struct slabinfo *s)
+{
+	if (strcmp(s->name, "*") == 0)
+		return;
+
+	if (read_slab_obj(s, "ops")) {
+		printf("\n%s: kmem_cache operations\n", s->name);
+		printf("--------------------------------------------\n");
+		printf(buffer);
+	} else
+		printf("\n%s has no kmem_cache operations\n", s->name);
+}
+
+const char *onoff(int x)
+{
+	if (x)
+		return "On ";
+	return "Off";
+}
+
+void report(struct slabinfo *s)
+{
+	if (strcmp(s->name, "*") == 0)
+		return;
+	printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order);
+	if (s->hwcache_align)
+		printf("** Hardware cacheline aligned\n");
+	if (s->cache_dma)
+		printf("** Memory is allocated in a special DMA zone\n");
+	if (s->destroy_by_rcu)
+		printf("** Slabs are destroyed via RCU\n");
+	if (s->reclaim_account)
+		printf("** Reclaim accounting active\n");
+
+	printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
+	printf("------------------------------------------------------------------------\n");
+	printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
+			s->object_size, s->slabs, onoff(s->sanity_checks),
+			s->slabs * (page_size << s->order));
+	printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
+			s->slab_size, s->slabs - s->partial - s->cpu_slabs,
+			onoff(s->red_zone), s->objects * s->object_size);
+	printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
+			page_size << s->order, s->partial, onoff(s->poison),
+			s->slabs * (page_size << s->order) - s->objects * s->object_size);
+	printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
+			s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
+			(s->slab_size - s->object_size) * s->objects);
+	printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
+			s->align, s->objs_per_slab, onoff(s->trace),
+			((page_size << s->order) - s->objs_per_slab * s->slab_size) *
+			s->slabs);
+
+	ops(s);
+	show_tracking(s);
+	slab_numa(s, 1);
+}
 
 void slabcache(struct slabinfo *s)
 {
@@ -265,7 +427,18 @@
 	char flags[20];
 	char *p = flags;
 
-	if (skip_zero && !s->slabs)
+	if (strcmp(s->name, "*") == 0)
+		return;
+
+	if (actual_slabs == 1) {
+		report(s);
+		return;
+	}
+
+	if (skip_zero && !show_empty && !s->slabs)
+		return;
+
+	if (show_empty && s->slabs)
 		return;
 
 	store_size(size_str, slab_size(s));
@@ -303,48 +476,128 @@
 		flags);
 }
 
-void slab_numa(struct slabinfo *s)
+/*
+ * Analyze debug options. Return false if something is amiss.
+ */
+int debug_opt_scan(char *opt)
 {
-	int node;
+	if (!opt || !opt[0] || strcmp(opt, "-") == 0)
+		return 1;
 
-	if (!highest_node)
-		fatal("No NUMA information available.\n");
-
-	if (skip_zero && !s->slabs)
-		return;
-
-	if (!line) {
-		printf("\nSlab             Node ");
-		for(node = 0; node <= highest_node; node++)
-			printf(" %4d", node);
-		printf("\n----------------------");
-		for(node = 0; node <= highest_node; node++)
-			printf("-----");
-		printf("\n");
+	if (strcasecmp(opt, "a") == 0) {
+		sanity = 1;
+		poison = 1;
+		redzone = 1;
+		tracking = 1;
+		return 1;
 	}
-	printf("%-21s ", s->name);
-	for(node = 0; node <= highest_node; node++) {
-		char b[20];
 
-		store_size(b, s->numa[node]);
-		printf(" %4s", b);
-	}
-	printf("\n");
-	line++;
+	for ( ; *opt; opt++)
+	 	switch (*opt) {
+		case 'F' : case 'f':
+			if (sanity)
+				return 0;
+			sanity = 1;
+			break;
+		case 'P' : case 'p':
+			if (poison)
+				return 0;
+			poison = 1;
+			break;
+
+		case 'Z' : case 'z':
+			if (redzone)
+				return 0;
+			redzone = 1;
+			break;
+
+		case 'U' : case 'u':
+			if (tracking)
+				return 0;
+			tracking = 1;
+			break;
+
+		case 'T' : case 't':
+			if (tracing)
+				return 0;
+			tracing = 1;
+			break;
+		default:
+			return 0;
+		}
+	return 1;
 }
 
-void show_tracking(struct slabinfo *s)
+int slab_empty(struct slabinfo *s)
 {
-	printf("\n%s: Calls to allocate a slab object\n", s->name);
-	printf("---------------------------------------------------\n");
-	if (read_obj("alloc_calls"))
-		printf(buffer);
+	if (s->objects > 0)
+		return 0;
 
-	printf("%s: Calls to free a slab object\n", s->name);
-	printf("-----------------------------------------------\n");
-	if (read_obj("free_calls"))
-		printf(buffer);
+	/*
+	 * We may still have slabs even if there are no objects. Shrinking will
+	 * remove them.
+	 */
+	if (s->slabs != 0)
+		set_obj(s, "shrink", 1);
 
+	return 1;
+}
+
+void slab_debug(struct slabinfo *s)
+{
+	if (sanity && !s->sanity_checks) {
+		set_obj(s, "sanity", 1);
+	}
+	if (!sanity && s->sanity_checks) {
+		if (slab_empty(s))
+			set_obj(s, "sanity", 0);
+		else
+			fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
+	}
+	if (redzone && !s->red_zone) {
+		if (slab_empty(s))
+			set_obj(s, "red_zone", 1);
+		else
+			fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
+	}
+	if (!redzone && s->red_zone) {
+		if (slab_empty(s))
+			set_obj(s, "red_zone", 0);
+		else
+			fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
+	}
+	if (poison && !s->poison) {
+		if (slab_empty(s))
+			set_obj(s, "poison", 1);
+		else
+			fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
+	}
+	if (!poison && s->poison) {
+		if (slab_empty(s))
+			set_obj(s, "poison", 0);
+		else
+			fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
+	}
+	if (tracking && !s->store_user) {
+		if (slab_empty(s))
+			set_obj(s, "store_user", 1);
+		else
+			fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
+	}
+	if (!tracking && s->store_user) {
+		if (slab_empty(s))
+			set_obj(s, "store_user", 0);
+		else
+			fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
+	}
+	if (tracing && !s->trace) {
+		if (slabs == 1)
+			set_obj(s, "trace", 1);
+		else
+			fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
+	}
+	if (!tracing && s->trace)
+		set_obj(s, "trace", 1);
 }
 
 void totals(void)
@@ -673,7 +926,7 @@
 
 	for (a = aliasinfo; a < aliasinfo + aliases; a++) {
 
-		for(s = slabinfo; s < slabinfo + slabs; s++)
+		for (s = slabinfo; s < slabinfo + slabs; s++)
 			if (strcmp(a->ref, s->name) == 0) {
 				a->slab = s;
 				s->refs++;
@@ -704,7 +957,7 @@
 					continue;
 				}
 			}
-			printf("\n%-20s <- %s", a->slab->name, a->name);
+			printf("\n%-12s <- %s", a->slab->name, a->name);
 			active = a->slab->name;
 		}
 		else
@@ -729,7 +982,12 @@
 
 		a = find_one_alias(s);
 
-		s->name = a->name;
+		if (a)
+			s->name = a->name;
+		else {
+			s->name = "*";
+			actual_slabs--;
+		}
 	}
 }
 
@@ -748,11 +1006,14 @@
 	char *t;
 	int count;
 
+	if (chdir("/sys/slab"))
+		fatal("SYSFS support for SLUB not active\n");
+
 	dir = opendir(".");
 	while ((de = readdir(dir))) {
 		if (de->d_name[0] == '.' ||
-				slab_mismatch(de->d_name))
-			continue;
+			(de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+				continue;
 		switch (de->d_type) {
 		   case DT_LNK:
 		   	alias->name = strdup(de->d_name);
@@ -807,6 +1068,7 @@
 	}
 	closedir(dir);
 	slabs = slab - slabinfo;
+	actual_slabs = slabs;
 	aliases = alias - aliasinfo;
 	if (slabs > MAX_SLABS)
 		fatal("Too many slabs\n");
@@ -825,34 +1087,37 @@
 
 
 		if (show_numa)
-			slab_numa(slab);
-		else
-		if (show_track)
+			slab_numa(slab, 0);
+		else if (show_track)
 			show_tracking(slab);
-		else
-		if (validate)
+		else if (validate)
 			slab_validate(slab);
-		else
-		if (shrink)
+		else if (shrink)
 			slab_shrink(slab);
-		else {
-			if (show_slab)
-				slabcache(slab);
-		}
+		else if (set_debug)
+			slab_debug(slab);
+		else if (show_ops)
+			ops(slab);
+		else if (show_slab)
+			slabcache(slab);
 	}
 }
 
 struct option opts[] = {
 	{ "aliases", 0, NULL, 'a' },
-	{ "slabs", 0, NULL, 'l' },
-	{ "numa", 0, NULL, 'n' },
-	{ "zero", 0, NULL, 'z' },
-	{ "help", 0, NULL, 'h' },
-	{ "validate", 0, NULL, 'v' },
+	{ "debug", 2, NULL, 'd' },
+	{ "empty", 0, NULL, 'e' },
 	{ "first-alias", 0, NULL, 'f' },
-	{ "shrink", 0, NULL, 's' },
-	{ "track", 0, NULL, 't'},
+	{ "help", 0, NULL, 'h' },
 	{ "inverted", 0, NULL, 'i'},
+	{ "numa", 0, NULL, 'n' },
+	{ "ops", 0, NULL, 'o' },
+	{ "report", 0, NULL, 'r' },
+	{ "shrink", 0, NULL, 's' },
+	{ "slabs", 0, NULL, 'l' },
+	{ "track", 0, NULL, 't'},
+	{ "validate", 0, NULL, 'v' },
+	{ "zero", 0, NULL, 'z' },
 	{ "1ref", 0, NULL, '1'},
 	{ NULL, 0, NULL, 0 }
 };
@@ -864,10 +1129,9 @@
 	char *pattern_source;
 
 	page_size = getpagesize();
-	if (chdir("/sys/slab"))
-		fatal("This kernel does not have SLUB support.\n");
 
-	while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1)
+	while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
+						opts, NULL)) != -1)
 	switch(c) {
 		case '1':
 			show_single_ref = 1;
@@ -875,6 +1139,14 @@
 		case 'a':
 			show_alias = 1;
 			break;
+		case 'd':
+			set_debug = 1;
+			if (!debug_opt_scan(optarg))
+				fatal("Invalid debug option '%s'\n", optarg);
+			break;
+		case 'e':
+			show_empty = 1;
+			break;
 		case 'f':
 			show_first_alias = 1;
 			break;
@@ -887,6 +1159,12 @@
 		case 'n':
 			show_numa = 1;
 			break;
+		case 'o':
+			show_ops = 1;
+			break;
+		case 'r':
+			show_report = 1;
+			break;
 		case 's':
 			shrink = 1;
 			break;
@@ -914,8 +1192,8 @@
 
 	}
 
-	if (!show_slab && !show_alias && !show_track
-		&& !validate && !shrink)
+	if (!show_slab && !show_alias && !show_track && !show_report
+		&& !validate && !shrink && !set_debug && !show_ops)
 			show_slab = 1;
 
 	if (argc > optind)
diff --git a/MAINTAINERS b/MAINTAINERS
index 41a4b47..cfd26dd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1038,6 +1038,8 @@
 CONEXANT ACCESSRUNNER USB DRIVER
 P:	Simon Arlott
 M:	cxacru@fire.lp0.eu
+L:	accessrunner-general@lists.sourceforge.net
+W:	http://accessrunner.sourceforge.net/
 S:	Maintained
 
 CORETEMP HARDWARE MONITORING DRIVER
@@ -2646,6 +2648,12 @@
 L:	video4linux-list@redhat.com
 S:	Maintained
 
+ONENAND FLASH DRIVER
+P:	Kyungmin Park
+M:	kyungmin.park@samsung.com
+L:	linux-mtd@lists.infradead.org
+S:	Maintained
+
 ONSTREAM SCSI TAPE DRIVER
 P:	Willem Riede
 M:	osst@riede.org
@@ -2800,7 +2808,7 @@
 S:	Maintained
 
 PHRAM MTD DRIVER
-P:	Jörn Engel
+P:	Jörn Engel
 M:	joern@wh.fh-wedel.de
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
@@ -3074,7 +3082,7 @@
 S:	Maintained
 
 SCSI TAPE DRIVER
-P:	Kai Mäkisara
+P:	Kai Mäkisara
 M:	Kai.Makisara@kolumbus.fi
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0d8fac3..d7c0984 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -354,6 +354,7 @@
 config ARCH_S3C2410
 	bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
 	select GENERIC_GPIO
+	select GENERIC_TIME
 	help
 	  Samsung S3C2410X CPU based systems, such as the Simtec Electronics
 	  BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ab9f2d4..00ea430 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -47,8 +47,13 @@
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7)		:=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7a,-march=armv5t -Wa$(comma)-march=armv7a)
 arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+# Only override the compiler option if ARMv6. The ARMv6K extensions are
+# always available in ARMv7
+ifeq ($(CONFIG_CPU_32v6),y)
 arch-$(CONFIG_CPU_32v6K)	:=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+endif
 arch-$(CONFIG_CPU_32v5)		:=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
 arch-$(CONFIG_CPU_32v4T)	:=-D__LINUX_ARM_ARCH__=4 -march=armv4t
 arch-$(CONFIG_CPU_32v4)		:=-D__LINUX_ARM_ARCH__=4 -march=armv4
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 0119c0d..5d78ffb 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -33,7 +33,7 @@
  * numbers for r1.
  *
  */
-	__INIT
+	.section ".text.head", "ax"
 	.type	stext, %function
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 1d35eda..41f98b4 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -73,7 +73,7 @@
  * crap here - that's what the boot loader (or in extreme, well justified
  * circumstances, zImage) is for.
  */
-	__INIT
+	.section ".text.head", "ax"
 	.type	stext, %function
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index a00cca0..bd4ef53 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -31,7 +31,7 @@
  * The things we do for performance..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".init.task"))) =
+	__attribute__((__section__(".data.init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1b06158..79b7e5c 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -116,8 +116,8 @@
 
 			offset += sym->st_value - loc;
 			if (offset & 3 ||
-			    offset <= (s32)0xfc000000 ||
-			    offset >= (s32)0x04000000) {
+			    offset <= (s32)0xfe000000 ||
+			    offset >= (s32)0x02000000) {
 				printk(KERN_ERR
 				       "%s: relocation out of range, section "
 				       "%d reloc %d sym '%s'\n", module->name,
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 070bcb7..1b76d87 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -486,7 +486,7 @@
 }
 
 #ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void do_local_timer(struct pt_regs *regs)
+asmlinkage void __exception do_local_timer(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	int cpu = smp_processor_id();
@@ -551,7 +551,7 @@
  *
  *  Bit 0 - Inter-processor function call
  */
-asmlinkage void do_IPI(struct pt_regs *regs)
+asmlinkage void __exception do_IPI(struct pt_regs *regs)
 {
 	unsigned int cpu = smp_processor_id();
 	struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 6be6729..e4156e7 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -23,11 +23,15 @@
 #else
 	. = PAGE_OFFSET + TEXT_OFFSET;
 #endif
-	.init : {			/* Init code and data		*/
+	.text.head : {
 		_stext = .;
-			_sinittext = .;
+		_sinittext = .;
+		*(.text.head)
+	}
+
+	.init : {			/* Init code and data		*/
 			*(.init.text)
-			_einittext = .;
+		_einittext = .;
 		__proc_info_begin = .;
 			*(.proc.info.init)
 		__proc_info_end = .;
@@ -119,7 +123,7 @@
 		 * first, the init task union, aligned
 		 * to an 8192 byte boundary.
 		 */
-		*(.init.task)
+		*(.data.init_task)
 
 #ifdef CONFIG_XIP_KERNEL
 		. = ALIGN(4096);
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index e238ad8..018d637 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -107,7 +107,7 @@
 	depends on ARCH_AT91SAM9260
 	help
 	  Select this if you are using Atmel's AT91SAM9XE System-on-Chip.
-	  They are basicaly AT91SAM9260s with various sizes of embedded Flash.
+	  They are basically AT91SAM9260s with various sizes of embedded Flash.
 
 comment "AT91SAM9260 / AT91SAM9XE Board Type"
 
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 8781aae..856c681 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -22,6 +22,7 @@
 config MACH_OMAP_INNOVATOR
 	bool "TI Innovator"
 	depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+	select OMAP_MCBSP
 	help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -29,6 +30,7 @@
 config MACH_OMAP_H2
 	bool "TI H2 Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+	select OMAP_MCBSP
     	help
 	  TI OMAP 1610/1611B H2 board support. Say Y here if you have such
 	  a board.
@@ -36,6 +38,7 @@
 config MACH_OMAP_H3
 	bool "TI H3 Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
+	select GPIOEXPANDER_OMAP
     	help
 	  TI OMAP 1710 H3 board support. Say Y here if you have such
 	  a board.
@@ -43,7 +46,7 @@
 config MACH_OMAP_OSK
 	bool "TI OSK Support"
 	depends on ARCH_OMAP1 && ARCH_OMAP16XX
-	select TPS65010
+	select OMAP_MCBSP
     	help
 	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -84,7 +87,7 @@
           Support for the Palm Tungsten E PDA. Currently only the LCD panel
           is supported. To boot the kernel, you'll need a PalmOS compatible
           bootloader; check out http://palmtelinux.sourceforge.net for more
-          informations.
+          information.
           Say Y here if you have such a PDA, say NO otherwise.
 
 config MACH_NOKIA770
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 7165f74..a8b9a00 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -37,4 +37,3 @@
 led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
 obj-$(CONFIG_LEDS)			+= $(led-y)
-
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 62e42c7a..f65baa9 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -246,7 +246,7 @@
 	mdelay(50);
 }
 
-void omap_fsample_init_irq(void)
+static void __init omap_fsample_init_irq(void)
 {
 	omap1_init_common_hw();
 	omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 9d2346f..7b260b7 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -455,7 +455,7 @@
 	}
 }
 
-void h3_init_irq(void)
+static void __init h3_init_irq(void)
 {
 	omap1_init_common_hw();
 	omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index cb00530..7e63a41 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -308,7 +308,7 @@
 	}
 }
 
-void innovator_init_irq(void)
+static void __init innovator_init_irq(void)
 {
 	omap1_init_common_hw();
 	omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index fa4be96..1d5c8d5 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -246,7 +246,7 @@
 	mdelay(50);
 }
 
-void omap_perseus2_init_irq(void)
+static void __init omap_perseus2_init_irq(void)
 {
 	omap1_init_common_hw();
 	omap_init_irq();
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 6dcd10a..da8a3ac 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -24,35 +24,6 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if	defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
-
-static u64 irda_dmamask = 0xffffffff;
-
-static struct platform_device omap1610ir_device = {
-	.name = "omap1610-ir",
-	.id = -1,
-	.dev = {
-		.dma_mask	= &irda_dmamask,
-	},
-};
-
-static void omap_init_irda(void)
-{
-	/* FIXME define and use a boot tag, members something like:
-	 *  u8		uart;		// uart1, or uart3
-	 * ... but driver only handles uart3 for now
-	 *  s16		fir_sel;	// gpio for SIR vs FIR
-	 * ... may prefer a callback for SIR/MIR/FIR mode select;
-	 * while h2 uses a GPIO, H3 uses a gpio expander
-	 */
-	if (machine_is_omap_h2()
-			|| machine_is_omap_h3())
-		(void) platform_device_register(&omap1610ir_device);
-}
-#else
-static inline void omap_init_irda(void) {}
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
@@ -90,6 +61,45 @@
 static inline void omap_init_rtc(void) {}
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#if defined(CONFIG_ARCH_OMAP15XX)
+#  define OMAP1_MBOX_SIZE	0x23
+#  define INT_DSP_MAILBOX1	INT_1510_DSP_MAILBOX1
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#  define OMAP1_MBOX_SIZE	0x2f
+#  define INT_DSP_MAILBOX1	INT_1610_DSP_MAILBOX1
+#endif
+
+#define OMAP1_MBOX_BASE		IO_ADDRESS(OMAP16XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+	{
+		.start		= OMAP1_MBOX_BASE,
+		.end		= OMAP1_MBOX_BASE + OMAP1_MBOX_SIZE,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_DSP_MAILBOX1,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mbox_device = {
+	.name		= "mailbox",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mbox_resources),
+	.resource	= mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+	platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP1_STI_BASE		IO_ADDRESS(0xfffea000)
@@ -154,7 +164,8 @@
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
-	omap_init_irda();
+
+	omap_init_mbox();
 	omap_init_rtc();
 	omap_init_sti();
 
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index fab8b0b..81c4e73 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -17,11 +17,11 @@
 #include <asm/io.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
-#include <asm/arch/omapfb.h>
 
 extern int omap1_clk_init(void);
 extern void omap_check_revision(void);
 extern void omap_sram_init(void);
+extern void omapfb_reserve_sdram(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -121,7 +121,7 @@
 #endif
 
 	omap_sram_init();
-	omapfb_reserve_mem();
+	omapfb_reserve_sdram();
 }
 
 /*
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
new file mode 100644
index 0000000..d3abf56
--- /dev/null
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -0,0 +1,206 @@
+/*
+ * Mailbox reservation modules for DSP
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/resource.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_ARM2DSP1		0x00
+#define MAILBOX_ARM2DSP1b		0x04
+#define MAILBOX_DSP2ARM1		0x08
+#define MAILBOX_DSP2ARM1b		0x0c
+#define MAILBOX_DSP2ARM2		0x10
+#define MAILBOX_DSP2ARM2b		0x14
+#define MAILBOX_ARM2DSP1_Flag		0x18
+#define MAILBOX_DSP2ARM1_Flag		0x1c
+#define MAILBOX_DSP2ARM2_Flag		0x20
+
+unsigned long mbox_base;
+
+struct omap_mbox1_fifo {
+	unsigned long cmd;
+	unsigned long data;
+	unsigned long flag;
+};
+
+struct omap_mbox1_priv {
+	struct omap_mbox1_fifo tx_fifo;
+	struct omap_mbox1_fifo rx_fifo;
+};
+
+static inline int mbox_read_reg(unsigned int reg)
+{
+	return __raw_readw(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+	__raw_writew(val, mbox_base + reg);
+}
+
+/* msg */
+static inline mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox)
+{
+	struct omap_mbox1_fifo *fifo =
+		&((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+	mbox_msg_t msg;
+
+	msg = mbox_read_reg(fifo->data);
+	msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16;
+
+	return msg;
+}
+
+static inline void
+omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	struct omap_mbox1_fifo *fifo =
+		&((struct omap_mbox1_priv *)mbox->priv)->tx_fifo;
+
+	mbox_write_reg(msg & 0xffff, fifo->data);
+	mbox_write_reg(msg >> 16, fifo->cmd);
+}
+
+static inline int omap1_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+	return 0;
+}
+
+static inline int omap1_mbox_fifo_full(struct omap_mbox *mbox)
+{
+	struct omap_mbox1_fifo *fifo =
+		&((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+
+	return (mbox_read_reg(fifo->flag));
+}
+
+/* irq */
+static inline void
+omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+	if (irq == IRQ_RX)
+		enable_irq(mbox->irq);
+}
+
+static inline void
+omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+	if (irq == IRQ_RX)
+		disable_irq(mbox->irq);
+}
+
+static inline int
+omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+	if (irq == IRQ_TX)
+		return 0;
+	return 1;
+}
+
+static struct omap_mbox_ops omap1_mbox_ops = {
+	.type		= OMAP_MBOX_TYPE1,
+	.fifo_read	= omap1_mbox_fifo_read,
+	.fifo_write	= omap1_mbox_fifo_write,
+	.fifo_empty	= omap1_mbox_fifo_empty,
+	.fifo_full	= omap1_mbox_fifo_full,
+	.enable_irq	= omap1_mbox_enable_irq,
+	.disable_irq	= omap1_mbox_disable_irq,
+	.is_irq		= omap1_mbox_is_irq,
+};
+
+/* FIXME: the following struct should be created automatically by the user id */
+
+/* DSP */
+static struct omap_mbox1_priv omap1_mbox_dsp_priv = {
+	.tx_fifo = {
+		.cmd	= MAILBOX_ARM2DSP1b,
+		.data	= MAILBOX_ARM2DSP1,
+		.flag	= MAILBOX_ARM2DSP1_Flag,
+	},
+	.rx_fifo = {
+		.cmd	= MAILBOX_DSP2ARM1b,
+		.data	= MAILBOX_DSP2ARM1,
+		.flag	= MAILBOX_DSP2ARM1_Flag,
+	},
+};
+
+struct omap_mbox mbox_dsp_info = {
+	.name	= "dsp",
+	.ops	= &omap1_mbox_ops,
+	.priv	= &omap1_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+static int __init omap1_mbox_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret = 0;
+
+	if (pdev->num_resources != 2) {
+		dev_err(&pdev->dev, "invalid number of resources: %d\n",
+			pdev->num_resources);
+		return -ENODEV;
+	}
+
+	/* MBOX base */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid mem resource\n");
+		return -ENODEV;
+	}
+	mbox_base = res->start;
+
+	/* DSP IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid irq resource\n");
+		return -ENODEV;
+	}
+	mbox_dsp_info.irq = res->start;
+
+	ret = omap_mbox_register(&mbox_dsp_info);
+
+	return ret;
+}
+
+static int omap1_mbox_remove(struct platform_device *pdev)
+{
+	omap_mbox_unregister(&mbox_dsp_info);
+
+	return 0;
+}
+
+static struct platform_driver omap1_mbox_driver = {
+	.probe	= omap1_mbox_probe,
+	.remove	= omap1_mbox_remove,
+	.driver	= {
+		.name	= "mailbox",
+	},
+};
+
+static int __init omap1_mbox_init(void)
+{
+	return platform_driver_register(&omap1_mbox_driver);
+}
+
+static void __exit omap1_mbox_exit(void)
+{
+	platform_driver_unregister(&omap1_mbox_driver);
+}
+
+module_init(omap1_mbox_init);
+module_exit(omap1_mbox_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index aab97cc..7393109 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -9,6 +9,7 @@
 	bool "OMAP2420 support"
 	depends on ARCH_OMAP24XX
 	select OMAP_DM_TIMER
+	select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
 	depends on ARCH_OMAP2
@@ -20,6 +21,7 @@
 config MACH_OMAP_H4
 	bool "OMAP 2420 H4 board"
 	depends on ARCH_OMAP2 && ARCH_OMAP24XX
+	select OMAP_DEBUG_LEDS if LEDS || LEDS_OMAP_DEBUG
 
 config MACH_OMAP_APOLLON
 	bool "OMAP 2420 Apollon board"
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 1e7ed6d..452193f0 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -266,12 +266,26 @@
 	.id		= -1,
 };
 
+static struct resource h4_led_resources[] = {
+	[0] = {
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device h4_led_device = {
+	.name		= "omap_dbg_led",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(h4_led_resources),
+	.resource	= h4_led_resources,
+};
+
 static struct platform_device *h4_devices[] __initdata = {
 	&h4_smc91x_device,
 	&h4_flash_device,
 	&h4_irda_device,
 	&h4_kp_device,
 	&h4_lcd_device,
+	&h4_led_device,
 };
 
 static inline void __init h4_init_smc91x(void)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index aa43224..52ec2f2 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -24,7 +24,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if 	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define OMAP2_I2C_BASE2		0x48072000
 #define OMAP2_I2C_INT2		57
@@ -42,8 +42,8 @@
 };
 
 static struct platform_device omap_i2c_device2 = {
-        .name           = "i2c_omap",
-        .id             = 2,
+	.name           = "i2c_omap",
+	.id             = 2,
 	.num_resources	= ARRAY_SIZE(i2c_resources2),
 	.resource	= i2c_resources2,
 };
@@ -66,6 +66,40 @@
 
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+#define OMAP2_MBOX_BASE		IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+	{
+		.start		= OMAP2_MBOX_BASE,
+		.end		= OMAP2_MBOX_BASE + 0x11f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_24XX_MAIL_U0_MPU,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= INT_24XX_MAIL_U3_MPU,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mbox_device = {
+	.name		= "mailbox",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mbox_resources),
+	.resource	= mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+	platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP2_STI_BASE		IO_ADDRESS(0x48068000)
@@ -111,29 +145,45 @@
 #define OMAP2_MCSPI1_BASE		0x48098000
 #define OMAP2_MCSPI2_BASE		0x4809a000
 
-/* FIXME: use resources instead */
-
 static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
-	.base		= io_p2v(OMAP2_MCSPI1_BASE),
 	.num_cs		= 4,
 };
 
+static struct resource omap2_mcspi1_resources[] = {
+	{
+		.start		= OMAP2_MCSPI1_BASE,
+		.end		= OMAP2_MCSPI1_BASE + 0xff,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
 struct platform_device omap2_mcspi1 = {
 	.name		= "omap2_mcspi",
 	.id		= 1,
+	.num_resources	= ARRAY_SIZE(omap2_mcspi1_resources),
+	.resource	= omap2_mcspi1_resources,
 	.dev		= {
 		.platform_data = &omap2_mcspi1_config,
 	},
 };
 
 static struct omap2_mcspi_platform_config omap2_mcspi2_config = {
-	.base		= io_p2v(OMAP2_MCSPI2_BASE),
 	.num_cs		= 2,
 };
 
+static struct resource omap2_mcspi2_resources[] = {
+	{
+		.start		= OMAP2_MCSPI2_BASE,
+		.end		= OMAP2_MCSPI2_BASE + 0xff,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
 struct platform_device omap2_mcspi2 = {
 	.name		= "omap2_mcspi",
 	.id		= 2,
+	.num_resources	= ARRAY_SIZE(omap2_mcspi2_resources),
+	.resource	= omap2_mcspi2_resources,
 	.dev		= {
 		.platform_data = &omap2_mcspi2_config,
 	},
@@ -157,10 +207,10 @@
 	 * in alphabetical order so they're easier to sort through.
 	 */
 	omap_init_i2c();
+	omap_init_mbox();
 	omap_init_mcspi();
 	omap_init_sti();
 
 	return 0;
 }
 arch_initcall(omap2_init_devices);
-
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d8f5782..54c836a9 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -246,14 +246,22 @@
 	return l & (1 << 6);
 }
 
-static void gpmc_cs_set_reserved(int cs, int reserved)
+int gpmc_cs_set_reserved(int cs, int reserved)
 {
+	if (cs > GPMC_CS_NUM)
+		return -ENODEV;
+
 	gpmc_cs_map &= ~(1 << cs);
 	gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+
+	return 0;
 }
 
-static int gpmc_cs_reserved(int cs)
+int gpmc_cs_reserved(int cs)
 {
+	if (cs > GPMC_CS_NUM)
+		return -ENODEV;
+
 	return gpmc_cs_map & (1 << cs);
 }
 
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index a0728c3..82dc70f 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -27,6 +27,7 @@
 extern int omap2_clk_init(void);
 extern void omap2_check_revision(void);
 extern void gpmc_init(void);
+extern void omapfb_reserve_sdram(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -40,9 +41,21 @@
 		.type		= MT_DEVICE
 	},
 	{
-		.virtual	= L4_24XX_VIRT,
-		.pfn		= __phys_to_pfn(L4_24XX_PHYS),
-		.length		= L4_24XX_SIZE,
+		.virtual	= DSP_MEM_24XX_VIRT,
+		.pfn		= __phys_to_pfn(DSP_MEM_24XX_PHYS),
+		.length		= DSP_MEM_24XX_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= DSP_IPI_24XX_VIRT,
+		.pfn		= __phys_to_pfn(DSP_IPI_24XX_PHYS),
+		.length		= DSP_IPI_24XX_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= DSP_MMU_24XX_VIRT,
+		.pfn		= __phys_to_pfn(DSP_MMU_24XX_PHYS),
+		.length		= DSP_MMU_24XX_SIZE,
 		.type		= MT_DEVICE
 	}
 };
@@ -60,7 +73,7 @@
 
 	omap2_check_revision();
 	omap_sram_init();
-	omapfb_reserve_mem();
+	omapfb_reserve_sdram();
 }
 
 void __init omap2_init_common_hw(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
new file mode 100644
index 0000000..b03cd06
--- /dev/null
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -0,0 +1,318 @@
+/*
+ * Mailbox reservation modules for OMAP2
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *        and  Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_REVISION		0x00
+#define MAILBOX_SYSCONFIG		0x10
+#define MAILBOX_SYSSTATUS		0x14
+#define MAILBOX_MESSAGE_0		0x40
+#define MAILBOX_MESSAGE_1		0x44
+#define MAILBOX_MESSAGE_2		0x48
+#define MAILBOX_MESSAGE_3		0x4c
+#define MAILBOX_MESSAGE_4		0x50
+#define MAILBOX_MESSAGE_5		0x54
+#define MAILBOX_FIFOSTATUS_0		0x80
+#define MAILBOX_FIFOSTATUS_1		0x84
+#define MAILBOX_FIFOSTATUS_2		0x88
+#define MAILBOX_FIFOSTATUS_3		0x8c
+#define MAILBOX_FIFOSTATUS_4		0x90
+#define MAILBOX_FIFOSTATUS_5		0x94
+#define MAILBOX_MSGSTATUS_0		0xc0
+#define MAILBOX_MSGSTATUS_1		0xc4
+#define MAILBOX_MSGSTATUS_2		0xc8
+#define MAILBOX_MSGSTATUS_3		0xcc
+#define MAILBOX_MSGSTATUS_4		0xd0
+#define MAILBOX_MSGSTATUS_5		0xd4
+#define MAILBOX_IRQSTATUS_0		0x100
+#define MAILBOX_IRQENABLE_0		0x104
+#define MAILBOX_IRQSTATUS_1		0x108
+#define MAILBOX_IRQENABLE_1		0x10c
+#define MAILBOX_IRQSTATUS_2		0x110
+#define MAILBOX_IRQENABLE_2		0x114
+#define MAILBOX_IRQSTATUS_3		0x118
+#define MAILBOX_IRQENABLE_3		0x11c
+
+static unsigned long mbox_base;
+
+#define MAILBOX_IRQ_NOTFULL(n)		(1 << (2 * (n) + 1))
+#define MAILBOX_IRQ_NEWMSG(n)		(1 << (2 * (n)))
+
+struct omap_mbox2_fifo {
+	unsigned long msg;
+	unsigned long fifo_stat;
+	unsigned long msg_stat;
+};
+
+struct omap_mbox2_priv {
+	struct omap_mbox2_fifo tx_fifo;
+	struct omap_mbox2_fifo rx_fifo;
+	unsigned long irqenable;
+	unsigned long irqstatus;
+	u32 newmsg_bit;
+	u32 notfull_bit;
+};
+
+static struct clk *mbox_ick_handle;
+
+static inline unsigned int mbox_read_reg(unsigned int reg)
+{
+	return __raw_readl(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+	__raw_writel(val, mbox_base + reg);
+}
+
+/* Mailbox H/W preparations */
+static inline int omap2_mbox_startup(struct omap_mbox *mbox)
+{
+	unsigned int l;
+
+	mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
+	if (IS_ERR(mbox_ick_handle)) {
+		printk("Could not get mailboxes_ick\n");
+		return -ENODEV;
+	}
+	clk_enable(mbox_ick_handle);
+
+	/* set smart-idle & autoidle */
+	l = mbox_read_reg(MAILBOX_SYSCONFIG);
+	l |= 0x00000011;
+	mbox_write_reg(l, MAILBOX_SYSCONFIG);
+
+	return 0;
+}
+
+static inline void omap2_mbox_shutdown(struct omap_mbox *mbox)
+{
+	clk_disable(mbox_ick_handle);
+	clk_put(mbox_ick_handle);
+}
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
+{
+	struct omap_mbox2_fifo *fifo =
+		&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+	return (mbox_msg_t) mbox_read_reg(fifo->msg);
+}
+
+static inline void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	struct omap_mbox2_fifo *fifo =
+		&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+	mbox_write_reg(msg, fifo->msg);
+}
+
+static inline int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+	struct omap_mbox2_fifo *fifo =
+		&((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+	return (mbox_read_reg(fifo->msg_stat) == 0);
+}
+
+static inline int omap2_mbox_fifo_full(struct omap_mbox *mbox)
+{
+	struct omap_mbox2_fifo *fifo =
+		&((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+	return (mbox_read_reg(fifo->fifo_stat));
+}
+
+/* Mailbox IRQ handle functions */
+static inline void omap2_mbox_enable_irq(struct omap_mbox *mbox,
+		omap_mbox_type_t irq)
+{
+	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+	l = mbox_read_reg(p->irqenable);
+	l |= bit;
+	mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_disable_irq(struct omap_mbox *mbox,
+		omap_mbox_type_t irq)
+{
+	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+	l = mbox_read_reg(p->irqenable);
+	l &= ~bit;
+	mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_ack_irq(struct omap_mbox *mbox,
+		omap_mbox_type_t irq)
+{
+	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+	mbox_write_reg(bit, p->irqstatus);
+}
+
+static inline int omap2_mbox_is_irq(struct omap_mbox *mbox,
+		omap_mbox_type_t irq)
+{
+	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+	u32 enable = mbox_read_reg(p->irqenable);
+	u32 status = mbox_read_reg(p->irqstatus);
+
+	return (enable & status & bit);
+}
+
+static struct omap_mbox_ops omap2_mbox_ops = {
+	.type		= OMAP_MBOX_TYPE2,
+	.startup	= omap2_mbox_startup,
+	.shutdown	= omap2_mbox_shutdown,
+	.fifo_read	= omap2_mbox_fifo_read,
+	.fifo_write	= omap2_mbox_fifo_write,
+	.fifo_empty	= omap2_mbox_fifo_empty,
+	.fifo_full	= omap2_mbox_fifo_full,
+	.enable_irq	= omap2_mbox_enable_irq,
+	.disable_irq	= omap2_mbox_disable_irq,
+	.ack_irq	= omap2_mbox_ack_irq,
+	.is_irq		= omap2_mbox_is_irq,
+};
+
+/*
+ * MAILBOX 0: ARM -> DSP,
+ * MAILBOX 1: ARM <- DSP.
+ * MAILBOX 2: ARM -> IVA,
+ * MAILBOX 3: ARM <- IVA.
+ */
+
+/* FIXME: the following structs should be filled automatically by the user id */
+
+/* DSP */
+static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
+	.tx_fifo = {
+		.msg		= MAILBOX_MESSAGE_0,
+		.fifo_stat	= MAILBOX_FIFOSTATUS_0,
+	},
+	.rx_fifo = {
+		.msg		= MAILBOX_MESSAGE_1,
+		.msg_stat	= MAILBOX_MSGSTATUS_1,
+	},
+	.irqenable	= MAILBOX_IRQENABLE_0,
+	.irqstatus	= MAILBOX_IRQSTATUS_0,
+	.notfull_bit	= MAILBOX_IRQ_NOTFULL(0),
+	.newmsg_bit	= MAILBOX_IRQ_NEWMSG(1),
+};
+
+struct omap_mbox mbox_dsp_info = {
+	.name	= "dsp",
+	.ops	= &omap2_mbox_ops,
+	.priv	= &omap2_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+/* IVA */
+static struct omap_mbox2_priv omap2_mbox_iva_priv = {
+	.tx_fifo = {
+		.msg		= MAILBOX_MESSAGE_2,
+		.fifo_stat	= MAILBOX_FIFOSTATUS_2,
+	},
+	.rx_fifo = {
+		.msg		= MAILBOX_MESSAGE_3,
+		.msg_stat	= MAILBOX_MSGSTATUS_3,
+	},
+	.irqenable	= MAILBOX_IRQENABLE_3,
+	.irqstatus	= MAILBOX_IRQSTATUS_3,
+	.notfull_bit	= MAILBOX_IRQ_NOTFULL(2),
+	.newmsg_bit	= MAILBOX_IRQ_NEWMSG(3),
+};
+
+static struct omap_mbox mbox_iva_info = {
+	.name	= "iva",
+	.ops	= &omap2_mbox_ops,
+	.priv	= &omap2_mbox_iva_priv,
+};
+
+static int __init omap2_mbox_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret = 0;
+
+	if (pdev->num_resources != 3) {
+		dev_err(&pdev->dev, "invalid number of resources: %d\n",
+			pdev->num_resources);
+		return -ENODEV;
+	}
+
+	/* MBOX base */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid mem resource\n");
+		return -ENODEV;
+	}
+	mbox_base = res->start;
+
+	/* DSP IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid irq resource\n");
+		return -ENODEV;
+	}
+	mbox_dsp_info.irq = res->start;
+
+	ret = omap_mbox_register(&mbox_dsp_info);
+
+	/* IVA IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "invalid irq resource\n");
+		return -ENODEV;
+	}
+	mbox_iva_info.irq = res->start;
+
+	ret = omap_mbox_register(&mbox_iva_info);
+
+	return ret;
+}
+
+static int omap2_mbox_remove(struct platform_device *pdev)
+{
+	omap_mbox_unregister(&mbox_dsp_info);
+	return 0;
+}
+
+static struct platform_driver omap2_mbox_driver = {
+	.probe = omap2_mbox_probe,
+	.remove = omap2_mbox_remove,
+	.driver = {
+		.name = "mailbox",
+	},
+};
+
+static int __init omap2_mbox_init(void)
+{
+	return platform_driver_register(&omap2_mbox_driver);
+}
+
+static void __exit omap2_mbox_exit(void)
+{
+	platform_driver_unregister(&omap2_mbox_driver);
+}
+
+module_init(omap2_mbox_init);
+module_exit(omap2_mbox_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index 637aaba..d1eeed2 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
+/* linux/arch/arm/mach-s3c2410/sleep.S
  *
  * Copyright (c) 2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index e684e9b..b81391a 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -366,6 +366,19 @@
 	  enabled will not boot on processors with do not support these
 	  instructions.
 
+# ARMv7
+config CPU_V7
+	bool "Support ARM V7 processor"
+	depends on ARCH_INTEGRATOR
+	select CPU_32v6K
+	select CPU_32v7
+	select CPU_ABRT_EV7
+	select CPU_CACHE_V7
+	select CPU_CACHE_VIPT
+	select CPU_CP15_MMU
+	select CPU_COPY_V6 if MMU
+	select CPU_TLB_V6 if MMU
+
 # Figure out what processor architecture version we should be using.
 # This defines the compiler instruction set which depends on the machine type.
 config CPU_32v3
@@ -391,6 +404,9 @@
 config CPU_32v6
 	bool
 
+config CPU_32v7
+	bool
+
 # The abort model
 config CPU_ABRT_NOMMU
 	bool
@@ -413,6 +429,9 @@
 config CPU_ABRT_EV6
 	bool
 
+config CPU_ABRT_EV7
+	bool
+
 # The cache model
 config CPU_CACHE_V3
 	bool
@@ -429,6 +448,9 @@
 config CPU_CACHE_V6
 	bool
 
+config CPU_CACHE_V7
+	bool
+
 config CPU_CACHE_VIVT
 	bool
 
@@ -503,7 +525,7 @@
 
 config ARM_THUMB
 	bool "Support Thumb user binaries"
-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6
+	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7
 	default y
 	help
 	  Say Y if you want to include kernel support for running user space
@@ -578,9 +600,15 @@
 	  Say Y here to use the predictable round-robin cache replacement
 	  policy.  Unless you specifically require this or are unsure, say N.
 
+config CPU_L2CACHE_DISABLE
+	bool "Disable level 2 cache"
+	depends on CPU_V7
+	help
+	  Say Y here to disable the level 2 cache.  If unsure, say N.
+
 config CPU_BPREDICT_DISABLE
 	bool "Disable branch prediction"
-	depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3
+	depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
 	help
 	  Say Y here to disable branch prediction.  If unsure, say N.
 
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 2f8b959..b5bd335 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -24,12 +24,14 @@
 obj-$(CONFIG_CPU_ABRT_EV5T)	+= abort-ev5t.o
 obj-$(CONFIG_CPU_ABRT_EV5TJ)	+= abort-ev5tj.o
 obj-$(CONFIG_CPU_ABRT_EV6)	+= abort-ev6.o
+obj-$(CONFIG_CPU_ABRT_EV7)	+= abort-ev7.o
 
 obj-$(CONFIG_CPU_CACHE_V3)	+= cache-v3.o
 obj-$(CONFIG_CPU_CACHE_V4)	+= cache-v4.o
 obj-$(CONFIG_CPU_CACHE_V4WT)	+= cache-v4wt.o
 obj-$(CONFIG_CPU_CACHE_V4WB)	+= cache-v4wb.o
 obj-$(CONFIG_CPU_CACHE_V6)	+= cache-v6.o
+obj-$(CONFIG_CPU_CACHE_V7)	+= cache-v7.o
 
 obj-$(CONFIG_CPU_COPY_V3)	+= copypage-v3.o
 obj-$(CONFIG_CPU_COPY_V4WT)	+= copypage-v4wt.o
@@ -66,5 +68,6 @@
 obj-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o
 obj-$(CONFIG_CPU_XSC3)		+= proc-xsc3.o
 obj-$(CONFIG_CPU_V6)		+= proc-v6.o
+obj-$(CONFIG_CPU_V7)		+= proc-v7.o
 
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S
new file mode 100644
index 0000000..eb90bce
--- /dev/null
+++ b/arch/arm/mm/abort-ev7.S
@@ -0,0 +1,32 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v7_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 11 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ */
+	.align	5
+ENTRY(v7_early_abort)
+	/*
+	 * The effect of data aborts on on the exclusive access monitor are
+	 * UNPREDICTABLE. Do a CLREX to clear the state
+	 */
+	clrex
+
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+
+	/*
+	 * V6 code adjusts the returned DFSR.
+	 * New designs should not need to patch up faults.
+	 */
+	mov	pc, lr
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
new file mode 100644
index 0000000..35ffc4d
--- /dev/null
+++ b/arch/arm/mm/cache-v7.S
@@ -0,0 +1,253 @@
+/*
+ *  linux/arch/arm/mm/cache-v7.S
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2005 ARM Ltd.
+ *
+ * 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 is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+#include "proc-macros.S"
+
+/*
+ *	v7_flush_dcache_all()
+ *
+ *	Flush the whole D-cache.
+ *
+ *	Corrupted registers: r0-r5, r7, r9-r11
+ *
+ *	- mm    - mm_struct describing address space
+ */
+ENTRY(v7_flush_dcache_all)
+	mrc	p15, 1, r0, c0, c0, 1		@ read clidr
+	ands	r3, r0, #0x7000000		@ extract loc from clidr
+	mov	r3, r3, lsr #23			@ left align loc bit field
+	beq	finished			@ if loc is 0, then no need to clean
+	mov	r10, #0				@ start clean at cache level 0
+loop1:
+	add	r2, r10, r10, lsr #1		@ work out 3x current cache level
+	mov	r1, r0, lsr r2			@ extract cache type bits from clidr
+	and	r1, r1, #7			@ mask of the bits for current cache only
+	cmp	r1, #2				@ see what cache we have at this level
+	blt	skip				@ skip if no cache, or just i-cache
+	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
+	isb					@ isb to sych the new cssr&csidr
+	mrc	p15, 1, r1, c0, c0, 0		@ read the new csidr
+	and	r2, r1, #7			@ extract the length of the cache lines
+	add	r2, r2, #4			@ add 4 (line length offset)
+	ldr	r4, =0x3ff
+	ands	r4, r4, r1, lsr #3		@ find maximum number on the way size
+	clz	r5, r4				@ find bit position of way size increment
+	ldr	r7, =0x7fff
+	ands	r7, r7, r1, lsr #13		@ extract max number of the index size
+loop2:
+	mov	r9, r4				@ create working copy of max way size
+loop3:
+	orr	r11, r10, r9, lsl r5		@ factor way and cache number into r11
+	orr	r11, r11, r7, lsl r2		@ factor index number into r11
+	mcr	p15, 0, r11, c7, c14, 2		@ clean & invalidate by set/way
+	subs	r9, r9, #1			@ decrement the way
+	bge	loop3
+	subs	r7, r7, #1			@ decrement the index
+	bge	loop2
+skip:
+	add	r10, r10, #2			@ increment cache number
+	cmp	r3, r10
+	bgt	loop1
+finished:
+	mov	r10, #0				@ swith back to cache level 0
+	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
+	isb
+	mov	pc, lr
+
+/*
+ *	v7_flush_cache_all()
+ *
+ *	Flush the entire cache system.
+ *  The data cache flush is now achieved using atomic clean / invalidates
+ *  working outwards from L1 cache. This is done using Set/Way based cache
+ *  maintainance instructions.
+ *  The instruction cache can still be invalidated back to the point of
+ *  unification in a single instruction.
+ *
+ */
+ENTRY(v7_flush_kern_cache_all)
+	stmfd	sp!, {r4-r5, r7, r9-r11, lr}
+	bl	v7_flush_dcache_all
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ I+BTB cache invalidate
+	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}
+	mov	pc, lr
+
+/*
+ *	v7_flush_cache_all()
+ *
+ *	Flush all TLB entries in a particular address space
+ *
+ *	- mm    - mm_struct describing address space
+ */
+ENTRY(v7_flush_user_cache_all)
+	/*FALLTHROUGH*/
+
+/*
+ *	v7_flush_cache_range(start, end, flags)
+ *
+ *	Flush a range of TLB entries in the specified address space.
+ *
+ *	- start - start address (may not be aligned)
+ *	- end   - end address (exclusive, may not be aligned)
+ *	- flags	- vm_area_struct flags describing address space
+ *
+ *	It is assumed that:
+ *	- we have a VIPT cache.
+ */
+ENTRY(v7_flush_user_cache_range)
+	mov	pc, lr
+
+/*
+ *	v7_coherent_kern_range(start,end)
+ *
+ *	Ensure that the I and D caches are coherent within specified
+ *	region.  This is typically used when code has been written to
+ *	a memory region, and will be executed.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ *
+ *	It is assumed that:
+ *	- the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_kern_range)
+	/* FALLTHROUGH */
+
+/*
+ *	v7_coherent_user_range(start,end)
+ *
+ *	Ensure that the I and D caches are coherent within specified
+ *	region.  This is typically used when code has been written to
+ *	a memory region, and will be executed.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ *
+ *	It is assumed that:
+ *	- the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_user_range)
+	dcache_line_size r2, r3
+	sub	r3, r2, #1
+	bic	r0, r0, r3
+1:	mcr	p15, 0, r0, c7, c11, 1		@ clean D line to the point of unification
+	dsb
+	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I line
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	1b
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 6		@ invalidate BTB
+	dsb
+	isb
+	mov	pc, lr
+
+/*
+ *	v7_flush_kern_dcache_page(kaddr)
+ *
+ *	Ensure that the data held in the page kaddr is written back
+ *	to the page in question.
+ *
+ *	- kaddr   - kernel address (guaranteed to be page aligned)
+ */
+ENTRY(v7_flush_kern_dcache_page)
+	dcache_line_size r2, r3
+	add	r1, r0, #PAGE_SZ
+1:
+	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D line / unified line
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	1b
+	dsb
+	mov	pc, lr
+
+/*
+ *	v7_dma_inv_range(start,end)
+ *
+ *	Invalidate the data cache within the specified region; we will
+ *	be performing a DMA operation in this region and we want to
+ *	purge old data in the cache.
+ *
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(v7_dma_inv_range)
+	dcache_line_size r2, r3
+	sub	r3, r2, #1
+	tst	r0, r3
+	bic	r0, r0, r3
+	mcrne	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
+
+	tst	r1, r3
+	bic	r1, r1, r3
+	mcrne	p15, 0, r1, c7, c14, 1		@ clean & invalidate D / U line
+1:
+	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D / U line
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	1b
+	dsb
+	mov	pc, lr
+
+/*
+ *	v7_dma_clean_range(start,end)
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(v7_dma_clean_range)
+	dcache_line_size r2, r3
+	sub	r3, r2, #1
+	bic	r0, r0, r3
+1:
+	mcr	p15, 0, r0, c7, c10, 1		@ clean D / U line
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	1b
+	dsb
+	mov	pc, lr
+
+/*
+ *	v7_dma_flush_range(start,end)
+ *	- start   - virtual start address of region
+ *	- end     - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range)
+	dcache_line_size r2, r3
+	sub	r3, r2, #1
+	bic	r0, r0, r3
+1:
+	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	1b
+	dsb
+	mov	pc, lr
+
+	__INITDATA
+
+	.type	v7_cache_fns, #object
+ENTRY(v7_cache_fns)
+	.long	v7_flush_kern_cache_all
+	.long	v7_flush_user_cache_all
+	.long	v7_flush_user_cache_range
+	.long	v7_coherent_kern_range
+	.long	v7_coherent_user_range
+	.long	v7_flush_kern_dcache_page
+	.long	v7_dma_inv_range
+	.long	v7_dma_clean_range
+	.long	v7_dma_flush_range
+	.size	v7_cache_fns, . - v7_cache_fns
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 9da43a0..fc84fcc 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -14,7 +14,8 @@
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
-unsigned int cpu_last_asid = { 1 << ASID_BITS };
+static DEFINE_SPINLOCK(cpu_asid_lock);
+unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 
 /*
  * We fork()ed a process, and we need a new context for the child
@@ -31,15 +32,16 @@
 {
 	unsigned int asid;
 
+	spin_lock(&cpu_asid_lock);
 	asid = ++cpu_last_asid;
 	if (asid == 0)
-		asid = cpu_last_asid = 1 << ASID_BITS;
+		asid = cpu_last_asid = ASID_FIRST_VERSION;
 
 	/*
 	 * If we've used up all our ASIDs, we need
 	 * to start a new version and flush the TLB.
 	 */
-	if ((asid & ~ASID_MASK) == 0) {
+	if (unlikely((asid & ~ASID_MASK) == 0)) {
 		asid = ++cpu_last_asid;
 		/* set the reserved ASID before flushing the TLB */
 		asm("mcr	p15, 0, %0, c13, c0, 1	@ set reserved context ID\n"
@@ -47,7 +49,16 @@
 		    : "r" (0));
 		isb();
 		flush_tlb_all();
+		if (icache_is_vivt_asid_tagged()) {
+			asm("mcr	p15, 0, %0, c7, c5, 0	@ invalidate I-cache\n"
+			    "mcr	p15, 0, %0, c7, c5, 6	@ flush BTAC/BTB\n"
+			    :
+			    : "r" (0));
+			dsb();
+		}
 	}
+	spin_unlock(&cpu_asid_lock);
 
+	mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
 	mm->context.id = asid;
 }
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 9e2c89e..b131500 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -59,3 +59,15 @@
 	.word	\ucset
 #endif
 	.endm
+
+/*
+ * cache_line_size - get the cache line size from the CSIDR register
+ * (available on ARMv7+). It assumes that the CSSR register was configured
+ * to access the L1 data cache CSIDR.
+ */
+	.macro	dcache_line_size, reg, tmp
+	mrc	p15, 1, \tmp, c0, c0, 0		@ read CSIDR
+	and	\tmp, \tmp, #7			@ cache line size encoding
+	mov	\reg, #16			@ size offset
+	mov	\reg, \reg, lsl \tmp		@ actual cache line size
+	.endm
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
new file mode 100644
index 0000000..dd823dd
--- /dev/null
+++ b/arch/arm/mm/proc-v7.S
@@ -0,0 +1,262 @@
+/*
+ *  linux/arch/arm/mm/proc-v7.S
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * 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 is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/elf.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+
+#include "proc-macros.S"
+
+#define TTB_C		(1 << 0)
+#define TTB_S		(1 << 1)
+#define TTB_RGN_OC_WT	(2 << 3)
+#define TTB_RGN_OC_WB	(3 << 3)
+
+ENTRY(cpu_v7_proc_init)
+	mov	pc, lr
+
+ENTRY(cpu_v7_proc_fin)
+	mov	pc, lr
+
+/*
+ *	cpu_v7_reset(loc)
+ *
+ *	Perform a soft reset of the system.  Put the CPU into the
+ *	same state as it would be if it had been reset, and branch
+ *	to what would be the reset vector.
+ *
+ *	- loc   - location to jump to for soft reset
+ *
+ *	It is assumed that:
+ */
+	.align	5
+ENTRY(cpu_v7_reset)
+	mov	pc, r0
+
+/*
+ *	cpu_v7_do_idle()
+ *
+ *	Idle the processor (eg, wait for interrupt).
+ *
+ *	IRQs are already disabled.
+ */
+ENTRY(cpu_v7_do_idle)
+	.long	0xe320f003			@ ARM V7 WFI instruction
+	mov	pc, lr
+
+ENTRY(cpu_v7_dcache_clean_area)
+#ifndef TLB_CAN_READ_FROM_L1_CACHE
+	dcache_line_size r2, r3
+1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+	add	r0, r0, r2
+	subs	r1, r1, r2
+	bhi	1b
+	dsb
+#endif
+	mov	pc, lr
+
+/*
+ *	cpu_v7_switch_mm(pgd_phys, tsk)
+ *
+ *	Set the translation table base pointer to be pgd_phys
+ *
+ *	- pgd_phys - physical address of new TTB
+ *
+ *	It is assumed that:
+ *	- we are not using split page tables
+ */
+ENTRY(cpu_v7_switch_mm)
+	mov	r2, #0
+	ldr	r1, [r1, #MM_CONTEXT_ID]	@ get mm->context.id
+	orr	r0, r0, #TTB_RGN_OC_WB		@ mark PTWs outer cacheable, WB
+	mcr	p15, 0, r2, c13, c0, 1		@ set reserved context ID
+	isb
+1:	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
+	isb
+	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
+	isb
+	mov	pc, lr
+
+/*
+ *	cpu_v7_set_pte_ext(ptep, pte)
+ *
+ *	Set a level 2 translation table entry.
+ *
+ *	- ptep  - pointer to level 2 translation table entry
+ *		  (hardware version is stored at -1024 bytes)
+ *	- pte   - PTE value to store
+ *	- ext	- value for extended PTE bits
+ *
+ *	Permissions:
+ *	  YUWD  APX AP1 AP0	SVC	User
+ *	  0xxx   0   0   0	no acc	no acc
+ *	  100x   1   0   1	r/o	no acc
+ *	  10x0   1   0   1	r/o	no acc
+ *	  1011   0   0   1	r/w	no acc
+ *	  110x   0   1   0	r/w	r/o
+ *	  11x0   0   1   0	r/w	r/o
+ *	  1111   0   1   1	r/w	r/w
+ */
+ENTRY(cpu_v7_set_pte_ext)
+	str	r1, [r0], #-2048		@ linux version
+
+	bic	r3, r1, #0x000003f0
+	bic	r3, r3, #0x00000003
+	orr	r3, r3, r2
+	orr	r3, r3, #PTE_EXT_AP0 | 2
+
+	tst	r1, #L_PTE_WRITE
+	tstne	r1, #L_PTE_DIRTY
+	orreq	r3, r3, #PTE_EXT_APX
+
+	tst	r1, #L_PTE_USER
+	orrne	r3, r3, #PTE_EXT_AP1
+	tstne	r3, #PTE_EXT_APX
+	bicne	r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
+
+	tst	r1, #L_PTE_YOUNG
+	biceq	r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
+
+	tst	r1, #L_PTE_EXEC
+	orreq	r3, r3, #PTE_EXT_XN
+
+	tst	r1, #L_PTE_PRESENT
+	moveq	r3, #0
+
+	str	r3, [r0]
+	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
+	mov	pc, lr
+
+cpu_v7_name:
+	.ascii	"ARMv7 Processor"
+	.align
+
+	.section ".text.init", #alloc, #execinstr
+
+/*
+ *	__v7_setup
+ *
+ *	Initialise TLB, Caches, and MMU state ready to switch the MMU
+ *	on.  Return in r0 the new CP15 C1 control register setting.
+ *
+ *	We automatically detect if we have a Harvard cache, and use the
+ *	Harvard cache control instructions insead of the unified cache
+ *	control instructions.
+ *
+ *	This should be able to cover all ARMv7 cores.
+ *
+ *	It is assumed that:
+ *	- cache type register is implemented
+ */
+__v7_setup:
+	adr	r12, __v7_setup_stack		@ the local stack
+	stmia	r12, {r0-r5, r7, r9, r11, lr}
+	bl	v7_flush_dcache_all
+	ldmia	r12, {r0-r5, r7, r9, r11, lr}
+	mov	r10, #0
+#ifdef HARVARD_CACHE
+	mcr	p15, 0, r10, c7, c5, 0		@ I+BTB cache invalidate
+#endif
+	dsb
+	mcr	p15, 0, r10, c8, c7, 0		@ invalidate I + D TLBs
+	mcr	p15, 0, r10, c2, c0, 2		@ TTB control register
+	orr	r4, r4, #TTB_RGN_OC_WB		@ mark PTWs outer cacheable, WB
+	mcr	p15, 0, r4, c2, c0, 0		@ load TTB0
+	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
+	mov	r10, #0x1f			@ domains 0, 1 = manager
+	mcr	p15, 0, r10, c3, c0, 0		@ load domain access register
+#ifndef CONFIG_CPU_L2CACHE_DISABLE
+	@ L2 cache configuration in the L2 aux control register
+	mrc	p15, 1, r10, c9, c0, 2
+	bic	r10, r10, #(1 << 16)		@ L2 outer cache
+	mcr	p15, 1, r10, c9, c0, 2
+	@ L2 cache is enabled in the aux control register
+	mrc	p15, 0, r10, c1, c0, 1
+	orr	r10, r10, #2
+	mcr	p15, 0, r10, c1, c0, 1
+#endif
+	mrc	p15, 0, r0, c1, c0, 0		@ read control register
+	ldr	r10, cr1_clear			@ get mask for bits to clear
+	bic	r0, r0, r10			@ clear bits them
+	ldr	r10, cr1_set			@ get mask for bits to set
+	orr	r0, r0, r10			@ set them
+	mov	pc, lr				@ return to head.S:__ret
+
+	/*
+	 *         V X F   I D LR
+	 * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
+	 * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
+	 *         0 110       0011 1.00 .111 1101 < we want
+	 */
+	.type	cr1_clear, #object
+	.type	cr1_set, #object
+cr1_clear:
+	.word	0x0120c302
+cr1_set:
+	.word	0x00c0387d
+
+__v7_setup_stack:
+	.space	4 * 11				@ 11 registers
+
+	.type	v7_processor_functions, #object
+ENTRY(v7_processor_functions)
+	.word	v7_early_abort
+	.word	cpu_v7_proc_init
+	.word	cpu_v7_proc_fin
+	.word	cpu_v7_reset
+	.word	cpu_v7_do_idle
+	.word	cpu_v7_dcache_clean_area
+	.word	cpu_v7_switch_mm
+	.word	cpu_v7_set_pte_ext
+	.size	v7_processor_functions, . - v7_processor_functions
+
+	.type	cpu_arch_name, #object
+cpu_arch_name:
+	.asciz	"armv7"
+	.size	cpu_arch_name, . - cpu_arch_name
+
+	.type	cpu_elf_name, #object
+cpu_elf_name:
+	.asciz	"v7"
+	.size	cpu_elf_name, . - cpu_elf_name
+	.align
+
+	.section ".proc.info.init", #alloc, #execinstr
+
+	/*
+	 * Match any ARMv7 processor core.
+	 */
+	.type	__v7_proc_info, #object
+__v7_proc_info:
+	.long	0x000f0000		@ Required ID value
+	.long	0x000f0000		@ Mask for ID
+	.long   PMD_TYPE_SECT | \
+		PMD_SECT_BUFFERABLE | \
+		PMD_SECT_CACHEABLE | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ
+	.long   PMD_TYPE_SECT | \
+		PMD_SECT_XN | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ
+	b	__v7_setup
+	.long	cpu_arch_name
+	.long	cpu_elf_name
+	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+	.long	cpu_v7_name
+	.long	v7_processor_functions
+	.long	v6wbi_tlb_fns
+	.long	v6_user_fns
+	.long	v7_cache_fns
+	.size	__v7_proc_info, . - __v7_proc_info
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 9e8d21e..cfc69f3 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -20,6 +20,11 @@
 
 comment "OMAP Feature Selections"
 
+config OMAP_DEBUG_LEDS
+	bool
+	help
+	  For debug card leds on TI reference boards.
+
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
 	depends on ARCH_OMAP
@@ -58,6 +63,14 @@
 	  to change the pin multiplexing setup.  When there are no warnings
 	  printed, it's safe to deselect OMAP_MUX for your product.
 
+config OMAP_MCBSP
+	bool "McBSP support"
+	depends on ARCH_OMAP
+	default y
+	help
+	  Say Y here if you want support for the OMAP Multichannel
+	  Buffered Serial Port.
+
 choice
         prompt "System timer"
 	default OMAP_MPU_TIMER
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 2896b45..41a3c1c 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,7 +3,8 @@
 #
 
 # Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o \
+	 usb.o fb.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -16,4 +17,4 @@
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
-
+obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index f1179ad..0a60324 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -33,6 +33,41 @@
 
 static struct clk_functions *arch_clock;
 
+#ifdef CONFIG_PM_DEBUG
+
+static void print_parents(struct clk *clk)
+{
+	struct clk *p;
+	int printed = 0;
+
+	list_for_each_entry(p, &clocks, node) {
+		if (p->parent == clk && p->usecount) {
+			if (!clk->usecount && !printed) {
+				printk("MISMATCH: %s\n", clk->name);
+				printed = 1;
+			}
+			printk("\t%-15s\n", p->name);
+		}
+	}
+}
+
+void clk_print_usecounts(void)
+{
+	unsigned long flags;
+	struct clk *p;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	list_for_each_entry(p, &clocks, node) {
+		if (p->usecount)
+			printk("%-15s: %d\n", p->name, p->usecount);
+		print_parents(p);
+
+	}
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+
+#endif
+
 /*-------------------------------------------------------------------------
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
@@ -249,6 +284,8 @@
 		return;
 
 	clk->rate = clk->parent->rate;
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
 }
 
 /* Propagate rate to children */
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index fecd3d6..dd8708a 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -93,8 +93,12 @@
 	 * in the kernel. */
 	for (i = 0; i < omap_board_config_size; i++) {
 		if (omap_board_config[i].tag == tag) {
-			kinfo = &omap_board_config[i];
-			break;
+			if (skip == 0) {
+				kinfo = &omap_board_config[i];
+				break;
+			} else {
+				skip--;
+			}
 		}
 	}
 	if (kinfo == NULL)
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
new file mode 100644
index 0000000..9128a80
--- /dev/null
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -0,0 +1,314 @@
+/*
+ * linux/arch/arm/plat-omap/debug-leds.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+
+/* Many OMAP development platforms reuse the same "debug board"; these
+ * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
+ * debug board (all green), accessed through FPGA registers.
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators
+ * in preference to the ones on the debug board, for a "Disco LED" effect.
+ *
+ * This driver exports either the original ARM LED API, the new generic
+ * one, or both.
+ */
+
+static spinlock_t			lock;
+static struct h2p2_dbg_fpga __iomem	*fpga;
+static u16				led_state, hw_led_state;
+
+
+#ifdef	CONFIG_LEDS_OMAP_DEBUG
+#define new_led_api()	1
+#else
+#define new_led_api()	0
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/* original ARM debug LED API:
+ *  - timer and idle leds (some boards use non-FPGA leds here);
+ *  - up to 4 generic leds, easily accessed in-kernel (any context)
+ */
+
+#define GPIO_LED_RED		3
+#define GPIO_LED_GREEN		OMAP_MPUIO(4)
+
+#define LED_STATE_ENABLED	0x01
+#define LED_STATE_CLAIMED	0x02
+#define LED_TIMER_ON		0x04
+
+#define GPIO_IDLE		GPIO_LED_GREEN
+#define GPIO_TIMER		GPIO_LED_RED
+
+static void h2p2_dbg_leds_event(led_event_t evt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&lock, flags);
+
+	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+		goto done;
+
+	switch (evt) {
+	case led_start:
+		if (fpga)
+			led_state |= LED_STATE_ENABLED;
+		break;
+
+	case led_stop:
+	case led_halted:
+		/* all leds off during suspend or shutdown */
+
+		if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
+			omap_set_gpio_dataout(GPIO_TIMER, 0);
+			omap_set_gpio_dataout(GPIO_IDLE, 0);
+		}
+
+		__raw_writew(~0, &fpga->leds);
+		led_state &= ~LED_STATE_ENABLED;
+		goto done;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		break;
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		led_state ^= LED_TIMER_ON;
+
+		if (machine_is_omap_perseus2() || machine_is_omap_h4())
+			hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
+		else {
+			omap_set_gpio_dataout(GPIO_TIMER,
+					led_state & LED_TIMER_ON);
+			goto done;
+		}
+
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	/* LED lit iff busy */
+	case led_idle_start:
+		if (machine_is_omap_perseus2() || machine_is_omap_h4())
+			hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
+		else {
+			omap_set_gpio_dataout(GPIO_IDLE, 1);
+			goto done;
+		}
+
+		break;
+
+	case led_idle_end:
+		if (machine_is_omap_perseus2() || machine_is_omap_h4())
+			hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
+		else {
+			omap_set_gpio_dataout(GPIO_IDLE, 0);
+			goto done;
+		}
+
+		break;
+#endif
+
+	case led_green_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
+		break;
+	case led_green_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
+		break;
+
+	case led_amber_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
+		break;
+	case led_amber_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
+		break;
+
+	case led_red_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
+		break;
+	case led_red_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+		break;
+
+	case led_blue_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+		break;
+	case led_blue_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
+		break;
+
+	default:
+		break;
+	}
+
+
+	/*
+	 *  Actually burn the LEDs
+	 */
+	if (led_state & LED_STATE_ENABLED)
+		__raw_writew(~hw_led_state, &fpga->leds);
+
+done:
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* "new" LED API
+ *  - with syfs access and generic triggering
+ *  - not readily accessible to in-kernel drivers
+ */
+
+struct dbg_led {
+	struct led_classdev	cdev;
+	u16			mask;
+};
+
+static struct dbg_led dbg_leds[] = {
+	/* REVISIT at least H2 uses different timer & cpu leds... */
+#ifndef CONFIG_LEDS_TIMER
+	{ .mask = 1 << 0,  .cdev.name =  "d4:green",
+		.cdev.default_trigger = "heartbeat", },
+#endif
+#ifndef CONFIG_LEDS_CPU
+	{ .mask = 1 << 1,  .cdev.name =  "d5:green", },		/* !idle */
+#endif
+	{ .mask = 1 << 2,  .cdev.name =  "d6:green", },
+	{ .mask = 1 << 3,  .cdev.name =  "d7:green", },
+
+	{ .mask = 1 << 4,  .cdev.name =  "d8:green", },
+	{ .mask = 1 << 5,  .cdev.name =  "d9:green", },
+	{ .mask = 1 << 6,  .cdev.name = "d10:green", },
+	{ .mask = 1 << 7,  .cdev.name = "d11:green", },
+
+	{ .mask = 1 << 8,  .cdev.name = "d12:green", },
+	{ .mask = 1 << 9,  .cdev.name = "d13:green", },
+	{ .mask = 1 << 10, .cdev.name = "d14:green", },
+	{ .mask = 1 << 11, .cdev.name = "d15:green", },
+
+#ifndef	CONFIG_LEDS
+	{ .mask = 1 << 12, .cdev.name = "d16:green", },
+	{ .mask = 1 << 13, .cdev.name = "d17:green", },
+	{ .mask = 1 << 14, .cdev.name = "d18:green", },
+	{ .mask = 1 << 15, .cdev.name = "d19:green", },
+#endif
+};
+
+static void
+fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+	struct dbg_led	*led = container_of(cdev, struct dbg_led, cdev);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&lock, flags);
+	if (value == LED_OFF)
+		hw_led_state &= ~led->mask;
+	else
+		hw_led_state |= led->mask;
+	__raw_writew(~hw_led_state, &fpga->leds);
+	spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __init newled_init(struct device *dev)
+{
+	unsigned	i;
+	struct dbg_led	*led;
+	int		status;
+
+	for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
+		led->cdev.brightness_set = fpga_led_set;
+		status = led_classdev_register(dev, &led->cdev);
+		if (status < 0)
+			break;
+	}
+	return;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int /* __init */ fpga_probe(struct platform_device *pdev)
+{
+	struct resource	*iomem;
+
+	spin_lock_init(&lock);
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem)
+		return -ENODEV;
+
+	fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
+	__raw_writew(~0, &fpga->leds);
+
+#ifdef	CONFIG_LEDS
+	leds_event = h2p2_dbg_leds_event;
+	leds_event(led_start);
+#endif
+
+	if (new_led_api()) {
+		newled_init(&pdev->dev);
+	}
+
+	return 0;
+}
+
+static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+	__raw_writew(~0, &fpga->leds);
+	return 0;
+}
+
+static int fpga_resume_early(struct platform_device *pdev)
+{
+	__raw_writew(~hw_led_state, &fpga->leds);
+	return 0;
+}
+
+
+static struct platform_driver led_driver = {
+	.driver.name	= "omap_dbg_led",
+	.probe		= fpga_probe,
+	.suspend_late	= fpga_suspend_late,
+	.resume_early	= fpga_resume_early,
+};
+
+static int __init fpga_init(void)
+{
+	if (machine_is_omap_h4()
+			|| machine_is_omap_h3()
+			|| machine_is_omap_h2()
+			|| machine_is_omap_perseus2()
+			)
+		return platform_driver_register(&led_driver);
+	return 0;
+}
+fs_initcall(fpga_init);
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index eeb33fe..c5dab1d 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -25,7 +25,71 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/menelaus.h>
 
-#if 	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if	defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+static struct dsp_platform_data dsp_pdata = {
+	.kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
+};
+
+static struct resource omap_dsp_resources[] = {
+	{
+		.name	= "dsp_mmu",
+		.start	= -1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device omap_dsp_device = {
+	.name		= "dsp",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(omap_dsp_resources),
+	.resource	= omap_dsp_resources,
+	.dev = {
+		.platform_data = &dsp_pdata,
+	},
+};
+
+static inline void omap_init_dsp(void)
+{
+	struct resource *res;
+	int irq;
+
+	if (cpu_is_omap15xx())
+		irq = INT_1510_DSP_MMU;
+	else if (cpu_is_omap16xx())
+		irq = INT_1610_DSP_MMU;
+	else if (cpu_is_omap24xx())
+		irq = INT_24XX_DSP_MMU;
+
+	res = platform_get_resource_byname(&omap_dsp_device,
+					   IORESOURCE_IRQ, "dsp_mmu");
+	res->start = irq;
+
+	platform_device_register(&omap_dsp_device);
+}
+
+int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
+{
+	static DEFINE_MUTEX(dsp_pdata_lock);
+
+	mutex_init(&kdev->lock);
+
+	mutex_lock(&dsp_pdata_lock);
+	list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+	mutex_unlock(&dsp_pdata_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(dsp_kfunc_device_register);
+
+#else
+static inline void omap_init_dsp(void) { }
+#endif	/* CONFIG_OMAP_DSP */
+
+/*-------------------------------------------------------------------------*/
+#if	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define	OMAP1_I2C_BASE		0xfffb3800
 #define OMAP2_I2C_BASE1		0x48070000
@@ -48,8 +112,8 @@
 /* DMA not used; works around erratum writing to non-empty i2c fifo */
 
 static struct platform_device omap_i2c_device1 = {
-        .name           = "i2c_omap",
-        .id             = 1,
+	.name           = "i2c_omap",
+	.id             = 1,
 	.num_resources	= ARRAY_SIZE(i2c_resources1),
 	.resource	= i2c_resources1,
 };
@@ -376,7 +440,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#if	defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE)
+#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE)
 
 #ifdef CONFIG_ARCH_OMAP24XX
 #define	OMAP_RNG_BASE		0x480A0000
@@ -436,6 +500,7 @@
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
+	omap_init_dsp();
 	omap_init_i2c();
 	omap_init_kp();
 	omap_init_mmc();
@@ -446,4 +511,3 @@
 	return 0;
 }
 arch_initcall(omap_init_devices);
-
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index f3f84fb..2d86b10 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -925,10 +925,17 @@
 {
 	u32 status = OMAP_DMA_CSR_REG(ch);
 
-	if (!status)
+	if (!status) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n", ch);
 		return 0;
-	if (unlikely(dma_chan[ch].dev_id == -1))
+	}
+	if (unlikely(dma_chan[ch].dev_id == -1)) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING "IRQ %04x for non-allocated DMA"
+					"channel %d\n", status, ch);
 		return 0;
+	}
 	if (unlikely(status & OMAP_DMA_DROP_IRQ))
 		printk(KERN_INFO
 		       "DMA synchronization event drop occurred with device "
@@ -959,11 +966,15 @@
 	int i;
 
 	val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-
-	for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) {
-		int active = val & (1 << (i - 1));
-		if (active)
-			omap2_dma_handle_ch(i - 1);
+	if (val == 0) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING "Spurious DMA IRQ\n");
+		return IRQ_HANDLED;
+	}
+	for (i = 0; i < OMAP_LOGICAL_DMA_CH_COUNT && val != 0; i++) {
+		if (val & 1)
+			omap2_dma_handle_ch(i);
+		val >>= 1;
 	}
 
 	return IRQ_HANDLED;
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 659619f..36073df 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -372,7 +372,7 @@
 
 	/* When the functional clock disappears, too quick writes seem to
 	 * cause an abort. */
-	__delay(15000);
+	__delay(150000);
 }
 
 #endif
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 56acb87..4493bcf 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -1,3 +1,26 @@
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -16,6 +39,8 @@
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
 static struct omapfb_platform_data omapfb_config;
+static int config_invalid;
+static int configured_regions;
 
 static u64 omap_fb_dma_mask = ~(u32)0;
 
@@ -30,39 +55,270 @@
 	.num_resources = 0,
 };
 
-/* called from map_io */
-void omapfb_reserve_mem(void)
+static inline int ranges_overlap(unsigned long start1, unsigned long size1,
+				 unsigned long start2, unsigned long size2)
 {
-	const struct omap_fbmem_config *fbmem_conf;
+	return (start1 >= start2 && start1 < start2 + size2) ||
+	       (start2 >= start1 && start2 < start1 + size1);
+}
 
-	omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
-	omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+static inline int range_included(unsigned long start1, unsigned long size1,
+				 unsigned long start2, unsigned long size2)
+{
+	return start1 >= start2 && start1 + size1 <= start2 + size2;
+}
 
-	fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
 
-	if (fbmem_conf != NULL) {
-		/* indicate that the bootloader already initialized the
-		 * fb device, so we'll skip that part in the fb driver
-		 */
-		omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
-		omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
-		if (fbmem_conf->fb_sdram_size) {
-			pr_info("Reserving %u bytes SDRAM for frame buffer\n",
-				fbmem_conf->fb_sdram_size);
-			reserve_bootmem(fbmem_conf->fb_sdram_start,
-					fbmem_conf->fb_sdram_size);
-		}
+/* Check if there is an overlapping region. */
+static int fbmem_region_reserved(unsigned long start, size_t size)
+{
+	struct omapfb_mem_region *rg;
+	int i;
+
+	rg = &omapfb_config.mem_desc.region[0];
+	for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) {
+		if (!rg->paddr)
+			/* Empty slot. */
+			continue;
+		if (ranges_overlap(start, size, rg->paddr, rg->size))
+			return 1;
 	}
+	return 0;
+}
+
+/*
+ * Get the region_idx`th region from board config/ATAG and convert it to
+ * our internal format.
+ */
+static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+{
+	const struct omap_fbmem_config	*conf;
+	u32				paddr;
+
+	conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+				  struct omap_fbmem_config, region_idx);
+	if (conf == NULL)
+		return -ENOENT;
+
+	paddr = conf->start;
+	/*
+	 * Low bits encode the page allocation mode, if high bits
+	 * are zero. Otherwise we need a page aligned fixed
+	 * address.
+	 */
+	memset(rg, 0, sizeof(*rg));
+	rg->type = paddr & ~PAGE_MASK;
+	rg->paddr = paddr & PAGE_MASK;
+	rg->size = PAGE_ALIGN(conf->size);
+	return 0;
+}
+
+static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
+				  unsigned long mem_start,
+				  unsigned long mem_size)
+{
+	/*
+	 * Check if the configuration specifies the type explicitly.
+	 * type = 0 && paddr = 0, a default don't care case maps to
+	 * the SDRAM type.
+	 */
+	if (rg->type || (!rg->type && !rg->paddr))
+		return 0;
+	if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
+		rg->type = mem_type;
+		return 0;
+	}
+	/* Can't determine it. */
+	return -1;
+}
+
+static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
+			      unsigned long start_avail, unsigned size_avail)
+{
+	unsigned long	paddr = rg->paddr;
+	size_t		size = rg->size;
+
+	if (rg->type > OMAPFB_MEMTYPE_MAX) {
+		printk(KERN_ERR
+			"Invalid start address for FB region %d\n", region_idx);
+		return -EINVAL;
+	}
+
+	if (!rg->size) {
+		printk(KERN_ERR "Zero size for FB region %d\n", region_idx);
+		return -EINVAL;
+	}
+
+	if (!paddr)
+		/* Allocate this dynamically, leave paddr 0 for now. */
+		return 0;
+
+	/*
+	 * Fixed region for the given RAM range. Check if it's already
+	 * reserved by the FB code or someone else.
+	 */
+	if (fbmem_region_reserved(paddr, size) ||
+	    !range_included(paddr, size, start_avail, size_avail)) {
+		printk(KERN_ERR "Trying to use reserved memory "
+			"for FB region %d\n", region_idx);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Called from map_io. We need to call to this early enough so that we
+ * can reserve the fixed SDRAM regions before VM could get hold of them.
+ */
+void omapfb_reserve_sdram(void)
+{
+	struct bootmem_data	*bdata;
+	unsigned long		sdram_start, sdram_size;
+	unsigned long		reserved;
+	int			i;
+
+	if (config_invalid)
+		return;
+
+	bdata = NODE_DATA(0)->bdata;
+	sdram_start = bdata->node_boot_start;
+	sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
+	reserved = 0;
+	for (i = 0; ; i++) {
+		struct omapfb_mem_region	rg;
+
+		if (get_fbmem_region(i, &rg) < 0)
+			break;
+		if (i == OMAPFB_PLANE_NUM) {
+			printk(KERN_ERR
+				"Extraneous FB mem configuration entries\n");
+			config_invalid = 1;
+			return;
+		}
+		/* Check if it's our memory type. */
+		if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM,
+				          sdram_start, sdram_size) < 0 ||
+		    (rg.type != OMAPFB_MEMTYPE_SDRAM))
+			continue;
+		BUG_ON(omapfb_config.mem_desc.region[i].size);
+		if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) {
+			config_invalid = 1;
+			return;
+		}
+		if (rg.paddr)
+			reserve_bootmem(rg.paddr, rg.size);
+		reserved += rg.size;
+		omapfb_config.mem_desc.region[i] = rg;
+		configured_regions++;
+	}
+	omapfb_config.mem_desc.region_cnt = i;
+	if (reserved)
+		pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
+			 reserved);
+}
+
+/*
+ * Called at sram init time, before anything is pushed to the SRAM stack.
+ * Because of the stack scheme, we will allocate everything from the
+ * start of the lowest address region to the end of SRAM. This will also
+ * include padding for page alignment and possible holes between regions.
+ *
+ * As opposed to the SDRAM case, we'll also do any dynamic allocations at
+ * this point, since the driver built as a module would have problem with
+ * freeing / reallocating the regions.
+ */
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+				  unsigned long sram_vstart,
+				  unsigned long sram_size,
+				  unsigned long pstart_avail,
+				  unsigned long size_avail)
+{
+	struct omapfb_mem_region	rg;
+	unsigned long			pend_avail;
+	unsigned long			reserved;
+	int				i;
+
+	if (config_invalid)
+		return 0;
+
+	reserved = 0;
+	pend_avail = pstart_avail + size_avail;
+	for (i = 0; ; i++) {
+		if (get_fbmem_region(i, &rg) < 0)
+			break;
+		if (i == OMAPFB_PLANE_NUM) {
+			printk(KERN_ERR
+				"Extraneous FB mem configuration entries\n");
+			config_invalid = 1;
+			return 0;
+		}
+
+		/* Check if it's our memory type. */
+		if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM,
+				          sram_pstart, sram_size) < 0 ||
+		    (rg.type != OMAPFB_MEMTYPE_SRAM))
+			continue;
+		BUG_ON(omapfb_config.mem_desc.region[i].size);
+
+		if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) {
+			config_invalid = 1;
+			return 0;
+		}
+
+		if (!rg.paddr) {
+			/* Dynamic allocation */
+			if ((size_avail & PAGE_MASK) < rg.size) {
+				printk("Not enough SRAM for FB region %d\n",
+					i);
+				config_invalid = 1;
+				return 0;
+			}
+			size_avail = (size_avail - rg.size) & PAGE_MASK;
+			rg.paddr = pstart_avail + size_avail;
+		}
+		/* Reserve everything above the start of the region. */
+		if (pend_avail - rg.paddr > reserved)
+			reserved = pend_avail - rg.paddr;
+		size_avail = pend_avail - reserved - pstart_avail;
+
+		/*
+		 * We have a kernel mapping for this already, so the
+		 * driver won't have to make one.
+		 */
+		rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart);
+		omapfb_config.mem_desc.region[i] = rg;
+		configured_regions++;
+	}
+	omapfb_config.mem_desc.region_cnt = i;
+	if (reserved)
+		pr_info("Reserving %lu bytes SRAM for frame buffer\n",
+			 reserved);
+	return reserved;
+}
+
+void omapfb_set_ctrl_platform_data(void *data)
+{
+	omapfb_config.ctrl_platform_data = data;
 }
 
 static inline int omap_init_fb(void)
 {
 	const struct omap_lcd_config *conf;
 
-	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
-	if (conf == NULL)
+	if (config_invalid)
 		return 0;
-
+	if (configured_regions != omapfb_config.mem_desc.region_cnt) {
+		printk(KERN_ERR "Invalid FB mem configuration entries\n");
+		return 0;
+	}
+	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+	if (conf == NULL) {
+		if (configured_regions)
+			/* FB mem config, but no LCD config? */
+			printk(KERN_ERR "Missing LCD configuration\n");
+		return 0;
+	}
 	omapfb_config.lcd = *conf;
 
 	return platform_device_register(&omap_fb_device);
@@ -72,7 +328,16 @@
 
 #else
 
-void omapfb_reserve_mem(void) {}
+void omapfb_reserve_sdram(void) {}
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+				  unsigned long sram_vstart,
+				  unsigned long sram_size,
+				  unsigned long start_avail,
+				  unsigned long size_avail)
+{
+	return 0;
+}
+
 
 #endif
 
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 9dc6d36..337455d 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/sysdev.h>
 #include <linux/err.h>
@@ -1545,7 +1544,7 @@
  * This may get called early from board specific init
  * for boards that have interrupts routed via FPGA.
  */
-int omap_gpio_init(void)
+int __init omap_gpio_init(void)
 {
 	if (!initialized)
 		return _omap_gpio_init();
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
new file mode 100644
index 0000000..de7e6ef
--- /dev/null
+++ b/arch/arm/plat-omap/mailbox.c
@@ -0,0 +1,509 @@
+/*
+ * OMAP mailbox driver
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *		Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.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 License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/blkdev.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include "mailbox.h"
+
+static struct omap_mbox *mboxes;
+static DEFINE_RWLOCK(mboxes_lock);
+
+/* Mailbox Sequence Bit function */
+void omap_mbox_init_seq(struct omap_mbox *mbox)
+{
+	mbox_seq_init(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_init_seq);
+
+/*
+ * message sender
+ */
+static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
+{
+	int ret = 0, i = 1000;
+
+	while (mbox_fifo_full(mbox)) {
+		if (mbox->ops->type == OMAP_MBOX_TYPE2)
+			return -1;
+		if (--i == 0)
+			return -1;
+		udelay(1);
+	}
+
+	if (arg && mbox->txq->callback) {
+		ret = mbox->txq->callback(arg);
+		if (ret)
+			goto out;
+	}
+
+	mbox_seq_toggle(mbox, &msg);
+	mbox_fifo_write(mbox, msg);
+ out:
+	return ret;
+}
+
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
+{
+	struct request *rq;
+	struct request_queue *q = mbox->txq->queue;
+	int ret = 0;
+
+	rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+	if (unlikely(!rq)) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	rq->data = (void *)msg;
+	blk_insert_request(q, rq, 0, arg);
+
+	schedule_work(&mbox->txq->work);
+ fail:
+	return ret;
+}
+EXPORT_SYMBOL(omap_mbox_msg_send);
+
+static void mbox_tx_work(struct work_struct *work)
+{
+	int ret;
+	struct request *rq;
+	struct omap_mbox_queue *mq = container_of(work,
+				struct omap_mbox_queue, work);
+	struct omap_mbox *mbox = mq->queue->queuedata;
+	struct request_queue *q = mbox->txq->queue;
+
+	while (1) {
+		spin_lock(q->queue_lock);
+		rq = elv_next_request(q);
+		spin_unlock(q->queue_lock);
+
+		if (!rq)
+			break;
+
+		ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special);
+		if (ret) {
+			enable_mbox_irq(mbox, IRQ_TX);
+			return;
+		}
+
+		spin_lock(q->queue_lock);
+		blkdev_dequeue_request(rq);
+		end_that_request_last(rq, 0);
+		spin_unlock(q->queue_lock);
+	}
+}
+
+/*
+ * Message receiver(workqueue)
+ */
+static void mbox_rx_work(struct work_struct *work)
+{
+	struct omap_mbox_queue *mq =
+			container_of(work, struct omap_mbox_queue, work);
+	struct omap_mbox *mbox = mq->queue->queuedata;
+	struct request_queue *q = mbox->rxq->queue;
+	struct request *rq;
+	mbox_msg_t msg;
+	unsigned long flags;
+
+	if (mbox->rxq->callback == NULL) {
+		sysfs_notify(&mbox->dev.kobj, NULL, "mbox");
+		return;
+	}
+
+	while (1) {
+		spin_lock_irqsave(q->queue_lock, flags);
+		rq = elv_next_request(q);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+		if (!rq)
+			break;
+
+		msg = (mbox_msg_t) rq->data;
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		blkdev_dequeue_request(rq);
+		end_that_request_last(rq, 0);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+
+		mbox->rxq->callback((void *)msg);
+	}
+}
+
+/*
+ * Mailbox interrupt handler
+ */
+static void mbox_txq_fn(request_queue_t * q)
+{
+}
+
+static void mbox_rxq_fn(request_queue_t * q)
+{
+}
+
+static void __mbox_tx_interrupt(struct omap_mbox *mbox)
+{
+	disable_mbox_irq(mbox, IRQ_TX);
+	ack_mbox_irq(mbox, IRQ_TX);
+	schedule_work(&mbox->txq->work);
+}
+
+static void __mbox_rx_interrupt(struct omap_mbox *mbox)
+{
+	struct request *rq;
+	mbox_msg_t msg;
+	request_queue_t *q = mbox->rxq->queue;
+
+	disable_mbox_irq(mbox, IRQ_RX);
+
+	while (!mbox_fifo_empty(mbox)) {
+		rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+		if (unlikely(!rq))
+			goto nomem;
+
+		msg = mbox_fifo_read(mbox);
+		rq->data = (void *)msg;
+
+		if (unlikely(mbox_seq_test(mbox, msg))) {
+			pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
+			if (mbox->err_notify)
+				mbox->err_notify();
+		}
+
+		blk_insert_request(q, rq, 0, NULL);
+		if (mbox->ops->type == OMAP_MBOX_TYPE1)
+			break;
+	}
+
+	/* no more messages in the fifo. clear IRQ source. */
+	ack_mbox_irq(mbox, IRQ_RX);
+	enable_mbox_irq(mbox, IRQ_RX);
+	nomem:
+	schedule_work(&mbox->rxq->work);
+}
+
+static irqreturn_t mbox_interrupt(int irq, void *p)
+{
+	struct omap_mbox *mbox = (struct omap_mbox *)p;
+
+	if (is_mbox_irq(mbox, IRQ_TX))
+		__mbox_tx_interrupt(mbox);
+
+	if (is_mbox_irq(mbox, IRQ_RX))
+		__mbox_rx_interrupt(mbox);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t
+omap_mbox_write(struct device *dev, struct device_attribute *attr,
+		const char * buf, size_t count)
+{
+	int ret;
+	mbox_msg_t *p = (mbox_msg_t *)buf;
+	struct omap_mbox *mbox = dev_get_drvdata(dev);
+
+	for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) {
+		ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL);
+		if (ret)
+			return -EAGAIN;
+		p++;
+	}
+
+	return (size_t)((char *)p - buf);
+}
+
+static ssize_t
+omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	unsigned long flags;
+	struct request *rq;
+	mbox_msg_t *p = (mbox_msg_t *) buf;
+	struct omap_mbox *mbox = dev_get_drvdata(dev);
+	struct request_queue *q = mbox->rxq->queue;
+
+	while (1) {
+		spin_lock_irqsave(q->queue_lock, flags);
+		rq = elv_next_request(q);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+
+		if (!rq)
+			break;
+
+		*p = (mbox_msg_t) rq->data;
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		blkdev_dequeue_request(rq);
+		end_that_request_last(rq, 0);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+
+		if (unlikely(mbox_seq_test(mbox, *p))) {
+			pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
+			continue;
+		}
+		p++;
+	}
+
+	pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+
+	return (size_t) ((char *)p - buf);
+}
+
+static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
+
+static ssize_t mbox_show(struct class *class, char *buf)
+{
+	return sprintf(buf, "mbox");
+}
+
+static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
+
+static struct class omap_mbox_class = {
+	.name = "omap_mbox",
+};
+
+static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
+					request_fn_proc * proc,
+					void (*work) (struct work_struct *))
+{
+	request_queue_t *q;
+	struct omap_mbox_queue *mq;
+
+	mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
+	if (!mq)
+		return NULL;
+
+	spin_lock_init(&mq->lock);
+
+	q = blk_init_queue(proc, &mq->lock);
+	if (!q)
+		goto error;
+	q->queuedata = mbox;
+	mq->queue = q;
+
+	INIT_WORK(&mq->work, work);
+
+	return mq;
+error:
+	kfree(mq);
+	return NULL;
+}
+
+static void mbox_queue_free(struct omap_mbox_queue *q)
+{
+	blk_cleanup_queue(q->queue);
+	kfree(q);
+}
+
+static int omap_mbox_init(struct omap_mbox *mbox)
+{
+	int ret;
+	struct omap_mbox_queue *mq;
+
+	if (likely(mbox->ops->startup)) {
+		ret = mbox->ops->startup(mbox);
+		if (unlikely(ret))
+			return ret;
+	}
+
+	mbox->dev.class = &omap_mbox_class;
+	strlcpy(mbox->dev.bus_id, mbox->name, KOBJ_NAME_LEN);
+	dev_set_drvdata(&mbox->dev, mbox);
+
+	ret = device_register(&mbox->dev);
+	if (unlikely(ret))
+		goto fail_device_reg;
+
+	ret = device_create_file(&mbox->dev, &dev_attr_mbox);
+	if (unlikely(ret)) {
+		printk(KERN_ERR
+			"device_create_file failed: %d\n", ret);
+		goto fail_create_mbox;
+	}
+
+	ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
+				mbox->name, mbox);
+	if (unlikely(ret)) {
+		printk(KERN_ERR
+			"failed to register mailbox interrupt:%d\n", ret);
+		goto fail_request_irq;
+	}
+	enable_mbox_irq(mbox, IRQ_RX);
+
+	mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
+	if (!mq) {
+		ret = -ENOMEM;
+		goto fail_alloc_txq;
+	}
+	mbox->txq = mq;
+
+	mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
+	if (!mq) {
+		ret = -ENOMEM;
+		goto fail_alloc_rxq;
+	}
+	mbox->rxq = mq;
+
+	return 0;
+
+ fail_alloc_rxq:
+	mbox_queue_free(mbox->txq);
+ fail_alloc_txq:
+	free_irq(mbox->irq, mbox);
+ fail_request_irq:
+	device_remove_file(&mbox->dev, &dev_attr_mbox);
+ fail_create_mbox:
+	device_unregister(&mbox->dev);
+ fail_device_reg:
+	if (unlikely(mbox->ops->shutdown))
+		mbox->ops->shutdown(mbox);
+
+	return ret;
+}
+
+static void omap_mbox_fini(struct omap_mbox *mbox)
+{
+	mbox_queue_free(mbox->txq);
+	mbox_queue_free(mbox->rxq);
+
+	free_irq(mbox->irq, mbox);
+	device_remove_file(&mbox->dev, &dev_attr_mbox);
+	class_unregister(&omap_mbox_class);
+
+	if (unlikely(mbox->ops->shutdown))
+		mbox->ops->shutdown(mbox);
+}
+
+static struct omap_mbox **find_mboxes(const char *name)
+{
+	struct omap_mbox **p;
+
+	for (p = &mboxes; *p; p = &(*p)->next) {
+		if (strcmp((*p)->name, name) == 0)
+			break;
+	}
+
+	return p;
+}
+
+struct omap_mbox *omap_mbox_get(const char *name)
+{
+	struct omap_mbox *mbox;
+	int ret;
+
+	read_lock(&mboxes_lock);
+	mbox = *(find_mboxes(name));
+	if (mbox == NULL) {
+		read_unlock(&mboxes_lock);
+		return ERR_PTR(-ENOENT);
+	}
+
+	read_unlock(&mboxes_lock);
+
+	ret = omap_mbox_init(mbox);
+	if (ret)
+		return ERR_PTR(-ENODEV);
+
+	return mbox;
+}
+EXPORT_SYMBOL(omap_mbox_get);
+
+void omap_mbox_put(struct omap_mbox *mbox)
+{
+	omap_mbox_fini(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_put);
+
+int omap_mbox_register(struct omap_mbox *mbox)
+{
+	int ret = 0;
+	struct omap_mbox **tmp;
+
+	if (!mbox)
+		return -EINVAL;
+	if (mbox->next)
+		return -EBUSY;
+
+	write_lock(&mboxes_lock);
+	tmp = find_mboxes(mbox->name);
+	if (*tmp)
+		ret = -EBUSY;
+	else
+		*tmp = mbox;
+	write_unlock(&mboxes_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(omap_mbox_register);
+
+int omap_mbox_unregister(struct omap_mbox *mbox)
+{
+	struct omap_mbox **tmp;
+
+	write_lock(&mboxes_lock);
+	tmp = &mboxes;
+	while (*tmp) {
+		if (mbox == *tmp) {
+			*tmp = mbox->next;
+			mbox->next = NULL;
+			write_unlock(&mboxes_lock);
+			return 0;
+		}
+		tmp = &(*tmp)->next;
+	}
+	write_unlock(&mboxes_lock);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(omap_mbox_unregister);
+
+static int __init omap_mbox_class_init(void)
+{
+	int ret = class_register(&omap_mbox_class);
+	if (!ret)
+		ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
+
+	return ret;
+}
+
+static void __exit omap_mbox_class_exit(void)
+{
+	class_remove_file(&omap_mbox_class, &class_attr_mbox);
+	class_unregister(&omap_mbox_class);
+}
+
+subsys_initcall(omap_mbox_class_init);
+module_exit(omap_mbox_class_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h
new file mode 100644
index 0000000..67c6740
--- /dev/null
+++ b/arch/arm/plat-omap/mailbox.h
@@ -0,0 +1,100 @@
+/*
+ * Mailbox internal functions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ARCH_ARM_PLAT_MAILBOX_H
+#define __ARCH_ARM_PLAT_MAILBOX_H
+
+/*
+ * Mailbox sequence bit API
+ */
+#if defined(CONFIG_ARCH_OMAP1)
+#  define MBOX_USE_SEQ_BIT
+#elif defined(CONFIG_ARCH_OMAP2)
+#  define MBOX_USE_SEQ_BIT
+#endif
+
+#ifdef MBOX_USE_SEQ_BIT
+/* seq_rcv should be initialized with any value other than
+ * 0 and 1 << 31, to allow either value for the first
+ * message.  */
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+	/* any value other than 0 and 1 << 31 */
+	mbox->seq_rcv = 0xffffffff;
+}
+
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+	/* add seq_snd to msg */
+	*msg = (*msg & 0x7fffffff) | mbox->seq_snd;
+	/* flip seq_snd */
+	mbox->seq_snd ^= 1 << 31;
+}
+
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	mbox_msg_t seq = msg & (1 << 31);
+	if (seq == mbox->seq_rcv)
+		return -1;
+	mbox->seq_rcv = seq;
+	return 0;
+}
+#else
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+}
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+}
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	return 0;
+}
+#endif
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
+{
+	return mbox->ops->fifo_read(mbox);
+}
+static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+	mbox->ops->fifo_write(mbox, msg);
+}
+static inline int mbox_fifo_empty(struct omap_mbox *mbox)
+{
+	return mbox->ops->fifo_empty(mbox);
+}
+static inline int mbox_fifo_full(struct omap_mbox *mbox)
+{
+	return mbox->ops->fifo_full(mbox);
+}
+
+/* Mailbox IRQ handle functions */
+static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+	mbox->ops->enable_irq(mbox, irq);
+}
+static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+	mbox->ops->disable_irq(mbox, irq);
+}
+static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+	if (mbox->ops->ack_irq)
+		mbox->ops->ack_irq(mbox, irq);
+}
+static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+	return mbox->ops->is_irq(mbox, irq);
+}
+
+#endif				/* __ARCH_ARM_PLAT_MAILBOX_H */
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 19014b2..bc46f33 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -46,14 +46,19 @@
 
 #define ROUND_DOWN(value,boundary)	((value) & (~((boundary)-1)))
 
+static unsigned long omap_sram_start;
 static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-unsigned long omap_fb_sram_start;
-unsigned long omap_fb_sram_size;
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+					 unsigned long sram_vstart,
+					 unsigned long sram_size,
+					 unsigned long pstart_avail,
+					 unsigned long size_avail);
 
-/* Depending on the target RAMFS firewall setup, the public usable amount of
+/*
+ * Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessable size for all device types is 2k. A GP
  * device allows ARM11 but not other initators for full size. This
  * functionality seems ok until some nice security API happens.
@@ -77,32 +82,6 @@
 		return 1; /* assume locked with no PPA or security driver */
 }
 
-void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
-		      unsigned long *start, unsigned long *size)
-{
-	const struct omap_fbmem_config *fbmem_conf;
-
-	fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-	if (fbmem_conf != NULL) {
-		*start = fbmem_conf->fb_sram_start;
-		*size = fbmem_conf->fb_sram_size;
-	} else {
-		*size = 0;
-		*start = 0;
-	}
-
-	if (*size && (
-	    *start < start_avail ||
-	    *start + *size > start_avail + size_avail)) {
-		printk(KERN_ERR "invalid FB SRAM configuration\n");
-		*start = start_avail;
-		*size = size_avail;
-	}
-
-	if (*size)
-		pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
-}
-
 /*
  * The amount of SRAM depends on the core type.
  * Note that we cannot try to test for SRAM here because writes
@@ -111,16 +90,16 @@
  */
 void __init omap_detect_sram(void)
 {
-	unsigned long sram_start;
+	unsigned long reserved;
 
 	if (cpu_is_omap24xx()) {
 		if (is_sram_locked()) {
 			omap_sram_base = OMAP2_SRAM_PUB_VA;
-			sram_start = OMAP2_SRAM_PUB_PA;
+			omap_sram_start = OMAP2_SRAM_PUB_PA;
 			omap_sram_size = 0x800; /* 2K */
 		} else {
 			omap_sram_base = OMAP2_SRAM_VA;
-			sram_start = OMAP2_SRAM_PA;
+			omap_sram_start = OMAP2_SRAM_PA;
 			if (cpu_is_omap242x())
 				omap_sram_size = 0xa0000; /* 640K */
 			else if (cpu_is_omap243x())
@@ -128,7 +107,7 @@
 		}
 	} else {
 		omap_sram_base = OMAP1_SRAM_VA;
-		sram_start = OMAP1_SRAM_PA;
+		omap_sram_start = OMAP1_SRAM_PA;
 
 		if (cpu_is_omap730())
 			omap_sram_size = 0x32000;	/* 200K */
@@ -144,12 +123,11 @@
 			omap_sram_size = 0x4000;
 		}
 	}
-	get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
-			 omap_sram_size - SRAM_BOOTLOADER_SZ,
-			 &omap_fb_sram_start, &omap_fb_sram_size);
-	if (omap_fb_sram_size)
-		omap_sram_size -= sram_start + omap_sram_size -
-				  omap_fb_sram_start;
+	reserved = omapfb_reserve_sram(omap_sram_start, omap_sram_base,
+				       omap_sram_size,
+				       omap_sram_start + SRAM_BOOTLOADER_SZ,
+				       omap_sram_size - SRAM_BOOTLOADER_SZ);
+	omap_sram_size -= reserved;
 	omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 7e80968..25489aa 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -37,9 +37,27 @@
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
 
+#ifdef CONFIG_ARCH_OMAP1
+
+#define INT_USB_IRQ_GEN		IH2_BASE + 20
+#define INT_USB_IRQ_NISO	IH2_BASE + 30
+#define INT_USB_IRQ_ISO		IH2_BASE + 29
+#define INT_USB_IRQ_HGEN	INT_USB_HHC_1
+#define INT_USB_IRQ_OTG		IH2_BASE + 8
+
+#else
+
+#define INT_USB_IRQ_GEN		INT_24XX_USB_IRQ_GEN
+#define INT_USB_IRQ_NISO	INT_24XX_USB_IRQ_NISO
+#define INT_USB_IRQ_ISO		INT_24XX_USB_IRQ_ISO
+#define INT_USB_IRQ_HGEN	INT_24XX_USB_IRQ_HGEN
+#define INT_USB_IRQ_OTG		INT_24XX_USB_IRQ_OTG
+
+#endif
+
+
 /* These routines should handle the standard chip-specific modes
  * for usb0/1/2 ports, covering basic mux and transceiver setup.
- * Call omap_usb_init() once, from INIT_MACHINE().
  *
  * Some board-*.c files will need to set up additional mux options,
  * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
@@ -96,19 +114,26 @@
 {
 	u32	syscon1 = 0;
 
+	if (cpu_is_omap24xx())
+		CONTROL_DEVCONF_REG &= ~USBT0WRMODEI(USB_BIDIR_TLL);
+
 	if (nwires == 0) {
-		if (!cpu_is_omap15xx()) {
+		if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
 			/* pulldown D+/D- */
 			USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
 		}
 		return 0;
 	}
 
-	if (is_device)
-		omap_cfg_reg(W4_USB_PUEN);
+	if (is_device) {
+		if (cpu_is_omap24xx())
+			omap_cfg_reg(J20_24XX_USB0_PUEN);
+		else
+			omap_cfg_reg(W4_USB_PUEN);
+	}
 
-	/* internal transceiver */
-	if (nwires == 2) {
+	/* internal transceiver (unavailable on 17xx, 24xx) */
+	if (!cpu_class_is_omap2() && nwires == 2) {
 		// omap_cfg_reg(P9_USB_DP);
 		// omap_cfg_reg(R8_USB_DM);
 
@@ -136,29 +161,50 @@
 		return 0;
 	}
 
-	omap_cfg_reg(V6_USB0_TXD);
-	omap_cfg_reg(W9_USB0_TXEN);
-	omap_cfg_reg(W5_USB0_SE0);
+	if (cpu_is_omap24xx()) {
+		omap_cfg_reg(K18_24XX_USB0_DAT);
+		omap_cfg_reg(K19_24XX_USB0_TXEN);
+		omap_cfg_reg(J14_24XX_USB0_SE0);
+		if (nwires != 3)
+			omap_cfg_reg(J18_24XX_USB0_RCV);
+	} else {
+		omap_cfg_reg(V6_USB0_TXD);
+		omap_cfg_reg(W9_USB0_TXEN);
+		omap_cfg_reg(W5_USB0_SE0);
+		if (nwires != 3)
+			omap_cfg_reg(Y5_USB0_RCV);
+	}
 
-	/* NOTE:  SPEED and SUSP aren't configured here */
+	/* NOTE:  SPEED and SUSP aren't configured here.  OTG hosts
+	 * may be able to use I2C requests to set those bits along
+	 * with VBUS switching and overcurrent detction.
+	 */
 
-	if (nwires != 3)
-		omap_cfg_reg(Y5_USB0_RCV);
-	if (nwires != 6)
+	if (cpu_class_is_omap1() && nwires != 6)
 		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
 	switch (nwires) {
 	case 3:
 		syscon1 = 2;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
 		break;
 	case 4:
 		syscon1 = 1;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
 		break;
 	case 6:
 		syscon1 = 3;
-		omap_cfg_reg(AA9_USB0_VP);
-		omap_cfg_reg(R9_USB0_VM);
-		USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+		if (cpu_is_omap24xx()) {
+			omap_cfg_reg(J19_24XX_USB0_VP);
+			omap_cfg_reg(K20_24XX_USB0_VM);
+			CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_UNIDIR);
+		} else {
+			omap_cfg_reg(AA9_USB0_VP);
+			omap_cfg_reg(R9_USB0_VM);
+			USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+		}
 		break;
 	default:
 		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -171,14 +217,22 @@
 {
 	u32	syscon1 = 0;
 
-	if (nwires != 6 && !cpu_is_omap15xx())
+	if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
 		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+	if (cpu_is_omap24xx())
+		CONTROL_DEVCONF_REG &= ~USBT1WRMODEI(USB_BIDIR_TLL);
+
 	if (nwires == 0)
 		return 0;
 
 	/* external transceiver */
-	omap_cfg_reg(USB1_TXD);
-	omap_cfg_reg(USB1_TXEN);
+	if (cpu_class_is_omap1()) {
+		omap_cfg_reg(USB1_TXD);
+		omap_cfg_reg(USB1_TXEN);
+		if (nwires != 3)
+			omap_cfg_reg(USB1_RCV);
+	}
+
 	if (cpu_is_omap15xx()) {
 		omap_cfg_reg(USB1_SEO);
 		omap_cfg_reg(USB1_SPEED);
@@ -190,20 +244,38 @@
 	} else if (cpu_is_omap1710()) {
 		omap_cfg_reg(R13_1710_USB1_SE0);
 		// SUSP
+	} else if (cpu_is_omap24xx()) {
+		/* NOTE:  board-specific code must set up pin muxing for usb1,
+		 * since each signal could come out on either of two balls.
+		 */
 	} else {
-		pr_debug("usb unrecognized\n");
+		pr_debug("usb%d cpu unrecognized\n", 1);
+		return 0;
 	}
-	if (nwires != 3)
-		omap_cfg_reg(USB1_RCV);
 
 	switch (nwires) {
+	case 2:
+		if (!cpu_is_omap24xx())
+			goto bad;
+		/* NOTE: board-specific code must override this setting if
+		 * this TLL link is not using DP/DM
+		 */
+		syscon1 = 1;
+		CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR_TLL);
+		break;
 	case 3:
 		syscon1 = 2;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
 		break;
 	case 4:
 		syscon1 = 1;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
 		break;
 	case 6:
+		if (cpu_is_omap24xx())
+			goto bad;
 		syscon1 = 3;
 		omap_cfg_reg(USB1_VP);
 		omap_cfg_reg(USB1_VM);
@@ -211,6 +283,7 @@
 			USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
 		break;
 	default:
+bad:
 		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
 			1, nwires);
 	}
@@ -221,10 +294,17 @@
 {
 	u32	syscon1 = 0;
 
-	/* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
+	if (cpu_is_omap24xx()) {
+		CONTROL_DEVCONF_REG &= ~(USBT2WRMODEI(USB_BIDIR_TLL)
+					| USBT2TLL5PI);
+		alt_pingroup = 0;
+	}
+
+	/* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
 	if (alt_pingroup || nwires == 0)
 		return 0;
-	if (nwires != 6 && !cpu_is_omap15xx())
+
+	if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
 		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
 	/* external transceiver */
@@ -242,19 +322,54 @@
 		if (nwires != 3)
 			omap_cfg_reg(Y5_USB2_RCV);
 		// FIXME omap_cfg_reg(USB2_SPEED);
+	} else if (cpu_is_omap24xx()) {
+		omap_cfg_reg(Y11_24XX_USB2_DAT);
+		omap_cfg_reg(AA10_24XX_USB2_SE0);
+		if (nwires > 2)
+			omap_cfg_reg(AA12_24XX_USB2_TXEN);
+		if (nwires > 3)
+			omap_cfg_reg(AA6_24XX_USB2_RCV);
 	} else {
-		pr_debug("usb unrecognized\n");
+		pr_debug("usb%d cpu unrecognized\n", 1);
+		return 0;
 	}
-	// omap_cfg_reg(USB2_SUSP);
+	// if (cpu_class_is_omap1()) omap_cfg_reg(USB2_SUSP);
 
 	switch (nwires) {
+	case 2:
+		if (!cpu_is_omap24xx())
+			goto bad;
+		/* NOTE: board-specific code must override this setting if
+		 * this TLL link is not using DP/DM
+		 */
+		syscon1 = 1;
+		CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR_TLL);
+		break;
 	case 3:
 		syscon1 = 2;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
 		break;
 	case 4:
 		syscon1 = 1;
+		if (cpu_is_omap24xx())
+			CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
+		break;
+	case 5:
+		if (!cpu_is_omap24xx())
+			goto bad;
+		omap_cfg_reg(AA4_24XX_USB2_TLLSE0);
+		/* NOTE: board-specific code must override this setting if
+		 * this TLL link is not using DP/DM.  Something must also
+		 * set up OTG_SYSCON2.HMC_TLL{ATTACH,SPEED}
+		 */
+		syscon1 = 3;
+		CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_UNIDIR_TLL)
+					| USBT2TLL5PI;
 		break;
 	case 6:
+		if (cpu_is_omap24xx())
+			goto bad;
 		syscon1 = 3;
 		if (cpu_is_omap15xx()) {
 			omap_cfg_reg(USB2_VP);
@@ -266,6 +381,7 @@
 		}
 		break;
 	default:
+bad:
 		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
 			2, nwires);
 	}
@@ -294,13 +410,13 @@
 		.end		= UDC_BASE + 0xff,
 		.flags		= IORESOURCE_MEM,
 	}, {		/* general IRQ */
-		.start		= IH2_BASE + 20,
+		.start		= INT_USB_IRQ_GEN,
 		.flags		= IORESOURCE_IRQ,
 	}, {		/* PIO IRQ */
-		.start		= IH2_BASE + 30,
+		.start		= INT_USB_IRQ_NISO,
 		.flags		= IORESOURCE_IRQ,
 	}, {		/* SOF IRQ */
-		.start		= IH2_BASE + 29,
+		.start		= INT_USB_IRQ_ISO,
 		.flags		= IORESOURCE_IRQ,
 	},
 };
@@ -329,11 +445,11 @@
 static struct resource ohci_resources[] = {
 	{
 		.start	= OMAP_OHCI_BASE,
-		.end	= OMAP_OHCI_BASE + 4096 - 1,
+		.end	= OMAP_OHCI_BASE + 0xff,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
-		.start	= INT_USB_HHC_1,
+		.start	= INT_USB_IRQ_HGEN,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -361,7 +477,7 @@
 		.end		= OTG_BASE + 0xff,
 		.flags		= IORESOURCE_MEM,
 	}, {
-		.start		= IH2_BASE + 8,
+		.start		= INT_USB_IRQ_OTG,
 		.flags		= IORESOURCE_IRQ,
 	},
 };
@@ -385,7 +501,7 @@
 
 
 // FIXME correct answer depends on hmc_mode,
-// as does any nonzero value for config->otg port number
+// as does (on omap1) any nonzero value for config->otg port number
 #ifdef	CONFIG_USB_GADGET_OMAP
 #define	is_usb0_device(config)	1
 #else
@@ -426,12 +542,13 @@
 	if (config->otg)
 		syscon |= OTG_EN;
 #endif
-	pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
+	if (cpu_class_is_omap1())
+		pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
 	pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
 	OTG_SYSCON_2_REG = syscon;
 
 	printk("USB: hmc %d", config->hmc_mode);
-	if (alt_pingroup)
+	if (!alt_pingroup)
 		printk(", usb2 alt %d wires", config->pins[2]);
 	else if (config->pins[0])
 		printk(", usb0 %d wires%s", config->pins[0],
@@ -444,10 +561,12 @@
 		printk(", Mini-AB on usb%d", config->otg - 1);
 	printk("\n");
 
-	/* leave USB clocks/controllers off until needed */
-	ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
-	ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
-	ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+	if (cpu_class_is_omap1()) {
+		/* leave USB clocks/controllers off until needed */
+		ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+		ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+		ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+	}
 	syscon = OTG_SYSCON_1_REG;
 	syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
 
@@ -585,7 +704,7 @@
 	}
 	platform_data = *config;
 
-	if (cpu_is_omap730() || cpu_is_omap16xx())
+	if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
 		omap_otg_init(&platform_data);
 	else if (cpu_is_omap15xx())
 		omap_1510_usb_init(&platform_data);
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S
index 435349d..7b7ae79 100644
--- a/arch/arm/plat-s3c24xx/sleep.S
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/sleep.S
+/* linux/arch/arm/plat-s3c24xx/sleep.S
  *
  * Copyright (c) 2004 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 6115fc1..dc6bc01 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -16,7 +16,7 @@
 CFLAGS_MODULE	+= -mno-relax
 LDFLAGS_vmlinux	+= --relax
 
-cpuflags-$(CONFIG_CPU_AP7000)	+= -mcpu=ap7000
+cpuflags-$(CONFIG_CPU_AT32AP7000)	+= -mcpu=ap7000
 
 CFLAGS		+= $(cpuflags-y)
 AFLAGS		+= $(cpuflags-y)
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 4e4181e..13f9884 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -330,13 +330,13 @@
 {
 	struct pt_regs *childregs;
 
-	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1;
+	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
 	*childregs = *regs;
 
 	if (user_mode(regs))
 		childregs->sp = usp;
 	else
-		childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE;
+		childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
 
 	childregs->r12 = 0; /* Set return value for child */
 
@@ -403,7 +403,7 @@
 	if (!p || p == current || p->state == TASK_RUNNING)
 		return 0;
 
-	stack_page = (unsigned long)p->thread_info;
+	stack_page = (unsigned long)task_stack_page(p);
 	BUG_ON(!stack_page);
 
 	/*
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 8ac74dd..3c36c2d 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -24,7 +24,7 @@
 
 static struct pt_regs *get_user_regs(struct task_struct *tsk)
 {
-	return (struct pt_regs *)((unsigned long) tsk->thread_info +
+	return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
 				  THREAD_SIZE - sizeof(struct pt_regs));
 }
 
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 7c27958..07f6a6f 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -291,4 +291,5 @@
 	.long	sys_shmget		/* 275 */
 	.long	sys_shmdt
 	.long	sys_shmctl
+	.long	sys_utimensat
 	.long	sys_ni_syscall		/* r8 is saturated at nr_syscalls */
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 4de9edf..86d1075 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -123,7 +123,7 @@
 
 /* This way of handling undefined instructions is stolen from ARM */
 static LIST_HEAD(undef_hook);
-static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(undef_lock);
 
 void register_undef_hook(struct undef_hook *hook)
 {
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index 7ad20cf..e7f72c9 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -35,7 +35,7 @@
 			_einittext = .;
 		. = ALIGN(4);
 		__tagtable_begin = .;
-			*(.taglist)
+			*(.taglist.init)
 		__tagtable_end = .;
 			*(.init.data)
 		. = ALIGN(16);
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 00c4354..0f8c89c 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -18,7 +18,7 @@
 
 #include "clock.h"
 
-static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clk_lock);
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
index b68d669..099212d 100644
--- a/arch/avr32/mm/dma-coherent.c
+++ b/arch/avr32/mm/dma-coherent.c
@@ -112,16 +112,21 @@
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-#if 0
 void *dma_alloc_writecombine(struct device *dev, size_t size,
 			     dma_addr_t *handle, gfp_t gfp)
 {
 	struct page *page;
+	dma_addr_t phys;
 
 	page = __dma_alloc(dev, size, handle, gfp);
+	if (!page)
+		return NULL;
+
+	phys = page_to_phys(page);
+	*handle = phys;
 
 	/* Now, map the page into P3 with write-combining turned on */
-	return __ioremap(page_to_phys(page), size, _PAGE_BUFFER);
+	return __ioremap(phys, size, _PAGE_BUFFER);
 }
 EXPORT_SYMBOL(dma_alloc_writecombine);
 
@@ -132,8 +137,7 @@
 
 	iounmap(cpu_addr);
 
-	page = bus_to_page(handle);
+	page = phys_to_page(handle);
 	__dma_free(dev, size, page, handle);
 }
 EXPORT_SYMBOL(dma_free_writecombine);
-#endif
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index 41d9a9f..e455f45 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -46,7 +46,7 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index d7c8e51..e718bb4 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -73,7 +73,7 @@
 static inline struct pt_regs *get_user_regs(struct task_struct *task)
 {
 	return (struct pt_regs *)
-	    ((unsigned long)task->thread_info +
+	    ((unsigned long)task_stack_page(task) +
 	     (THREAD_SIZE - sizeof(struct pt_regs)));
 }
 
@@ -99,7 +99,7 @@
 	unsigned char *reg_ptr;
 
 	struct pt_regs *regs =
-	    (struct pt_regs *)((unsigned long)task->thread_info +
+	    (struct pt_regs *)((unsigned long)task_stack_page(task) +
 			       (THREAD_SIZE - sizeof(struct pt_regs)));
 	reg_ptr = (char *)regs;
 
@@ -125,7 +125,7 @@
 	char * reg_ptr;
 
 	struct pt_regs *regs =
-	    (struct pt_regs *)((unsigned long)task->thread_info +
+	    (struct pt_regs *)((unsigned long)task_stack_page(task) +
 			       (THREAD_SIZE - sizeof(struct pt_regs)));
 	reg_ptr = (char *)regs;
 
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index f64624f..1d859c1 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -603,7 +603,7 @@
         select HOTPLUG
         select PCCARD_NONSTATIC
         help
-	 Enabled the ETRAX Carbus driver.
+	 Enabled the ETRAX Cardbus driver.
 
 config PCI
        bool
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index eed6943..114738a 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -45,6 +45,10 @@
 	bool
 	default y
 
+config QUICKLIST
+	bool
+	default y
+
 config ARCH_HAS_ILOG2_U32
 	bool
 	default y
@@ -53,10 +57,6 @@
 	bool
 	default y
 
-config ARCH_USES_SLAB_PAGE_STRUCT
-	bool
-	default y
-
 mainmenu "Fujitsu FR-V Kernel Configuration"
 
 source "init/Kconfig"
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 940ac30..43dc08e 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1482,6 +1482,16 @@
 	.long sys_faccessat
 	.long sys_pselect6
 	.long sys_ppoll
+	.long sys_unshare		/* 310 */
+	.long sys_set_robust_list
+	.long sys_get_robust_list
+	.long sys_splice
+	.long sys_sync_file_range
+	.long sys_tee			/* 315 */
+	.long sys_vmsplice
+	.long sys_move_pages
+	.long sys_getcpu
+	.long sys_epoll_pwait
 
 
 syscall_table_size = (. - sys_call_table)
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 515a5ce..9583a33 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -25,12 +25,14 @@
 #include <linux/elf.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/pagemap.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
+#include <asm/tlb.h>
 #include <asm/gdb-stub.h>
 #include <asm/mb-regs.h>
 
@@ -88,6 +90,8 @@
 		while (!need_resched()) {
 			irq_stat[cpu].idle_timestamp = jiffies;
 
+			check_pgt_cache();
+
 			if (!frv_dma_inprogress && idle)
 				idle();
 		}
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index 8ea3ca2..aa3c795 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -191,7 +191,7 @@
 static const struct clock_cmode __pminitdata *clock_cmodes;
 static int __pminitdata clock_doubled;
 
-static struct uart_port __initdata __frv_uart0 = {
+static struct uart_port __pminitdata __frv_uart0 = {
 	.uartclk		= 0,
 	.membase		= (char *) UART0_BASE,
 	.irq			= IRQ_CPU_UART0,
@@ -200,7 +200,7 @@
 	.flags			= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
 };
 
-static struct uart_port __initdata __frv_uart1 = {
+static struct uart_port __pminitdata __frv_uart1 = {
 	.uartclk		= 0,
 	.membase		= (char *) UART1_BASE,
 	.irq			= IRQ_CPU_UART1,
diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c
index cac2c01..385fd30 100644
--- a/arch/frv/mm/elf-fdpic.c
+++ b/arch/frv/mm/elf-fdpic.c
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/elf-fdpic.h>
+#include <asm/mman.h>
 
 /*****************************************************************************/
 /*
diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c
index 598a26a..7787c3c 100644
--- a/arch/frv/mm/pgalloc.c
+++ b/arch/frv/mm/pgalloc.c
@@ -13,12 +13,12 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/quicklist.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((aligned(PAGE_SIZE)));
-struct kmem_cache *pgd_cache;
 
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
@@ -100,7 +100,7 @@
 		set_page_private(next, (unsigned long) pprev);
 }
 
-void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_ctor(void *pgd)
 {
 	unsigned long flags;
 
@@ -120,7 +120,7 @@
 }
 
 /* never called when PTRS_PER_PMD > 1 */
-void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_dtor(void *pgd)
 {
 	unsigned long flags; /* can be called from interrupt context */
 
@@ -133,7 +133,7 @@
 {
 	pgd_t *pgd;
 
-	pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
+	pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
 	if (!pgd)
 		return pgd;
 
@@ -143,15 +143,15 @@
 void pgd_free(pgd_t *pgd)
 {
 	/* in the non-PAE case, clear_page_tables() clears user pgd entries */
-	kmem_cache_free(pgd_cache, pgd);
+ 	quicklist_free(0, pgd_dtor, pgd);
 }
 
 void __init pgtable_cache_init(void)
 {
-	pgd_cache = kmem_cache_create("pgd",
-				      PTRS_PER_PGD * sizeof(pgd_t),
-				      PTRS_PER_PGD * sizeof(pgd_t),
-				      SLAB_PANIC,
-				      pgd_ctor,
-				      pgd_dtor);
 }
+
+void check_pgt_cache(void)
+{
+	quicklist_trim(0, pgd_dtor, 25, 16);
+}
+
diff --git a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug
index e0e9bcb..554efe6 100644
--- a/arch/h8300/Kconfig.debug
+++ b/arch/h8300/Kconfig.debug
@@ -21,12 +21,12 @@
 	bool "Message Output for GDB MagicPrint service"
 	depends on (H8300H_SIM || H8S_SIM)
 	help
-	  kernel messages output useing MagicPrint service from GDB
+	  kernel messages output using MagicPrint service from GDB
 
 config SYSCALL_PRINT
 	bool "SystemCall trace print"
 	help
-	  outout history of systemcall
+	  output history of systemcall
 
 config GDB_DEBUG
    	bool "Use gdb stub"
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c
index b78b82a..fc30b4f 100644
--- a/arch/h8300/kernel/asm-offsets.c
+++ b/arch/h8300/kernel/asm-offsets.c
@@ -30,7 +30,7 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 64ad10f..30944ee 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -858,9 +858,9 @@
 	bool "Build a relocatable kernel(EXPERIMENTAL)"
 	depends on EXPERIMENTAL
 	help
-	  This build a kernel image that retains relocation information
+	  This builds a kernel image that retains relocation information
           so it can be loaded someplace besides the default 1MB.
-	  The relocations tend to the kernel binary about 10% larger,
+	  The relocations tend to make the kernel binary about 10% larger,
           but are discarded at runtime.
 
 	  One use is for the kexec on panic case where the recovery kernel
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index dce6124..d7f6fb0 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -108,7 +108,7 @@
 	bool "Core 2/newer Xeon"
 	help
 	  Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and 53xx)
-	  CPUs. You can distingush newer from older Xeons by the CPU family
+	  CPUs. You can distinguish newer from older Xeons by the CPU family
 	  in /proc/cpuinfo. Newer ones have 6.
 
 config MPENTIUM4
@@ -172,7 +172,7 @@
 	help
 	  Select this for an IDT Winchip-2A or 3.  Linux and GCC
 	  treat this chip as a 586TSC with some extended instructions
-	  and alignment reqirements.  Also enable out of order memory
+	  and alignment requirements.  Also enable out of order memory
 	  stores for this CPU, which can increase performance of some
 	  operations.
 
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 5e2280c..8143c95 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -496,11 +496,9 @@
 	cmpb	$VIDEO_FIRST_V7>>8, %ah
 	jz	setv7
 	
-#ifdef CONFIG_FB
 	cmpb	$VIDEO_FIRST_VESA>>8, %ah
 	jnc	check_vesa
-#endif
-
+	
 	orb	%ah, %ah
 	jz	setmenu
 	
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 80b4c5d..e5be819 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -733,9 +733,11 @@
 	sys_dev = get_cpu_sysdev(cpu);
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		cache_add_dev(sys_dev);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		cache_remove_dev(sys_dev);
 		break;
 	}
diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c
index 065005c..7ba7c3a 100644
--- a/arch/i386/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/i386/kerne/cpu/mcheck/therm_throt.c
+ * linux/arch/i386/kernel/cpu/mcheck/therm_throt.c
  *
  * Thermal throttle event support code (such as syslog messaging and rate
  * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
@@ -137,10 +137,12 @@
 	mutex_lock(&therm_cpu_lock);
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		err = thermal_throttle_add_dev(sys_dev);
 		WARN_ON(err);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		thermal_throttle_remove_dev(sys_dev);
 		break;
 	}
diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
index 6471a5a..200fb3f 100644
--- a/arch/i386/kernel/cpu/transmeta.c
+++ b/arch/i386/kernel/cpu/transmeta.c
@@ -77,8 +77,10 @@
 	set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
 	
 	/* If we can run i686 user-space code, call us an i686 */
-#define USER686 (X86_FEATURE_TSC|X86_FEATURE_CX8|X86_FEATURE_CMOV)
-        if ( c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686 )
+#define USER686 ((1 << X86_FEATURE_TSC)|\
+		 (1 << X86_FEATURE_CX8)|\
+		 (1 << X86_FEATURE_CMOV))
+        if (c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686)
 		c->x86 = 6;
 
 #ifdef CONFIG_SYSCTL
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
index eeae0d9..5c2faa1 100644
--- a/arch/i386/kernel/cpuid.c
+++ b/arch/i386/kernel/cpuid.c
@@ -169,9 +169,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		cpuid_device_create(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
 		break;
 	}
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index cbe7ec8..83f825f 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -567,7 +567,7 @@
 	return error;
 }
 
-static int apply_microcode_on_cpu(int cpu)
+static int apply_microcode_check_cpu(int cpu)
 {
 	struct cpuinfo_x86 *c = cpu_data + cpu;
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -575,8 +575,9 @@
 	unsigned int val[2];
 	int err = 0;
 
+	/* Check if the microcode is available */
 	if (!uci->mc)
-		return -EINVAL;
+		return 0;
 
 	old = current->cpus_allowed;
 	set_cpus_allowed(current, cpumask_of_cpu(cpu));
@@ -614,7 +615,7 @@
 	return err;
 }
 
-static void microcode_init_cpu(int cpu)
+static void microcode_init_cpu(int cpu, int resume)
 {
 	cpumask_t old;
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -624,8 +625,7 @@
 	set_cpus_allowed(current, cpumask_of_cpu(cpu));
 	mutex_lock(&microcode_mutex);
 	collect_cpu_info(cpu);
-	if (uci->valid && system_state == SYSTEM_RUNNING &&
-	    !suspend_cpu_hotplug)
+	if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
 		cpu_request_microcode(cpu);
 	mutex_unlock(&microcode_mutex);
 	set_cpus_allowed(current, old);
@@ -702,7 +702,7 @@
 	.name = "microcode",
 };
 
-static int mc_sysdev_add(struct sys_device *sys_dev)
+static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
 {
 	int err, cpu = sys_dev->id;
 	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -711,39 +711,31 @@
 		return 0;
 
 	pr_debug("Microcode:CPU %d added\n", cpu);
-	/* If suspend_cpu_hotplug is set, the system is resuming and we should
-	 * use the data from before the suspend.
-	 */
-	if (suspend_cpu_hotplug) {
-		err = apply_microcode_on_cpu(cpu);
-		if (err)
-			microcode_fini_cpu(cpu);
-	}
-	if (!uci->valid)
-		memset(uci, 0, sizeof(*uci));
+	memset(uci, 0, sizeof(*uci));
 
 	err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
 	if (err)
 		return err;
 
-	if (!uci->valid)
-		microcode_init_cpu(cpu);
+	microcode_init_cpu(cpu, resume);
 
 	return 0;
 }
 
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+	return __mc_sysdev_add(sys_dev, 0);
+}
+
 static int mc_sysdev_remove(struct sys_device *sys_dev)
 {
 	int cpu = sys_dev->id;
 
 	if (!cpu_online(cpu))
 		return 0;
+
 	pr_debug("Microcode:CPU %d removed\n", cpu);
-	/* If suspend_cpu_hotplug is set, the system is suspending and we should
-	 * keep the microcode in memory for the resume.
-	 */
-	if (!suspend_cpu_hotplug)
-		microcode_fini_cpu(cpu);
+	microcode_fini_cpu(cpu);
 	sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
 	return 0;
 }
@@ -774,13 +766,34 @@
 
 	sys_dev = get_cpu_sysdev(cpu);
 	switch (action) {
+	case CPU_UP_CANCELED_FROZEN:
+		/* The CPU refused to come up during a system resume */
+		microcode_fini_cpu(cpu);
+		break;
 	case CPU_ONLINE:
 	case CPU_DOWN_FAILED:
 		mc_sysdev_add(sys_dev);
 		break;
+	case CPU_ONLINE_FROZEN:
+		/* System-wide resume is in progress, try to apply microcode */
+		if (apply_microcode_check_cpu(cpu)) {
+			/* The application of microcode failed */
+			microcode_fini_cpu(cpu);
+			__mc_sysdev_add(sys_dev, 1);
+			break;
+		}
+	case CPU_DOWN_FAILED_FROZEN:
+		if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+			printk(KERN_ERR "Microcode: Failed to create the sysfs "
+				"group for CPU%d\n", cpu);
+		break;
 	case CPU_DOWN_PREPARE:
 		mc_sysdev_remove(sys_dev);
 		break;
+	case CPU_DOWN_PREPARE_FROZEN:
+		/* Suspend is in progress, only remove the interface */
+		sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+		break;
 	}
 	return NOTIFY_OK;
 }
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index 8cd0a91..0c1069b 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -153,9 +153,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		msr_device_create(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
 		break;
 	}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 4bec0cb..c05e7e8 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -305,7 +305,7 @@
 	       regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
 	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
 		TASK_COMM_LEN, current->comm, current->pid,
-		current_thread_info(), current, current->thread_info);
+		current_thread_info(), current, task_thread_info(current));
 	/*
 	 * When in-kernel, we also print out the stack and code at the
 	 * time of the fault..
diff --git a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c
index a7b3999..74f3da6 100644
--- a/arch/i386/mach-generic/probe.c
+++ b/arch/i386/mach-generic/probe.c
@@ -119,9 +119,7 @@
 	return 0;	
 }
 
-#ifdef CONFIG_SMP
 int hard_smp_processor_id(void)
 {
 	return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID));
 }
-#endif
diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
index 8fe7e45..9b77b39 100644
--- a/arch/i386/mach-voyager/voyager_basic.c
+++ b/arch/i386/mach-voyager/voyager_basic.c
@@ -292,8 +292,8 @@
 void
 mca_nmi_hook(void)
 {
-	__u8 dumpval __attribute__((unused)) = inb(0xf823);
-	__u8 swnmi __attribute__((unused)) = inb(0xf813);
+	__u8 dumpval __maybe_unused = inb(0xf823);
+	__u8 swnmi __maybe_unused = inb(0xf813);
 
 	/* FIXME: assume dump switch pressed */
 	/* check to see if the dump switch was pressed */
diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
index 1cf11af..3de9f9b 100644
--- a/arch/i386/pci/init.c
+++ b/arch/i386/pci/init.c
@@ -6,7 +6,7 @@
    in the right sequence from here. */
 static __init int pci_access_init(void)
 {
-	int type __attribute__((unused)) = 0;
+	int type __maybe_unused = 0;
 
 #ifdef CONFIG_PCI_DIRECT
 	type = pci_direct_probe();
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e23af4b..6e41471 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -468,7 +468,7 @@
 	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
+	  but it is independent 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.
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index 687e5fd..99b665e 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -52,43 +52,6 @@
 	br.ret.sptk.many rp
 END(ia32_clone)
 
-ENTRY(sys32_rt_sigsuspend)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-	alloc loc1=ar.pfs,8,2,3,0		// preserve all eight input regs
-	mov loc0=rp
-	mov out0=in0				// mask
-	mov out1=in1				// sigsetsize
-	mov out2=sp				// out2 = &sigscratch
-	.fframe 16
-	adds sp=-16,sp				// allocate dummy "sigscratch"
-	;;
-	.body
-	br.call.sptk.many rp=ia32_rt_sigsuspend
-1:	.restore sp
-	adds sp=16,sp
-	mov rp=loc0
-	mov ar.pfs=loc1
-	br.ret.sptk.many rp
-END(sys32_rt_sigsuspend)
-
-ENTRY(sys32_sigsuspend)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-	alloc loc1=ar.pfs,8,2,3,0		// preserve all eight input regs
-	mov loc0=rp
-	mov out0=in2				// mask (first two args are ignored)
-	;;
-	mov out1=sp				// out1 = &sigscratch
-	.fframe 16
-	adds sp=-16,sp				// allocate dummy "sigscratch"
-	.body
-	br.call.sptk.many rp=ia32_sigsuspend
-1:	.restore sp
-	adds sp=16,sp
-	mov rp=loc0
-	mov ar.pfs=loc1
-	br.ret.sptk.many rp
-END(sys32_sigsuspend)
-
 GLOBAL_ENTRY(ia32_ret_from_clone)
 	PT_REGS_UNWIND_INFO(0)
 {	/*
@@ -389,7 +352,7 @@
 	data8 sys_rt_sigpending
 	data8 compat_sys_rt_sigtimedwait
 	data8 sys32_rt_sigqueueinfo
-	data8 sys32_rt_sigsuspend
+	data8 compat_sys_rt_sigsuspend
 	data8 sys32_pread	  /* 180 */
 	data8 sys32_pwrite
 	data8 sys_chown	/* 16-bit version */
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index 10510e5..85e82f3 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -451,59 +451,20 @@
 		sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);
 }
 
-long
-__ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sigscratch *scr)
+asmlinkage long
+sys32_sigsuspend (int history0, int history1, old_sigset_t mask)
 {
-	extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall);
-	sigset_t oldset, set;
-
-	scr->scratch_unat = 0;	/* avoid leaking kernel bits to user level */
-	memset(&set, 0, sizeof(set));
-
-	memcpy(&set.sig, &sset->sig, sigsetsize);
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-
+	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sighand->siglock);
-	{
-		oldset = current->blocked;
-		current->blocked = set;
-		recalc_sigpending();
-	}
+	current->saved_sigmask = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	/*
-	 * The return below usually returns to the signal handler.  We need to pre-set the
-	 * correct error code here to ensure that the right values get saved in sigcontext
-	 * by ia64_do_signal.
-	 */
-	scr->pt.r8 = -EINTR;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (ia64_do_signal(&oldset, scr, 1))
-			return -EINTR;
-	}
-}
-
-asmlinkage long
-ia32_rt_sigsuspend (compat_sigset_t __user *uset, unsigned int sigsetsize, struct sigscratch *scr)
-{
-	compat_sigset_t set;
-
-	if (sigsetsize > sizeof(compat_sigset_t))
-		return -EINVAL;
-
-	if (copy_from_user(&set.sig, &uset->sig, sigsetsize))
-		return -EFAULT;
-
-	return __ia32_rt_sigsuspend(&set, sigsetsize, scr);
-}
-
-asmlinkage long
-ia32_sigsuspend (unsigned int mask, struct sigscratch *scr)
-{
-	return __ia32_rt_sigsuspend((compat_sigset_t *) &mask, sizeof(mask), scr);
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	set_thread_flag(TIF_RESTORE_SIGMASK);
+	return -ERESTARTNOHAND;
 }
 
 asmlinkage long
@@ -810,7 +771,11 @@
 	}
 	/* Legacy stack switching not supported */
 
-	return (void __user *)((esp - frame_size) & -8ul);
+	esp -= frame_size;
+	/* Align the stack pointer according to the i386 ABI,
+	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
+	esp = ((esp + 4) & -16ul) - 4;
+	return (void __user *) esp;
 }
 
 static int
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 55fd2d5..b50bf20 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1199,32 +1199,6 @@
 	br.ret.sptk.many rp
 END(notify_resume_user)
 
-GLOBAL_ENTRY(sys_rt_sigsuspend)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-	alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
-	mov r9=ar.unat
-	mov loc0=rp				// save return address
-	mov out0=in0				// mask
-	mov out1=in1				// sigsetsize
-	adds out2=8,sp				// out2=&sigscratch->ar_pfs
-	;;
-	.fframe 16
-	.spillsp ar.unat, 16
-	st8 [sp]=r9,-16				// allocate space for ar.unat and save it
-	st8 [out2]=loc1,-8			// save ar.pfs, out2=&sigscratch
-	.body
-	br.call.sptk.many rp=ia64_rt_sigsuspend
-.ret17:	.restore sp
-	adds sp=16,sp				// pop scratch stack space
-	;;
-	ld8 r9=[sp]				// load new unat from sw->caller_unat
-	mov rp=loc0
-	;;
-	mov ar.unat=r9
-	mov ar.pfs=loc1
-	br.ret.sptk.many rp
-END(sys_rt_sigsuspend)
-
 ENTRY(sys_rt_sigreturn)
 	PT_REGS_UNWIND_INFO(0)
 	/*
@@ -1598,8 +1572,8 @@
 	data8 sys_readlinkat
 	data8 sys_fchmodat
 	data8 sys_faccessat
-	data8 sys_ni_syscall			// reserved for pselect
-	data8 sys_ni_syscall			// 1295 reserved for ppoll
+	data8 sys_pselect6
+	data8 sys_ppoll
 	data8 sys_unshare
 	data8 sys_splice
 	data8 sys_set_robust_list
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
index d3e9f33..6a49600 100644
--- a/arch/ia64/kernel/err_inject.c
+++ b/arch/ia64/kernel/err_inject.c
@@ -236,9 +236,11 @@
 	sys_dev = get_cpu_sysdev(cpu);
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		err_inject_add_dev(sys_dev);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		err_inject_remove_dev(sys_dev);
 		break;
 	}
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 93d9ab1..37f4652 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -1012,7 +1012,7 @@
 /*
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
  */
-void __init
+void __devinit
 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
 			  unsigned long polarity,
 			  unsigned long trigger)
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 1c5044a..bc47049 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -38,6 +38,7 @@
 #include <asm/machvec.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
 
 #ifdef CONFIG_PERFMON
 # include <asm/perfmon.h>
@@ -126,8 +127,10 @@
 
 #ifdef CONFIG_SMP
 #	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
+#	define IS_LOCAL_TLB_FLUSH(vec)	(vec == IA64_IPI_LOCAL_TLB_FLUSH)
 #else
 #	define IS_RESCHEDULE(vec)	(0)
+#	define IS_LOCAL_TLB_FLUSH(vec)	(0)
 #endif
 /*
  * That's where the IVT branches when we get an external
@@ -179,8 +182,11 @@
 	saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
 	ia64_srlz_d();
 	while (vector != IA64_SPURIOUS_INT_VECTOR) {
-		if (unlikely(IS_RESCHEDULE(vector)))
-			 kstat_this_cpu.irqs[vector]++;
+		if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
+			smp_local_flush_tlb();
+			kstat_this_cpu.irqs[vector]++;
+		} else if (unlikely(IS_RESCHEDULE(vector)))
+			kstat_this_cpu.irqs[vector]++;
 		else {
 			ia64_setreg(_IA64_REG_CR_TPR, vector);
 			ia64_srlz_d();
@@ -226,8 +232,11 @@
 	  * Perform normal interrupt style processing
 	  */
 	while (vector != IA64_SPURIOUS_INT_VECTOR) {
-		if (unlikely(IS_RESCHEDULE(vector)))
-			 kstat_this_cpu.irqs[vector]++;
+		if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
+			smp_local_flush_tlb();
+			kstat_this_cpu.irqs[vector]++;
+		} else if (unlikely(IS_RESCHEDULE(vector)))
+			kstat_this_cpu.irqs[vector]++;
 		else {
 			struct pt_regs *old_regs = set_irq_regs(NULL);
 
@@ -259,12 +268,12 @@
 
 
 #ifdef CONFIG_SMP
-extern irqreturn_t handle_IPI (int irq, void *dev_id);
 
 static irqreturn_t dummy_handler (int irq, void *dev_id)
 {
 	BUG();
 }
+extern irqreturn_t handle_IPI (int irq, void *dev_id);
 
 static struct irqaction ipi_irqaction = {
 	.handler =	handle_IPI,
@@ -277,6 +286,13 @@
 	.flags =	IRQF_DISABLED,
 	.name =		"resched"
 };
+
+static struct irqaction tlb_irqaction = {
+	.handler =	dummy_handler,
+	.flags =	IRQF_DISABLED,
+	.name =		"tlb_flush"
+};
+
 #endif
 
 void
@@ -302,6 +318,7 @@
 #ifdef CONFIG_SMP
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 	register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
+	register_percpu_irq(IA64_IPI_LOCAL_TLB_FLUSH, &tlb_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
 	pfm_init_percpu();
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 1d7cc7e..f8ae709 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -1689,7 +1689,7 @@
 	ti->preempt_count = 1;
 	ti->task = p;
 	ti->cpu = cpu;
-	p->thread_info = ti;
+	p->stack = ti;
 	p->state = TASK_UNINTERRUPTIBLE;
 	cpu_set(cpu, p->cpus_allowed);
 	INIT_LIST_HEAD(&p->tasks);
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index a71df9a..85829e2 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -975,9 +975,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		create_palinfo_proc_entries(hotcpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		remove_palinfo_proc_entries(hotcpu);
 		break;
 	}
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 8bb571a..d1c3ed9 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -155,7 +155,7 @@
 }
 
 void
-do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
+do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall)
 {
 	if (fsys_mode(current, &scr->pt)) {
 		/* defer signal-handling etc. until we return to privilege-level 0.  */
@@ -170,8 +170,8 @@
 #endif
 
 	/* deal with pending signal delivery */
-	if (test_thread_flag(TIF_SIGPENDING))
-		ia64_do_signal(oldset, scr, in_syscall);
+	if (test_thread_flag(TIF_SIGPENDING)||test_thread_flag(TIF_RESTORE_SIGMASK))
+		ia64_do_signal(scr, in_syscall);
 }
 
 static int pal_halt        = 1;
@@ -236,6 +236,7 @@
 {
 	unsigned int cpu, this_cpu = get_cpu();
 	cpumask_t map;
+	cpumask_t tmp = current->cpus_allowed;
 
 	set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
 	put_cpu();
@@ -257,6 +258,7 @@
 		}
 		cpus_and(map, map, cpu_online_map);
 	} while (!cpus_empty(map));
+	set_cpus_allowed(current, tmp);
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
diff --git a/arch/ia64/kernel/relocate_kernel.S b/arch/ia64/kernel/relocate_kernel.S
index ae473e3..903babd 100644
--- a/arch/ia64/kernel/relocate_kernel.S
+++ b/arch/ia64/kernel/relocate_kernel.S
@@ -94,7 +94,7 @@
 4:
         srlz.i
         ;;
-	//purge TR entry for kernel text and data
+	// purge TR entry for kernel text and data
         movl r16=KERNEL_START
         mov r18=KERNEL_TR_PAGE_SHIFT<<2
         ;;
@@ -104,15 +104,6 @@
         srlz.i
         ;;
 
-	// purge TR entry for percpu data
-        movl r16=PERCPU_ADDR
-        mov r18=PERCPU_PAGE_SHIFT<<2
-        ;;
-        ptr.d r16,r18
-        ;;
-        srlz.d
-	;;
-
         // purge TR entry for pal code
         mov r16=in3
         mov r18=IA64_GRANULE_SHIFT<<2
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index a51f1d0..89f6b13 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -582,6 +582,7 @@
 	struct salinfo_data *data;
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		spin_lock_irqsave(&data_saved_lock, flags);
 		for (i = 0, data = salinfo_data;
 		     i < ARRAY_SIZE(salinfo_data);
@@ -592,6 +593,7 @@
 		spin_unlock_irqrestore(&data_saved_lock, flags);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		spin_lock_irqsave(&data_saved_lock, flags);
 		for (i = 0, data = salinfo_data;
 		     i < ARRAY_SIZE(salinfo_data);
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 6e19da1..9df1efe 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -786,7 +786,7 @@
 	c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
 }
 
-void
+void __init
 setup_per_cpu_areas (void)
 {
 	/* start_kernel() requires this... */
diff --git a/arch/ia64/kernel/sigframe.h b/arch/ia64/kernel/sigframe.h
index 37b986c..9fd9a19 100644
--- a/arch/ia64/kernel/sigframe.h
+++ b/arch/ia64/kernel/sigframe.h
@@ -22,4 +22,4 @@
 	struct sigcontext sc;
 };
 
-extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);
+extern void ia64_do_signal (struct sigscratch *, long);
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 0dcd56da..aeec818 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -40,47 +40,6 @@
 # define GET_SIGSET(k,u)	__get_user((k)->sig[0], &(u)->sig[0])
 #endif
 
-long
-ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch *scr)
-{
-	sigset_t oldset, set;
-
-	/* XXX: Don't preclude handling different sized sigset_t's.  */
-	if (sigsetsize != sizeof(sigset_t))
-		return -EINVAL;
-
-	if (!access_ok(VERIFY_READ, uset, sigsetsize))
-		return -EFAULT;
-
-	if (GET_SIGSET(&set, uset))
-		return -EFAULT;
-
-	sigdelsetmask(&set, ~_BLOCKABLE);
-
-	spin_lock_irq(&current->sighand->siglock);
-	{
-		oldset = current->blocked;
-		current->blocked = set;
-		recalc_sigpending();
-	}
-	spin_unlock_irq(&current->sighand->siglock);
-
-	/*
-	 * The return below usually returns to the signal handler.  We need to
-	 * pre-set the correct error code here to ensure that the right values
-	 * get saved in sigcontext by ia64_do_signal.
-	 */
-	scr->pt.r8 = EINTR;
-	scr->pt.r10 = -1;
-
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (ia64_do_signal(&oldset, scr, 1))
-			return -EINTR;
-	}
-}
-
 asmlinkage long
 sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2,
 		 long arg3, long arg4, long arg5, long arg6, long arg7,
@@ -477,10 +436,11 @@
  * Note that `init' is a special process: it doesn't get signals it doesn't want to
  * handle.  Thus you cannot kill init even with a SIGKILL even by mistake.
  */
-long
-ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
+void
+ia64_do_signal (struct sigscratch *scr, long in_syscall)
 {
 	struct k_sigaction ka;
+	sigset_t *oldset;
 	siginfo_t info;
 	long restart = in_syscall;
 	long errno = scr->pt.r8;
@@ -492,9 +452,11 @@
 	 * doing anything if so.
 	 */
 	if (!user_mode(&scr->pt))
-		return 0;
+		return;
 
-	if (!oldset)
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
 		oldset = &current->blocked;
 
 	/*
@@ -557,8 +519,15 @@
 		 * Whee!  Actually deliver the signal.  If the delivery failed, we need to
 		 * continue to iterate in this loop so we can deliver the SIGSEGV...
 		 */
-		if (handle_signal(signr, &ka, &info, oldset, scr))
-			return 1;
+		if (handle_signal(signr, &ka, &info, oldset, scr)) {
+			/* a signal was successfully delivered; the saved
+			 * sigmask will have been stored in the signal frame,
+			 * and will be restored by sigreturn, so we can simply
+			 * clear the TIF_RESTORE_SIGMASK flag */
+			if (test_thread_flag(TIF_RESTORE_SIGMASK))
+				clear_thread_flag(TIF_RESTORE_SIGMASK);
+			return;
+		}
 	}
 
 	/* Did we come from a system call? */
@@ -584,5 +553,11 @@
 			}
 		}
 	}
-	return 0;
+
+	/* if there's no signal to deliver, we just put the saved sigmask
+	 * back */
+	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+		clear_thread_flag(TIF_RESTORE_SIGMASK);
+		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+	}
 }
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 55ddd80..221de38 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -50,6 +50,18 @@
 #include <asm/mca.h>
 
 /*
+ * Note: alignment of 4 entries/cacheline was empirically determined
+ * to be a good tradeoff between hot cachelines & spreading the array
+ * across too many cacheline.
+ */
+static struct local_tlb_flush_counts {
+	unsigned int count;
+} __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS];
+
+static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
+
+
+/*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
  * requirements. It also looks cleaner.
  */
@@ -248,6 +260,62 @@
 	platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
 }
 
+/*
+ * Called with preeemption disabled.
+ */
+static void
+smp_send_local_flush_tlb (int cpu)
+{
+	platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0);
+}
+
+void
+smp_local_flush_tlb(void)
+{
+	/*
+	 * Use atomic ops. Otherwise, the load/increment/store sequence from
+	 * a "++" operation can have the line stolen between the load & store.
+	 * The overhead of the atomic op in negligible in this case & offers
+	 * significant benefit for the brief periods where lots of cpus
+	 * are simultaneously flushing TLBs.
+	 */
+	ia64_fetchadd(1, &local_tlb_flush_counts[smp_processor_id()].count, acq);
+	local_flush_tlb_all();
+}
+
+#define FLUSH_DELAY	5 /* Usec backoff to eliminate excessive cacheline bouncing */
+
+void
+smp_flush_tlb_cpumask(cpumask_t xcpumask)
+{
+	unsigned int *counts = __ia64_per_cpu_var(shadow_flush_counts);
+	cpumask_t cpumask = xcpumask;
+	int mycpu, cpu, flush_mycpu = 0;
+
+	preempt_disable();
+	mycpu = smp_processor_id();
+
+	for_each_cpu_mask(cpu, cpumask)
+		counts[cpu] = local_tlb_flush_counts[cpu].count;
+
+	mb();
+	for_each_cpu_mask(cpu, cpumask) {
+		if (cpu == mycpu)
+			flush_mycpu = 1;
+		else
+			smp_send_local_flush_tlb(cpu);
+	}
+
+	if (flush_mycpu)
+		smp_local_flush_tlb();
+
+	for_each_cpu_mask(cpu, cpumask)
+		while(counts[cpu] == local_tlb_flush_counts[cpu].count)
+			udelay(FLUSH_DELAY);
+
+	preempt_enable();
+}
+
 void
 smp_flush_tlb_all (void)
 {
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 687500d..94ae3c8 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -412,9 +412,11 @@
 	sys_dev = get_cpu_sysdev(cpu);
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		cache_add_dev(sys_dev);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		cache_remove_dev(sys_dev);
 		break;
 	}
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 5bfb8be..b8e0d70 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -43,9 +43,9 @@
 		u32 lock_owner;
 		int lock_owner_depth;
 	} die = {
-		.lock =			SPIN_LOCK_UNLOCKED,
-		.lock_owner =		-1,
-		.lock_owner_depth =	0
+		.lock =	__SPIN_LOCK_UNLOCKED(die.lock),
+		.lock_owner = -1,
+		.lock_owner_depth = 0
 	};
 	static int die_counter;
 	int cpu = get_cpu();
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
index 93d5a3b..fe14262 100644
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -60,6 +60,7 @@
 #  define UNW_DEBUG_ON(n)	unw_debug_level >= n
    /* Do not code a printk level, not all debug lines end in newline */
 #  define UNW_DPRINT(n, ...)  if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__)
+#  undef inline
 #  define inline
 #else /* !UNW_DEBUG */
 #  define UNW_DEBUG_ON(n)  0
@@ -145,7 +146,7 @@
 # endif
 } unw = {
 	.tables = &unw.kernel_table,
-	.lock = SPIN_LOCK_UNLOCKED,
+	.lock = __SPIN_LOCK_UNLOCKED(unw.lock),
 	.save_order = {
 		UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
 		UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
@@ -1943,9 +1944,9 @@
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-	unsigned long ip, sp, pr = 0;
+	unsigned long ip, sp, pr = info->pr;
 
-	while (unw_unwind(info) >= 0) {
+	do {
 		unw_get_sp(info, &sp);
 		if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)
 		    < IA64_PT_REGS_SIZE) {
@@ -1963,7 +1964,7 @@
 				__FUNCTION__, ip);
 			return -1;
 		}
-	}
+	} while (unw_unwind(info) >= 0);
 	unw_get_ip(info, &ip);
 	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",
 		   __FUNCTION__, ip);
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index ffad762..fa4e6d4 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -32,9 +32,9 @@
 } purge;
 
 struct ia64_ctx ia64_ctx = {
-	.lock =		SPIN_LOCK_UNLOCKED,
-	.next =		1,
-	.max_ctx =	~0U
+	.lock =	__SPIN_LOCK_UNLOCKED(ia64_ctx.lock),
+	.next =	1,
+	.max_ctx = ~0U
 };
 
 DEFINE_PER_CPU(u8, ia64_need_tlb_flush);
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 8d2a1bf..7f6d236 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -59,6 +59,22 @@
 			(u64) sn_irq_info->irq_cookie, 0, 0);
 }
 
+u64 sn_intr_redirect(nasid_t local_nasid, int local_widget,
+		      struct sn_irq_info *sn_irq_info,
+		      nasid_t req_nasid, int req_slice)
+{
+	struct ia64_sal_retval ret_stuff;
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
+			(u64) SAL_INTR_REDIRECT, (u64) local_nasid,
+			(u64) local_widget, __pa(sn_irq_info),
+			(u64) req_nasid, (u64) req_slice, 0);
+
+	return ret_stuff.status;
+}
+
 static unsigned int sn_startup_irq(unsigned int irq)
 {
 	return 0;
@@ -127,15 +143,8 @@
 	struct sn_irq_info *new_irq_info;
 	struct sn_pcibus_provider *pci_provider;
 
-	new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
-	if (new_irq_info == NULL)
-		return NULL;
-
-	memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
-
-	bridge = (u64) new_irq_info->irq_bridge;
+	bridge = (u64) sn_irq_info->irq_bridge;
 	if (!bridge) {
-		kfree(new_irq_info);
 		return NULL; /* irq is not a device interrupt */
 	}
 
@@ -145,8 +154,25 @@
 		local_widget = TIO_SWIN_WIDGETNUM(bridge);
 	else
 		local_widget = SWIN_WIDGETNUM(bridge);
-
 	vector = sn_irq_info->irq_irq;
+
+	/* Make use of SAL_INTR_REDIRECT if PROM supports it */
+	status = sn_intr_redirect(local_nasid, local_widget, sn_irq_info, nasid, slice);
+	if (!status) {
+		new_irq_info = sn_irq_info;
+		goto finish_up;
+	}
+
+	/*
+	 * PROM does not support SAL_INTR_REDIRECT, or it failed.
+	 * Revert to old method.
+	 */
+	new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+	if (new_irq_info == NULL)
+		return NULL;
+
+	memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
 	/* Free the old PROM new_irq_info structure */
 	sn_intr_free(local_nasid, local_widget, new_irq_info);
 	unregister_intr_pda(new_irq_info);
@@ -162,11 +188,18 @@
 		return NULL;
 	}
 
+	register_intr_pda(new_irq_info);
+	spin_lock(&sn_irq_info_lock);
+	list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+	spin_unlock(&sn_irq_info_lock);
+	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+
+
+finish_up:
 	/* Update kernels new_irq_info with new target info */
 	cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid,
 				     new_irq_info->irq_slice);
 	new_irq_info->irq_cpuid = cpuid;
-	register_intr_pda(new_irq_info);
 
 	pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
 
@@ -178,11 +211,6 @@
 	    pci_provider && pci_provider->target_interrupt)
 		(pci_provider->target_interrupt)(new_irq_info);
 
-	spin_lock(&sn_irq_info_lock);
-	list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
-	spin_unlock(&sn_irq_info_lock);
-	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
-
 #ifdef CONFIG_SMP
 	cpuphys = cpu_physical_id(cpuid);
 	set_irq_affinity_info((vector & 0xff), cpuphys, 0);
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index 601747b..5d318b5 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -46,6 +46,9 @@
 
 static  __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
 
+/* 0 = old algorithm (no IPI flushes), 1 = ipi deadlock flush, 2 = ipi instead of SHUB ptc, >2 = always ipi */
+static int sn2_flush_opt = 0;
+
 extern unsigned long
 sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
 			       volatile unsigned long *, unsigned long,
@@ -76,6 +79,8 @@
 	unsigned long shub_itc_clocks;
 	unsigned long shub_itc_clocks_max;
 	unsigned long shub_ptc_flushes_not_my_mm;
+	unsigned long shub_ipi_flushes;
+	unsigned long shub_ipi_flushes_itc_clocks;
 };
 
 #define sn2_ptctest	0
@@ -121,6 +126,18 @@
 		flush_tlb_mm(mm);
 }
 
+static void
+sn2_ipi_flush_all_tlb(struct mm_struct *mm)
+{
+	unsigned long itc;
+
+	itc = ia64_get_itc();
+	smp_flush_tlb_cpumask(mm->cpu_vm_mask);
+	itc = ia64_get_itc() - itc;
+	__get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc;
+	__get_cpu_var(ptcstats).shub_ipi_flushes++;
+}
+
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
  * @mm: mm_struct containing virtual address range
@@ -154,7 +171,12 @@
 	unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0;
 	short nasids[MAX_NUMNODES], nix;
 	nodemask_t nodes_flushed;
-	int active, max_active, deadlock;
+	int active, max_active, deadlock, flush_opt = sn2_flush_opt;
+
+	if (flush_opt > 2) {
+		sn2_ipi_flush_all_tlb(mm);
+		return;
+	}
 
 	nodes_clear(nodes_flushed);
 	i = 0;
@@ -189,6 +211,12 @@
 		return;
 	}
 
+	if (flush_opt == 2) {
+		sn2_ipi_flush_all_tlb(mm);
+		preempt_enable();
+		return;
+	}
+
 	itc = ia64_get_itc();
 	nix = 0;
 	for_each_node_mask(cnode, nodes_flushed)
@@ -256,6 +284,8 @@
 			}
 			if (active >= max_active || i == (nix - 1)) {
 				if ((deadlock = wait_piowc())) {
+					if (flush_opt == 1)
+						goto done;
 					sn2_ptc_deadlock_recovery(nasids, ibegin, i, mynasid, ptc0, data0, ptc1, data1);
 					if (reset_max_active_on_deadlock())
 						max_active = 1;
@@ -267,6 +297,7 @@
 		start += (1UL << nbits);
 	} while (start < end);
 
+done:
 	itc2 = ia64_get_itc() - itc2;
 	__get_cpu_var(ptcstats).shub_itc_clocks += itc2;
 	if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
@@ -279,6 +310,11 @@
 
 	spin_unlock_irqrestore(PTC_LOCK(shub1), flags);
 
+	if (flush_opt == 1 && deadlock) {
+		__get_cpu_var(ptcstats).deadlocks++;
+		sn2_ipi_flush_all_tlb(mm);
+	}
+
 	preempt_enable();
 }
 
@@ -425,24 +461,42 @@
 
 	if (!cpu) {
 		seq_printf(file,
-			   "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2\n");
-		seq_printf(file, "# ptctest %d\n", sn2_ptctest);
+			   "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2 ipi_fluches ipi_nsec\n");
+		seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
 	}
 
 	if (cpu < NR_CPUS && cpu_online(cpu)) {
 		stat = &per_cpu(ptcstats, cpu);
-		seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
+		seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
 				stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
 				stat->deadlocks,
 				1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
 				1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
 				1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec,
 				stat->shub_ptc_flushes_not_my_mm,
-				stat->deadlocks2);
+				stat->deadlocks2,
+				stat->shub_ipi_flushes,
+				1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec);
 	}
 	return 0;
 }
 
+static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, size_t count, loff_t *data)
+{
+	int cpu;
+	char optstr[64];
+
+	if (copy_from_user(optstr, user, count))
+		return -EFAULT;
+	optstr[count - 1] = '\0';
+	sn2_flush_opt = simple_strtoul(optstr, NULL, 0);
+
+	for_each_online_cpu(cpu)
+		memset(&per_cpu(ptcstats, cpu), 0, sizeof(struct ptc_stats));
+
+	return count;
+}
+
 static struct seq_operations sn2_ptc_seq_ops = {
 	.start = sn2_ptc_seq_start,
 	.next = sn2_ptc_seq_next,
@@ -458,6 +512,7 @@
 static const struct file_operations proc_sn2_ptc_operations = {
 	.open = sn2_ptc_proc_open,
 	.read = seq_read,
+	.write = sn2_ptc_proc_write,
 	.llseek = seq_lseek,
 	.release = seq_release,
 };
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug
index 763c9aa..9ff47bd 100644
--- a/arch/m68knommu/Kconfig.debug
+++ b/arch/m68knommu/Kconfig.debug
@@ -5,7 +5,7 @@
 config FULLDEBUG
 	bool "Full Symbolic/Source Debugging support"
 	help
-	  Enable debuging symbols on kernel build.
+	  Enable debugging symbols on kernel build.
 
 config HIGHPROFILE
 	bool "Use fast second timer for profiling"
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index b988c7b..7cd183d 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -31,7 +31,7 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b7cb048..16ecea3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -956,7 +956,7 @@
 	  byte order. These modes require different kernels and a different
 	  Linux distribution.  In general there is one preferred byteorder for a
 	  particular system but some systems are just as commonly used in the
-	  one or the other endianess.
+	  one or the other endianness.
 
 config CPU_BIG_ENDIAN
 	bool "Big endian"
@@ -1750,7 +1750,7 @@
 	bool
 	default y if SGI_IP27
 	help
-	  Say Y to upport efficient handling of discontiguous physical memory,
+	  Say Y to support efficient handling of discontiguous physical memory,
 	  for architectures which are either NUMA (Non-Uniform Memory Access)
 	  or have huge holes in the physical address space for other reasons.
 	  See <file:Documentation/vm/numa> for more.
@@ -1938,7 +1938,7 @@
 	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
+	  but it is independent 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.
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index f2f742d..4892db8 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -92,7 +92,7 @@
 # when fed the toolchain default!
 #
 # Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of
-# 2006-10-10 don't properly change the the predefined symbols if -EB / -EL
+# 2006-10-10 don't properly change the predefined symbols if -EB / -EL
 # are used, so we kludge that here.  A bug has been filed at
 # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413.
 #
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 761a779..3b27309 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -82,7 +82,7 @@
 {
 	text("/* MIPS task_struct offsets. */");
 	offset("#define TASK_STATE         ", struct task_struct, state);
-	offset("#define TASK_THREAD_INFO   ", struct task_struct, thread_info);
+	offset("#define TASK_THREAD_INFO   ", struct task_struct, stack);
 	offset("#define TASK_FLAGS         ", struct task_struct, flags);
 	offset("#define TASK_MM            ", struct task_struct, mm);
 	offset("#define TASK_PID           ", struct task_struct, pid);
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 5dcfab6..b361edb 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -560,7 +560,7 @@
 	write_tc_gpr_sp(__KSTK_TOS(idle));
 
 	/* global pointer */
-	write_tc_gpr_gp((unsigned long)idle->thread_info);
+	write_tc_gpr_gp((unsigned long)task_thread_info(idle));
 
 	smtc_status |= SMTC_MTC_ACTIVE;
 	write_tc_c0_tchalt(0);
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
index 7a74448..0ad39e5 100644
--- a/arch/mips/pci/fixup-sb1250.c
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -14,7 +14,7 @@
 #include <linux/pci.h>
 
 /*
- * Set the the BCM1250, etc. PCI host bridge's TRDY timeout
+ * Set the BCM1250, etc. PCI host bridge's TRDY timeout
  * to the finite max.
  */
 static void __init quirk_sb1250_pci(struct pci_dev *dev)
@@ -35,7 +35,7 @@
 			quirk_sb1250_ht);
 
 /*
- * Set the the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
+ * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
  */
 static void __init quirk_sp1011(struct pci_dev *dev)
 {
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index 54fdb95..d3b7917 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -54,7 +54,7 @@
 
 int main(void)
 {
-	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 808d2ef..ccc5410 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -120,19 +120,6 @@
 config SYS_SUPPORTS_APM_EMULATION
 	bool
 
-#
-# Powerpc uses the slab allocator to manage its ptes and the
-# page structs of ptes are used for splitting the page table
-# lock for configurations supporting more than SPLIT_PTLOCK_CPUS.
-#
-# In that special configuration the page structs of slabs are modified.
-# This setting disables the selection of SLUB as a slab allocator.
-#
-config ARCH_USES_SLAB_PAGE_STRUCT
-	bool
-	default y
-	depends on SPLIT_PTLOCK_CPUS <= NR_CPUS
-
 config DEFAULT_UIMAGE
 	bool
 	help
@@ -352,6 +339,11 @@
 	def_bool y
 	depends on PPC_STD_MMU && PPC32
 
+config PPC_MM_SLICES
+	bool
+	default y if HUGETLB_PAGE
+	default n
+
 config VIRT_CPU_ACCOUNTING
 	bool "Deterministic task and CPU time accounting"
 	depends on PPC64
@@ -541,9 +533,15 @@
 	def_bool y
 	depends on NEED_MULTIPLE_NODES
 
+config PPC_HAS_HASH_64K
+	bool
+	depends on PPC64
+	default n
+
 config PPC_64K_PAGES
 	bool "64k page size"
 	depends on PPC64
+	select PPC_HAS_HASH_64K
 	help
 	  This option changes the kernel logical page size to 64k. On machines
 	  without processor support for 64k pages, the kernel will simulate
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index f70e795..346cd3b 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -32,7 +32,7 @@
 	depends on PPC_PSERIES && DEBUG_FS
 	help
 	  Adds code to keep track of the number of hypervisor calls made and
-	  the amount of time spent in hypervisor callsr.  Wall time spent in
+	  the amount of time spent in hypervisor calls.  Wall time spent in
 	  each call is always calculated, and if available CPU cycles spent
 	  are also calculated.  A directory named hcall_inst is added at the
 	  root of the debugfs filesystem.  Within the hcall_inst directory
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8f48560..2cb1d948 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -58,7 +58,7 @@
 #ifdef CONFIG_PPC64
 	DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
 #else
-	DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
 #endif /* CONFIG_PPC64 */
 
@@ -122,12 +122,18 @@
 	DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
 	DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
-	DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
 	DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp));
-#ifdef CONFIG_HUGETLB_PAGE
-	DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
-	DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
-#endif /* CONFIG_HUGETLB_PAGE */
+#ifdef CONFIG_PPC_MM_SLICES
+	DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
+					    context.low_slices_psize));
+	DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct,
+					    context.high_slices_psize));
+	DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
+	DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp));
+#else
+	DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+
+#endif /* CONFIG_PPC_MM_SLICES */
 	DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
 	DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
 	DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c
index 584d1e3..af11285 100644
--- a/arch/powerpc/kernel/lparmap.c
+++ b/arch/powerpc/kernel/lparmap.c
@@ -10,7 +10,8 @@
 #include <asm/pgtable.h>
 #include <asm/iseries/lpar_map.h>
 
-const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
+/* The # is to stop gcc trying to make .text nonexecutable */
+const struct LparMap __attribute__((__section__(".text #"))) xLparMap = {
 	.xNumberEsids = HvEsidsToMap,
 	.xNumberRanges = HvRangesToMap,
 	.xSegmentTableOffs = STAB0_PAGE,
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index cae39d9..68991c2 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -342,10 +342,12 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		register_cpu_online(cpu);
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		unregister_cpu_online(cpu);
 		break;
 #endif
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 38a81967..4f839c6 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -18,4 +18,5 @@
 obj-$(CONFIG_44x)		+= 44x_mmu.o
 obj-$(CONFIG_FSL_BOOKE)		+= fsl_booke_mmu.o
 obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
+obj-$(CONFIG_PPC_MM_SLICES)	+= slice.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index e64ce3e..4762ff7 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -615,6 +615,9 @@
 	li	r3,-1
 	b	htab_bail
 
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
 
 /*****************************************************************************
  *                                                                           *
@@ -870,7 +873,7 @@
 	b	ht64_bail
 
 
-#endif /* CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC_HAS_HASH_64K */
 
 
 /*****************************************************************************
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 9b226fa..028ba4e 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -51,6 +51,7 @@
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
 #include <asm/sections.h>
+#include <asm/spu.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -419,7 +420,7 @@
 	extern unsigned int *htab_call_hpte_remove;
 	extern unsigned int *htab_call_hpte_updatepp;
 
-#ifdef CONFIG_PPC_64K_PAGES
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	extern unsigned int *ht64_call_hpte_insert1;
 	extern unsigned int *ht64_call_hpte_insert2;
 	extern unsigned int *ht64_call_hpte_remove;
@@ -596,22 +597,23 @@
  * Demote a segment to using 4k pages.
  * For now this makes the whole process use 4k pages.
  */
-void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
-{
 #ifdef CONFIG_PPC_64K_PAGES
+static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
 	if (mm->context.user_psize == MMU_PAGE_4K)
 		return;
+#ifdef CONFIG_PPC_MM_SLICES
+	slice_set_user_psize(mm, MMU_PAGE_4K);
+#else /* CONFIG_PPC_MM_SLICES */
 	mm->context.user_psize = MMU_PAGE_4K;
 	mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
-	get_paca()->context = mm->context;
-	slb_flush_and_rebolt();
+#endif /* CONFIG_PPC_MM_SLICES */
+
 #ifdef CONFIG_SPE_BASE
 	spu_flush_all_slbs(mm);
 #endif
-#endif
 }
-
-EXPORT_SYMBOL_GPL(demote_segment_4k);
+#endif /* CONFIG_PPC_64K_PAGES */
 
 /* Result code is:
  *  0 - handled
@@ -646,7 +648,11 @@
 			return 1;
 		}
 		vsid = get_vsid(mm->context.id, ea);
+#ifdef CONFIG_PPC_MM_SLICES
+		psize = get_slice_psize(mm, ea);
+#else
 		psize = mm->context.user_psize;
+#endif
 		break;
 	case VMALLOC_REGION_ID:
 		mm = &init_mm;
@@ -674,11 +680,22 @@
 	if (user_region && cpus_equal(mm->cpu_vm_mask, tmp))
 		local = 1;
 
+#ifdef CONFIG_HUGETLB_PAGE
 	/* Handle hugepage regions */
-	if (unlikely(in_hugepage_area(mm->context, ea))) {
+	if (HPAGE_SHIFT && psize == mmu_huge_psize) {
 		DBG_LOW(" -> huge page !\n");
 		return hash_huge_page(mm, access, ea, vsid, local, trap);
 	}
+#endif /* CONFIG_HUGETLB_PAGE */
+
+#ifndef CONFIG_PPC_64K_PAGES
+	/* If we use 4K pages and our psize is not 4K, then we are hitting
+	 * a special driver mapping, we need to align the address before
+	 * we fetch the PTE
+	 */
+	if (psize != MMU_PAGE_4K)
+		ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
+#endif /* CONFIG_PPC_64K_PAGES */
 
 	/* Get PTE and page size from page tables */
 	ptep = find_linux_pte(pgdir, ea);
@@ -702,54 +719,56 @@
 	}
 
 	/* Do actual hashing */
-#ifndef CONFIG_PPC_64K_PAGES
-	rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+#ifdef CONFIG_PPC_64K_PAGES
 	/* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
 	if (pte_val(*ptep) & _PAGE_4K_PFN) {
 		demote_segment_4k(mm, ea);
 		psize = MMU_PAGE_4K;
 	}
 
-	if (mmu_ci_restrictions) {
-		/* If this PTE is non-cacheable, switch to 4k */
-		if (psize == MMU_PAGE_64K &&
-		    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
-			if (user_region) {
-				demote_segment_4k(mm, ea);
-				psize = MMU_PAGE_4K;
-			} else if (ea < VMALLOC_END) {
-				/*
-				 * some driver did a non-cacheable mapping
-				 * in vmalloc space, so switch vmalloc
-				 * to 4k pages
-				 */
-				printk(KERN_ALERT "Reducing vmalloc segment "
-				       "to 4kB pages because of "
-				       "non-cacheable mapping\n");
-				psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-			}
+	/* If this PTE is non-cacheable and we have restrictions on
+	 * using non cacheable large pages, then we switch to 4k
+	 */
+	if (mmu_ci_restrictions && psize == MMU_PAGE_64K &&
+	    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+		if (user_region) {
+			demote_segment_4k(mm, ea);
+			psize = MMU_PAGE_4K;
+		} else if (ea < VMALLOC_END) {
+			/*
+			 * some driver did a non-cacheable mapping
+			 * in vmalloc space, so switch vmalloc
+			 * to 4k pages
+			 */
+			printk(KERN_ALERT "Reducing vmalloc segment "
+			       "to 4kB pages because of "
+			       "non-cacheable mapping\n");
+			psize = mmu_vmalloc_psize = MMU_PAGE_4K;
 #ifdef CONFIG_SPE_BASE
 			spu_flush_all_slbs(mm);
 #endif
 		}
-		if (user_region) {
-			if (psize != get_paca()->context.user_psize) {
-				get_paca()->context = mm->context;
-				slb_flush_and_rebolt();
-			}
-		} else if (get_paca()->vmalloc_sllp !=
-			   mmu_psize_defs[mmu_vmalloc_psize].sllp) {
-			get_paca()->vmalloc_sllp =
-				mmu_psize_defs[mmu_vmalloc_psize].sllp;
+	}
+	if (user_region) {
+		if (psize != get_paca()->context.user_psize) {
+			get_paca()->context.user_psize =
+				mm->context.user_psize;
 			slb_flush_and_rebolt();
 		}
+	} else if (get_paca()->vmalloc_sllp !=
+		   mmu_psize_defs[mmu_vmalloc_psize].sllp) {
+		get_paca()->vmalloc_sllp =
+			mmu_psize_defs[mmu_vmalloc_psize].sllp;
+		slb_flush_and_rebolt();
 	}
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	if (psize == MMU_PAGE_64K)
 		rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else
+#endif /* CONFIG_PPC_HAS_HASH_64K */
 		rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#endif /* CONFIG_PPC_64K_PAGES */
 
 #ifndef CONFIG_PPC_64K_PAGES
 	DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -772,42 +791,55 @@
 	unsigned long flags;
 	int local = 0;
 
-	/* We don't want huge pages prefaulted for now
-	 */
-	if (unlikely(in_hugepage_area(mm->context, ea)))
+	BUG_ON(REGION_ID(ea) != USER_REGION_ID);
+
+#ifdef CONFIG_PPC_MM_SLICES
+	/* We only prefault standard pages for now */
+	if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize));
 		return;
+#endif
 
 	DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
 		" trap=%lx\n", mm, mm->pgd, ea, access, trap);
 
-	/* Get PTE, VSID, access mask */
+	/* Get Linux PTE if available */
 	pgdir = mm->pgd;
 	if (pgdir == NULL)
 		return;
 	ptep = find_linux_pte(pgdir, ea);
 	if (!ptep)
 		return;
+
+#ifdef CONFIG_PPC_64K_PAGES
+	/* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
+	 * a 64K kernel), then we don't preload, hash_page() will take
+	 * care of it once we actually try to access the page.
+	 * That way we don't have to duplicate all of the logic for segment
+	 * page size demotion here
+	 */
+	if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
+		return;
+#endif /* CONFIG_PPC_64K_PAGES */
+
+	/* Get VSID */
 	vsid = get_vsid(mm->context.id, ea);
 
-	/* Hash it in */
+	/* Hash doesn't like irqs */
 	local_irq_save(flags);
+
+	/* Is that local to this CPU ? */
 	mask = cpumask_of_cpu(smp_processor_id());
 	if (cpus_equal(mm->cpu_vm_mask, mask))
 		local = 1;
-#ifndef CONFIG_PPC_64K_PAGES
-	__hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
-	if (mmu_ci_restrictions) {
-		/* If this PTE is non-cacheable, switch to 4k */
-		if (mm->context.user_psize == MMU_PAGE_64K &&
-		    (pte_val(*ptep) & _PAGE_NO_CACHE))
-			demote_segment_4k(mm, ea);
-	}
+
+	/* Hash it in */
+#ifdef CONFIG_PPC_HAS_HASH_64K
 	if (mm->context.user_psize == MMU_PAGE_64K)
 		__hash_page_64K(ea, access, vsid, ptep, trap, local);
 	else
-		__hash_page_4K(ea, access, vsid, ptep, trap, local);
 #endif /* CONFIG_PPC_64K_PAGES */
+		__hash_page_4K(ea, access, vsid, ptep, trap, local);
+
 	local_irq_restore(flags);
 }
 
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index fb95926..92a1b16 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -91,7 +91,7 @@
 	pgd_t *pg;
 	pud_t *pu;
 
-	BUG_ON(! in_hugepage_area(mm->context, addr));
+	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
 	addr &= HPAGE_MASK;
 
@@ -119,7 +119,7 @@
 	pud_t *pu;
 	hugepd_t *hpdp = NULL;
 
-	BUG_ON(! in_hugepage_area(mm->context, addr));
+	BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
 	addr &= HPAGE_MASK;
 
@@ -302,7 +302,7 @@
 	start = addr;
 	pgd = pgd_offset((*tlb)->mm, addr);
 	do {
-		BUG_ON(! in_hugepage_area((*tlb)->mm->context, addr));
+		BUG_ON(get_slice_psize((*tlb)->mm, addr) != mmu_huge_psize);
 		next = pgd_addr_end(addr, end);
 		if (pgd_none_or_clear_bad(pgd))
 			continue;
@@ -331,203 +331,13 @@
 	return __pte(old);
 }
 
-struct slb_flush_info {
-	struct mm_struct *mm;
-	u16 newareas;
-};
-
-static void flush_low_segments(void *parm)
-{
-	struct slb_flush_info *fi = parm;
-	unsigned long i;
-
-	BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_LOW_AREAS);
-
-	if (current->active_mm != fi->mm)
-		return;
-
-	/* Only need to do anything if this CPU is working in the same
-	 * mm as the one which has changed */
-
-	/* update the paca copy of the context struct */
-	get_paca()->context = current->active_mm->context;
-
-	asm volatile("isync" : : : "memory");
-	for (i = 0; i < NUM_LOW_AREAS; i++) {
-		if (! (fi->newareas & (1U << i)))
-			continue;
-		asm volatile("slbie %0"
-			     : : "r" ((i << SID_SHIFT) | SLBIE_C));
-	}
-	asm volatile("isync" : : : "memory");
-}
-
-static void flush_high_segments(void *parm)
-{
-	struct slb_flush_info *fi = parm;
-	unsigned long i, j;
-
-
-	BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_HIGH_AREAS);
-
-	if (current->active_mm != fi->mm)
-		return;
-
-	/* Only need to do anything if this CPU is working in the same
-	 * mm as the one which has changed */
-
-	/* update the paca copy of the context struct */
-	get_paca()->context = current->active_mm->context;
-
-	asm volatile("isync" : : : "memory");
-	for (i = 0; i < NUM_HIGH_AREAS; i++) {
-		if (! (fi->newareas & (1U << i)))
-			continue;
-		for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
-			asm volatile("slbie %0"
-				     :: "r" (((i << HTLB_AREA_SHIFT)
-					      + (j << SID_SHIFT)) | SLBIE_C));
-	}
-	asm volatile("isync" : : : "memory");
-}
-
-static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-	unsigned long start = area << SID_SHIFT;
-	unsigned long end = (area+1) << SID_SHIFT;
-	struct vm_area_struct *vma;
-
-	BUG_ON(area >= NUM_LOW_AREAS);
-
-	/* Check no VMAs are in the region */
-	vma = find_vma(mm, start);
-	if (vma && (vma->vm_start < end))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-	unsigned long start = area << HTLB_AREA_SHIFT;
-	unsigned long end = (area+1) << HTLB_AREA_SHIFT;
-	struct vm_area_struct *vma;
-
-	BUG_ON(area >= NUM_HIGH_AREAS);
-
-	/* Hack, so that each addresses is controlled by exactly one
-	 * of the high or low area bitmaps, the first high area starts
-	 * at 4GB, not 0 */
-	if (start == 0)
-		start = 0x100000000UL;
-
-	/* Check no VMAs are in the region */
-	vma = find_vma(mm, start);
-	if (vma && (vma->vm_start < end))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-	unsigned long i;
-	struct slb_flush_info fi;
-
-	BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
-	BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
-
-	newareas &= ~(mm->context.low_htlb_areas);
-	if (! newareas)
-		return 0; /* The segments we want are already open */
-
-	for (i = 0; i < NUM_LOW_AREAS; i++)
-		if ((1 << i) & newareas)
-			if (prepare_low_area_for_htlb(mm, i) != 0)
-				return -EBUSY;
-
-	mm->context.low_htlb_areas |= newareas;
-
-	/* the context change must make it to memory before the flush,
-	 * so that further SLB misses do the right thing. */
-	mb();
-
-	fi.mm = mm;
-	fi.newareas = newareas;
-	on_each_cpu(flush_low_segments, &fi, 0, 1);
-
-	return 0;
-}
-
-static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-	struct slb_flush_info fi;
-	unsigned long i;
-
-	BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
-	BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
-		     != NUM_HIGH_AREAS);
-
-	newareas &= ~(mm->context.high_htlb_areas);
-	if (! newareas)
-		return 0; /* The areas we want are already open */
-
-	for (i = 0; i < NUM_HIGH_AREAS; i++)
-		if ((1 << i) & newareas)
-			if (prepare_high_area_for_htlb(mm, i) != 0)
-				return -EBUSY;
-
-	mm->context.high_htlb_areas |= newareas;
-
-	/* the context change must make it to memory before the flush,
-	 * so that further SLB misses do the right thing. */
-	mb();
-
-	fi.mm = mm;
-	fi.newareas = newareas;
-	on_each_cpu(flush_high_segments, &fi, 0, 1);
-
-	return 0;
-}
-
-int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff)
-{
-	int err = 0;
-
-	if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT))
-		return -EINVAL;
-	if (len & ~HPAGE_MASK)
-		return -EINVAL;
-	if (addr & ~HPAGE_MASK)
-		return -EINVAL;
-
-	if (addr < 0x100000000UL)
-		err = open_low_hpage_areas(current->mm,
-					  LOW_ESID_MASK(addr, len));
-	if ((addr + len) > 0x100000000UL)
-		err = open_high_hpage_areas(current->mm,
-					    HTLB_AREA_MASK(addr, len));
-#ifdef CONFIG_SPE_BASE
-	spu_flush_all_slbs(current->mm);
-#endif
-	if (err) {
-		printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
-		       " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
-		       addr, len,
-		       LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
-		return err;
-	}
-
-	return 0;
-}
-
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
 {
 	pte_t *ptep;
 	struct page *page;
 
-	if (! in_hugepage_area(mm->context, address))
+	if (get_slice_psize(mm, address) != mmu_huge_psize)
 		return ERR_PTR(-EINVAL);
 
 	ptep = huge_pte_offset(mm, address);
@@ -551,359 +361,13 @@
 	return NULL;
 }
 
-/* Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions. */
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-				     unsigned long len, unsigned long pgoff,
-				     unsigned long flags)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-	unsigned long start_addr;
-
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	/* handle fixed mapping: prevent overlap with huge pages */
-	if (flags & MAP_FIXED) {
-		if (is_hugepage_only_range(mm, addr, len))
-			return -EINVAL;
-		return addr;
-	}
-
-	if (addr) {
-		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (((TASK_SIZE - len) >= addr)
-		    && (!vma || (addr+len) <= vma->vm_start)
-		    && !is_hugepage_only_range(mm, addr,len))
-			return addr;
-	}
-	if (len > mm->cached_hole_size) {
-	        start_addr = addr = mm->free_area_cache;
-	} else {
-	        start_addr = addr = TASK_UNMAPPED_BASE;
-	        mm->cached_hole_size = 0;
-	}
-
-full_search:
-	vma = find_vma(mm, addr);
-	while (TASK_SIZE - len >= addr) {
-		BUG_ON(vma && (addr >= vma->vm_end));
-
-		if (touches_hugepage_low_range(mm, addr, len)) {
-			addr = ALIGN(addr+1, 1<<SID_SHIFT);
-			vma = find_vma(mm, addr);
-			continue;
-		}
-		if (touches_hugepage_high_range(mm, addr, len)) {
-			addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-			vma = find_vma(mm, addr);
-			continue;
-		}
-		if (!vma || addr + len <= vma->vm_start) {
-			/*
-			 * Remember the place where we stopped the search:
-			 */
-			mm->free_area_cache = addr + len;
-			return addr;
-		}
-		if (addr + mm->cached_hole_size < vma->vm_start)
-		        mm->cached_hole_size = vma->vm_start - addr;
-		addr = vma->vm_end;
-		vma = vma->vm_next;
-	}
-
-	/* Make sure we didn't miss any holes */
-	if (start_addr != TASK_UNMAPPED_BASE) {
-		start_addr = addr = TASK_UNMAPPED_BASE;
-		mm->cached_hole_size = 0;
-		goto full_search;
-	}
-	return -ENOMEM;
-}
-
-/*
- * This mmap-allocator allocates new areas top-down from below the
- * stack's low limit (the base):
- *
- * Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions.
- */
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
-			  const unsigned long len, const unsigned long pgoff,
-			  const unsigned long flags)
-{
-	struct vm_area_struct *vma, *prev_vma;
-	struct mm_struct *mm = current->mm;
-	unsigned long base = mm->mmap_base, addr = addr0;
-	unsigned long largest_hole = mm->cached_hole_size;
-	int first_time = 1;
-
-	/* requested length too big for entire address space */
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	/* handle fixed mapping: prevent overlap with huge pages */
-	if (flags & MAP_FIXED) {
-		if (is_hugepage_only_range(mm, addr, len))
-			return -EINVAL;
-		return addr;
-	}
-
-	/* dont allow allocations above current base */
-	if (mm->free_area_cache > base)
-		mm->free_area_cache = base;
-
-	/* requesting a specific address */
-	if (addr) {
-		addr = PAGE_ALIGN(addr);
-		vma = find_vma(mm, addr);
-		if (TASK_SIZE - len >= addr &&
-				(!vma || addr + len <= vma->vm_start)
-				&& !is_hugepage_only_range(mm, addr,len))
-			return addr;
-	}
-
-	if (len <= largest_hole) {
-	        largest_hole = 0;
-		mm->free_area_cache = base;
-	}
-try_again:
-	/* make sure it can fit in the remaining address space */
-	if (mm->free_area_cache < len)
-		goto fail;
-
-	/* either no address requested or cant fit in requested address hole */
-	addr = (mm->free_area_cache - len) & PAGE_MASK;
-	do {
-hugepage_recheck:
-		if (touches_hugepage_low_range(mm, addr, len)) {
-			addr = (addr & ((~0) << SID_SHIFT)) - len;
-			goto hugepage_recheck;
-		} else if (touches_hugepage_high_range(mm, addr, len)) {
-			addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
-			goto hugepage_recheck;
-		}
-
-		/*
-		 * Lookup failure means no vma is above this address,
-		 * i.e. return with success:
-		 */
- 	 	if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
-			return addr;
-
-		/*
-		 * new region fits between prev_vma->vm_end and
-		 * vma->vm_start, use it:
-		 */
-		if (addr+len <= vma->vm_start &&
-		          (!prev_vma || (addr >= prev_vma->vm_end))) {
-			/* remember the address as a hint for next time */
-		        mm->cached_hole_size = largest_hole;
-		        return (mm->free_area_cache = addr);
-		} else {
-			/* pull free_area_cache down to the first hole */
-		        if (mm->free_area_cache == vma->vm_end) {
-				mm->free_area_cache = vma->vm_start;
-				mm->cached_hole_size = largest_hole;
-			}
-		}
-
-		/* remember the largest hole we saw so far */
-		if (addr + largest_hole < vma->vm_start)
-		        largest_hole = vma->vm_start - addr;
-
-		/* try just below the current vma->vm_start */
-		addr = vma->vm_start-len;
-	} while (len <= vma->vm_start);
-
-fail:
-	/*
-	 * if hint left us with no space for the requested
-	 * mapping then try again:
-	 */
-	if (first_time) {
-		mm->free_area_cache = base;
-		largest_hole = 0;
-		first_time = 0;
-		goto try_again;
-	}
-	/*
-	 * A failed mmap() very likely causes application failure,
-	 * so fall back to the bottom-up function here. This scenario
-	 * can happen with large stack limits and large mmap()
-	 * allocations.
-	 */
-	mm->free_area_cache = TASK_UNMAPPED_BASE;
-	mm->cached_hole_size = ~0UL;
-	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
-	/*
-	 * Restore the topdown base:
-	 */
-	mm->free_area_cache = base;
-	mm->cached_hole_size = ~0UL;
-
-	return addr;
-}
-
-static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
-{
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	if (TASK_SIZE - len >= addr &&
-	    (!vma || ((addr + len) <= vma->vm_start)))
-		return 0;
-
-	return -ENOMEM;
-}
-
-static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
-{
-	unsigned long addr = 0;
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	while (addr + len <= 0x100000000UL) {
-		BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-		if (! __within_hugepage_low_range(addr, len, segmask)) {
-			addr = ALIGN(addr+1, 1<<SID_SHIFT);
-			vma = find_vma(current->mm, addr);
-			continue;
-		}
-
-		if (!vma || (addr + len) <= vma->vm_start)
-			return addr;
-		addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-		/* Depending on segmask this might not be a confirmed
-		 * hugepage region, so the ALIGN could have skipped
-		 * some VMAs */
-		vma = find_vma(current->mm, addr);
-	}
-
-	return -ENOMEM;
-}
-
-static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
-{
-	unsigned long addr = 0x100000000UL;
-	struct vm_area_struct *vma;
-
-	vma = find_vma(current->mm, addr);
-	while (addr + len <= TASK_SIZE_USER64) {
-		BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-		if (! __within_hugepage_high_range(addr, len, areamask)) {
-			addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-			vma = find_vma(current->mm, addr);
-			continue;
-		}
-
-		if (!vma || (addr + len) <= vma->vm_start)
-			return addr;
-		addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-		/* Depending on segmask this might not be a confirmed
-		 * hugepage region, so the ALIGN could have skipped
-		 * some VMAs */
-		vma = find_vma(current->mm, addr);
-	}
-
-	return -ENOMEM;
-}
 
 unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 					unsigned long len, unsigned long pgoff,
 					unsigned long flags)
 {
-	int lastshift;
-	u16 areamask, curareas;
-
-	if (HPAGE_SHIFT == 0)
-		return -EINVAL;
-	if (len & ~HPAGE_MASK)
-		return -EINVAL;
-	if (len > TASK_SIZE)
-		return -ENOMEM;
-
-	if (!cpu_has_feature(CPU_FTR_16M_PAGE))
-		return -EINVAL;
-
-	/* Paranoia, caller should have dealt with this */
-	BUG_ON((addr + len)  < addr);
-
-	/* Handle MAP_FIXED */
-	if (flags & MAP_FIXED) {
-		if (prepare_hugepage_range(addr, len, pgoff))
-			return -EINVAL;
-		return addr;
-	}
-
-	if (test_thread_flag(TIF_32BIT)) {
-		curareas = current->mm->context.low_htlb_areas;
-
-		/* First see if we can use the hint address */
-		if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
-			areamask = LOW_ESID_MASK(addr, len);
-			if (open_low_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-
-		/* Next see if we can map in the existing low areas */
-		addr = htlb_get_low_area(len, curareas);
-		if (addr != -ENOMEM)
-			return addr;
-
-		/* Finally go looking for areas to open */
-		lastshift = 0;
-		for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
-		     ! lastshift; areamask >>=1) {
-			if (areamask & 1)
-				lastshift = 1;
-
-			addr = htlb_get_low_area(len, curareas | areamask);
-			if ((addr != -ENOMEM)
-			    && open_low_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-	} else {
-		curareas = current->mm->context.high_htlb_areas;
-
-		/* First see if we can use the hint address */
-		/* We discourage 64-bit processes from doing hugepage
-		 * mappings below 4GB (must use MAP_FIXED) */
-		if ((addr >= 0x100000000UL)
-		    && (htlb_check_hinted_area(addr, len) == 0)) {
-			areamask = HTLB_AREA_MASK(addr, len);
-			if (open_high_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-
-		/* Next see if we can map in the existing high areas */
-		addr = htlb_get_high_area(len, curareas);
-		if (addr != -ENOMEM)
-			return addr;
-
-		/* Finally go looking for areas to open */
-		lastshift = 0;
-		for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
-		     ! lastshift; areamask >>=1) {
-			if (areamask & 1)
-				lastshift = 1;
-
-			addr = htlb_get_high_area(len, curareas | areamask);
-			if ((addr != -ENOMEM)
-			    && open_high_hpage_areas(current->mm, areamask) == 0)
-				return addr;
-		}
-	}
-	printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
-	       " enough areas\n");
-	return -ENOMEM;
+	return slice_get_unmapped_area(addr, len, flags,
+				       mmu_huge_psize, 1, 0);
 }
 
 /*
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index fe1fe85..7312a26 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -146,21 +146,16 @@
 	memset(addr, 0, kmem_cache_size(cache));
 }
 
-#ifdef CONFIG_PPC_64K_PAGES
-static const unsigned int pgtable_cache_size[3] = {
-	PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-	"pte_pmd_cache", "pmd_cache", "pgd_cache",
-};
-#else
 static const unsigned int pgtable_cache_size[2] = {
-	PTE_TABLE_SIZE, PMD_TABLE_SIZE
+	PGD_TABLE_SIZE, PMD_TABLE_SIZE
 };
 static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-	"pgd_pte_cache", "pud_pmd_cache",
-};
+#ifdef CONFIG_PPC_64K_PAGES
+	"pgd_cache", "pmd_cache",
+#else
+	"pgd_cache", "pud_pmd_cache",
 #endif /* CONFIG_PPC_64K_PAGES */
+};
 
 #ifdef CONFIG_HUGETLB_PAGE
 /* Hugepages need one extra cache, initialized in hugetlbpage.c.  We
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 1a6e08f..246eeea 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -31,6 +31,7 @@
 #include <linux/highmem.h>
 #include <linux/initrd.h>
 #include <linux/pagemap.h>
+#include <linux/suspend.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -276,6 +277,28 @@
 	init_bootmem_done = 1;
 }
 
+/* mark pages that don't exist as nosave */
+static int __init mark_nonram_nosave(void)
+{
+	unsigned long lmb_next_region_start_pfn,
+		      lmb_region_max_pfn;
+	int i;
+
+	for (i = 0; i < lmb.memory.cnt - 1; i++) {
+		lmb_region_max_pfn =
+			(lmb.memory.region[i].base >> PAGE_SHIFT) +
+			(lmb.memory.region[i].size >> PAGE_SHIFT);
+		lmb_next_region_start_pfn =
+			lmb.memory.region[i+1].base >> PAGE_SHIFT;
+
+		if (lmb_region_max_pfn < lmb_next_region_start_pfn)
+			register_nosave_region(lmb_region_max_pfn,
+					       lmb_next_region_start_pfn);
+	}
+
+	return 0;
+}
+
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
  */
@@ -307,6 +330,8 @@
 	max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
 #endif
 	free_area_init_nodes(max_zone_pfns);
+
+	mark_nonram_nosave();
 }
 #endif /* ! CONFIG_NEED_MULTIPLE_NODES */
 
diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c
index 90a06ac..7a78cdc 100644
--- a/arch/powerpc/mm/mmu_context_64.c
+++ b/arch/powerpc/mm/mmu_context_64.c
@@ -28,6 +28,7 @@
 {
 	int index;
 	int err;
+	int new_context = (mm->context.id == 0);
 
 again:
 	if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
@@ -50,9 +51,18 @@
 	}
 
 	mm->context.id = index;
+#ifdef CONFIG_PPC_MM_SLICES
+	/* The old code would re-promote on fork, we don't do that
+	 * when using slices as it could cause problem promoting slices
+	 * that have been forced down to 4K
+	 */
+	if (new_context)
+		slice_set_user_psize(mm, mmu_virtual_psize);
+#else
 	mm->context.user_psize = mmu_virtual_psize;
 	mm->context.sllp = SLB_VSID_USER |
 		mmu_psize_defs[mmu_virtual_psize].sllp;
+#endif
 
 	return 0;
 }
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index b3a592b..de45aa8 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -252,12 +252,15 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		numa_setup_cpu(lcpu);
 		ret = NOTIFY_OK;
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		unmap_cpu_from_node(lcpu);
 		break;
 		ret = NOTIFY_OK;
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 0506667..ec1421a 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -185,7 +185,7 @@
 
 	if (Hash == 0)
 		return;
-	pmd = pmd_offset(pgd_offset(mm, ea), ea);
+	pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea);
 	if (!pmd_none(*pmd))
 		add_hash_page(mm->context.id, ea, pmd_val(*pmd));
 }
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 224e960..304375a7 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -198,12 +198,6 @@
 	static int slb_encoding_inited;
 	extern unsigned int *slb_miss_kernel_load_linear;
 	extern unsigned int *slb_miss_kernel_load_io;
-#ifdef CONFIG_HUGETLB_PAGE
-	extern unsigned int *slb_miss_user_load_huge;
-	unsigned long huge_llp;
-
-	huge_llp = mmu_psize_defs[mmu_huge_psize].sllp;
-#endif
 
 	/* Prepare our SLB miss handler based on our page size */
 	linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
@@ -220,11 +214,6 @@
 
 		DBG("SLB: linear  LLP = %04x\n", linear_llp);
 		DBG("SLB: io      LLP = %04x\n", io_llp);
-#ifdef CONFIG_HUGETLB_PAGE
-		patch_slb_encoding(slb_miss_user_load_huge,
-				   SLB_VSID_USER | huge_llp);
-		DBG("SLB: huge    LLP = %04x\n", huge_llp);
-#endif
 	}
 
 	get_paca()->stab_rr = SLB_NUM_BOLTED;
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index b10e470..cd1a93d 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -82,31 +82,45 @@
 	srdi.	r9,r10,USER_ESID_BITS
 	bne-	8f			/* invalid ea bits set */
 
-	/* Figure out if the segment contains huge pages */
-#ifdef CONFIG_HUGETLB_PAGE
-BEGIN_FTR_SECTION
-	b	1f
-END_FTR_SECTION_IFCLR(CPU_FTR_16M_PAGE)
+
+	/* when using slices, we extract the psize off the slice bitmaps
+	 * and then we need to get the sllp encoding off the mmu_psize_defs
+	 * array.
+	 *
+	 * XXX This is a bit inefficient especially for the normal case,
+	 * so we should try to implement a fast path for the standard page
+	 * size using the old sllp value so we avoid the array. We cannot
+	 * really do dynamic patching unfortunately as processes might flip
+	 * between 4k and 64k standard page size
+	 */
+#ifdef CONFIG_PPC_MM_SLICES
 	cmpldi	r10,16
 
-	lhz	r9,PACALOWHTLBAREAS(r13)
-	mr	r11,r10
+	/* Get the slice index * 4 in r11 and matching slice size mask in r9 */
+	ld	r9,PACALOWSLICESPSIZE(r13)
+	sldi	r11,r10,2
 	blt	5f
+	ld	r9,PACAHIGHSLICEPSIZE(r13)
+	srdi	r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2)
+	andi.	r11,r11,0x3c
 
-	lhz	r9,PACAHIGHHTLBAREAS(r13)
-	srdi	r11,r10,(HTLB_AREA_SHIFT-SID_SHIFT)
+5:	/* Extract the psize and multiply to get an array offset */
+	srd	r9,r9,r11
+	andi.	r9,r9,0xf
+	mulli	r9,r9,MMUPSIZEDEFSIZE
 
-5:	srd	r9,r9,r11
-	andi.	r9,r9,1
-	beq	1f
-_GLOBAL(slb_miss_user_load_huge)
-	li	r11,0
-	b	2f
-1:
-#endif /* CONFIG_HUGETLB_PAGE */
-
+	/* Now get to the array and obtain the sllp
+	 */
+	ld	r11,PACATOC(r13)
+	ld	r11,mmu_psize_defs@got(r11)
+	add	r11,r11,r9
+	ld	r11,MMUPSIZESLLP(r11)
+	ori	r11,r11,SLB_VSID_USER
+#else
+	/* paca context sllp already contains the SLB_VSID_USER bits */
 	lhz	r11,PACACONTEXTSLLP(r13)
-2:
+#endif /* CONFIG_PPC_MM_SLICES */
+
 	ld	r9,PACACONTEXTID(r13)
 	rldimi	r10,r9,USER_ESID_BITS,0
 	b	slb_finish_load
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
new file mode 100644
index 0000000..f833dba
--- /dev/null
+++ b/arch/powerpc/mm/slice.c
@@ -0,0 +1,633 @@
+/*
+ * address space "slices" (meta-segments) support
+ *
+ * Copyright (C) 2007 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * Based on hugetlb implementation
+ *
+ * Copyright (C) 2003 David Gibson, IBM Corporation.
+ *
+ * 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
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/mman.h>
+#include <asm/mmu.h>
+#include <asm/spu.h>
+
+static spinlock_t slice_convert_lock = SPIN_LOCK_UNLOCKED;
+
+
+#ifdef DEBUG
+int _slice_debug = 1;
+
+static void slice_print_mask(const char *label, struct slice_mask mask)
+{
+	char	*p, buf[16 + 3 + 16 + 1];
+	int	i;
+
+	if (!_slice_debug)
+		return;
+	p = buf;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		*(p++) = (mask.low_slices & (1 << i)) ? '1' : '0';
+	*(p++) = ' ';
+	*(p++) = '-';
+	*(p++) = ' ';
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		*(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';
+	*(p++) = 0;
+
+	printk(KERN_DEBUG "%s:%s\n", label, buf);
+}
+
+#define slice_dbg(fmt...) do { if (_slice_debug) pr_debug(fmt); } while(0)
+
+#else
+
+static void slice_print_mask(const char *label, struct slice_mask mask) {}
+#define slice_dbg(fmt...)
+
+#endif
+
+static struct slice_mask slice_range_to_mask(unsigned long start,
+					     unsigned long len)
+{
+	unsigned long end = start + len - 1;
+	struct slice_mask ret = { 0, 0 };
+
+	if (start < SLICE_LOW_TOP) {
+		unsigned long mend = min(end, SLICE_LOW_TOP);
+		unsigned long mstart = min(start, SLICE_LOW_TOP);
+
+		ret.low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
+			- (1u << GET_LOW_SLICE_INDEX(mstart));
+	}
+
+	if ((start + len) > SLICE_LOW_TOP)
+		ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))
+			- (1u << GET_HIGH_SLICE_INDEX(start));
+
+	return ret;
+}
+
+static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
+			      unsigned long len)
+{
+	struct vm_area_struct *vma;
+
+	if ((mm->task_size - len) < addr)
+		return 0;
+	vma = find_vma(mm, addr);
+	return (!vma || (addr + len) <= vma->vm_start);
+}
+
+static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+	return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,
+				   1ul << SLICE_LOW_SHIFT);
+}
+
+static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+	unsigned long start = slice << SLICE_HIGH_SHIFT;
+	unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);
+
+	/* Hack, so that each addresses is controlled by exactly one
+	 * of the high or low area bitmaps, the first high area starts
+	 * at 4GB, not 0 */
+	if (start == 0)
+		start = SLICE_LOW_TOP;
+
+	return !slice_area_is_free(mm, start, end - start);
+}
+
+static struct slice_mask slice_mask_for_free(struct mm_struct *mm)
+{
+	struct slice_mask ret = { 0, 0 };
+	unsigned long i;
+
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (!slice_low_has_vma(mm, i))
+			ret.low_slices |= 1u << i;
+
+	if (mm->task_size <= SLICE_LOW_TOP)
+		return ret;
+
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (!slice_high_has_vma(mm, i))
+			ret.high_slices |= 1u << i;
+
+	return ret;
+}
+
+static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize)
+{
+	struct slice_mask ret = { 0, 0 };
+	unsigned long i;
+	u64 psizes;
+
+	psizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (((psizes >> (i * 4)) & 0xf) == psize)
+			ret.low_slices |= 1u << i;
+
+	psizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (((psizes >> (i * 4)) & 0xf) == psize)
+			ret.high_slices |= 1u << i;
+
+	return ret;
+}
+
+static int slice_check_fit(struct slice_mask mask, struct slice_mask available)
+{
+	return (mask.low_slices & available.low_slices) == mask.low_slices &&
+		(mask.high_slices & available.high_slices) == mask.high_slices;
+}
+
+static void slice_flush_segments(void *parm)
+{
+	struct mm_struct *mm = parm;
+	unsigned long flags;
+
+	if (mm != current->active_mm)
+		return;
+
+	/* update the paca copy of the context struct */
+	get_paca()->context = current->active_mm->context;
+
+	local_irq_save(flags);
+	slb_flush_and_rebolt();
+	local_irq_restore(flags);
+}
+
+static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize)
+{
+	/* Write the new slice psize bits */
+	u64 lpsizes, hpsizes;
+	unsigned long i, flags;
+
+	slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);
+	slice_print_mask(" mask", mask);
+
+	/* We need to use a spinlock here to protect against
+	 * concurrent 64k -> 4k demotion ...
+	 */
+	spin_lock_irqsave(&slice_convert_lock, flags);
+
+	lpsizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (mask.low_slices & (1u << i))
+			lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	hpsizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (mask.high_slices & (1u << i))
+			hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	mm->context.low_slices_psize = lpsizes;
+	mm->context.high_slices_psize = hpsizes;
+
+	slice_dbg(" lsps=%lx, hsps=%lx\n",
+		  mm->context.low_slices_psize,
+		  mm->context.high_slices_psize);
+
+	spin_unlock_irqrestore(&slice_convert_lock, flags);
+	mb();
+
+	/* XXX this is sub-optimal but will do for now */
+	on_each_cpu(slice_flush_segments, mm, 0, 1);
+#ifdef CONFIG_SPU_BASE
+	spu_flush_all_slbs(mm);
+#endif
+}
+
+static unsigned long slice_find_area_bottomup(struct mm_struct *mm,
+					      unsigned long len,
+					      struct slice_mask available,
+					      int psize, int use_cache)
+{
+	struct vm_area_struct *vma;
+	unsigned long start_addr, addr;
+	struct slice_mask mask;
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+	if (use_cache) {
+		if (len <= mm->cached_hole_size) {
+			start_addr = addr = TASK_UNMAPPED_BASE;
+			mm->cached_hole_size = 0;
+		} else
+			start_addr = addr = mm->free_area_cache;
+	} else
+		start_addr = addr = TASK_UNMAPPED_BASE;
+
+full_search:
+	for (;;) {
+		addr = _ALIGN_UP(addr, 1ul << pshift);
+		if ((TASK_SIZE - len) < addr)
+			break;
+		vma = find_vma(mm, addr);
+		BUG_ON(vma && (addr >= vma->vm_end));
+
+		mask = slice_range_to_mask(addr, len);
+		if (!slice_check_fit(mask, available)) {
+			if (addr < SLICE_LOW_TOP)
+				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_LOW_SHIFT);
+			else
+				addr = _ALIGN_UP(addr + 1,  1ul << SLICE_HIGH_SHIFT);
+			continue;
+		}
+		if (!vma || addr + len <= vma->vm_start) {
+			/*
+			 * Remember the place where we stopped the search:
+			 */
+			if (use_cache)
+				mm->free_area_cache = addr + len;
+			return addr;
+		}
+		if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+		        mm->cached_hole_size = vma->vm_start - addr;
+		addr = vma->vm_end;
+	}
+
+	/* Make sure we didn't miss any holes */
+	if (use_cache && start_addr != TASK_UNMAPPED_BASE) {
+		start_addr = addr = TASK_UNMAPPED_BASE;
+		mm->cached_hole_size = 0;
+		goto full_search;
+	}
+	return -ENOMEM;
+}
+
+static unsigned long slice_find_area_topdown(struct mm_struct *mm,
+					     unsigned long len,
+					     struct slice_mask available,
+					     int psize, int use_cache)
+{
+	struct vm_area_struct *vma;
+	unsigned long addr;
+	struct slice_mask mask;
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+	/* check if free_area_cache is useful for us */
+	if (use_cache) {
+		if (len <= mm->cached_hole_size) {
+			mm->cached_hole_size = 0;
+			mm->free_area_cache = mm->mmap_base;
+		}
+
+		/* either no address requested or can't fit in requested
+		 * address hole
+		 */
+		addr = mm->free_area_cache;
+
+		/* make sure it can fit in the remaining address space */
+		if (addr > len) {
+			addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+			mask = slice_range_to_mask(addr, len);
+			if (slice_check_fit(mask, available) &&
+			    slice_area_is_free(mm, addr, len))
+					/* remember the address as a hint for
+					 * next time
+					 */
+					return (mm->free_area_cache = addr);
+		}
+	}
+
+	addr = mm->mmap_base;
+	while (addr > len) {
+		/* Go down by chunk size */
+		addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+
+		/* Check for hit with different page size */
+		mask = slice_range_to_mask(addr, len);
+		if (!slice_check_fit(mask, available)) {
+			if (addr < SLICE_LOW_TOP)
+				addr = _ALIGN_DOWN(addr, 1ul << SLICE_LOW_SHIFT);
+			else if (addr < (1ul << SLICE_HIGH_SHIFT))
+				addr = SLICE_LOW_TOP;
+			else
+				addr = _ALIGN_DOWN(addr, 1ul << SLICE_HIGH_SHIFT);
+			continue;
+		}
+
+		/*
+		 * Lookup failure means no vma is above this address,
+		 * else if new region fits below vma->vm_start,
+		 * return with success:
+		 */
+		vma = find_vma(mm, addr);
+		if (!vma || (addr + len) <= vma->vm_start) {
+			/* remember the address as a hint for next time */
+			if (use_cache)
+				mm->free_area_cache = addr;
+			return addr;
+		}
+
+		/* remember the largest hole we saw so far */
+		if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+		        mm->cached_hole_size = vma->vm_start - addr;
+
+		/* try just below the current vma->vm_start */
+		addr = vma->vm_start;
+	}
+
+	/*
+	 * A failed mmap() very likely causes application failure,
+	 * so fall back to the bottom-up function here. This scenario
+	 * can happen with large stack limits and large mmap()
+	 * allocations.
+	 */
+	addr = slice_find_area_bottomup(mm, len, available, psize, 0);
+
+	/*
+	 * Restore the topdown base:
+	 */
+	if (use_cache) {
+		mm->free_area_cache = mm->mmap_base;
+		mm->cached_hole_size = ~0UL;
+	}
+
+	return addr;
+}
+
+
+static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len,
+				     struct slice_mask mask, int psize,
+				     int topdown, int use_cache)
+{
+	if (topdown)
+		return slice_find_area_topdown(mm, len, mask, psize, use_cache);
+	else
+		return slice_find_area_bottomup(mm, len, mask, psize, use_cache);
+}
+
+unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
+				      unsigned long flags, unsigned int psize,
+				      int topdown, int use_cache)
+{
+	struct slice_mask mask;
+	struct slice_mask good_mask;
+	struct slice_mask potential_mask = {0,0} /* silence stupid warning */;
+	int pmask_set = 0;
+	int fixed = (flags & MAP_FIXED);
+	int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+	struct mm_struct *mm = current->mm;
+
+	/* Sanity checks */
+	BUG_ON(mm->task_size == 0);
+
+	slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
+	slice_dbg(" addr=%lx, len=%lx, flags=%lx, topdown=%d, use_cache=%d\n",
+		  addr, len, flags, topdown, use_cache);
+
+	if (len > mm->task_size)
+		return -ENOMEM;
+	if (fixed && (addr & ((1ul << pshift) - 1)))
+		return -EINVAL;
+	if (fixed && addr > (mm->task_size - len))
+		return -EINVAL;
+
+	/* If hint, make sure it matches our alignment restrictions */
+	if (!fixed && addr) {
+		addr = _ALIGN_UP(addr, 1ul << pshift);
+		slice_dbg(" aligned addr=%lx\n", addr);
+	}
+
+	/* First makeup a "good" mask of slices that have the right size
+	 * already
+	 */
+	good_mask = slice_mask_for_size(mm, psize);
+	slice_print_mask(" good_mask", good_mask);
+
+	/* First check hint if it's valid or if we have MAP_FIXED */
+	if ((addr != 0 || fixed) && (mm->task_size - len) >= addr) {
+
+		/* Don't bother with hint if it overlaps a VMA */
+		if (!fixed && !slice_area_is_free(mm, addr, len))
+			goto search;
+
+		/* Build a mask for the requested range */
+		mask = slice_range_to_mask(addr, len);
+		slice_print_mask(" mask", mask);
+
+		/* Check if we fit in the good mask. If we do, we just return,
+		 * nothing else to do
+		 */
+		if (slice_check_fit(mask, good_mask)) {
+			slice_dbg(" fits good !\n");
+			return addr;
+		}
+
+		/* We don't fit in the good mask, check what other slices are
+		 * empty and thus can be converted
+		 */
+		potential_mask = slice_mask_for_free(mm);
+		potential_mask.low_slices |= good_mask.low_slices;
+		potential_mask.high_slices |= good_mask.high_slices;
+		pmask_set = 1;
+		slice_print_mask(" potential", potential_mask);
+		if (slice_check_fit(mask, potential_mask)) {
+			slice_dbg(" fits potential !\n");
+			goto convert;
+		}
+	}
+
+	/* If we have MAP_FIXED and failed the above step, then error out */
+	if (fixed)
+		return -EBUSY;
+
+ search:
+	slice_dbg(" search...\n");
+
+	/* Now let's see if we can find something in the existing slices
+	 * for that size
+	 */
+	addr = slice_find_area(mm, len, good_mask, psize, topdown, use_cache);
+	if (addr != -ENOMEM) {
+		/* Found within the good mask, we don't have to setup,
+		 * we thus return directly
+		 */
+		slice_dbg(" found area at 0x%lx\n", addr);
+		return addr;
+	}
+
+	/* Won't fit, check what can be converted */
+	if (!pmask_set) {
+		potential_mask = slice_mask_for_free(mm);
+		potential_mask.low_slices |= good_mask.low_slices;
+		potential_mask.high_slices |= good_mask.high_slices;
+		pmask_set = 1;
+		slice_print_mask(" potential", potential_mask);
+	}
+
+	/* Now let's see if we can find something in the existing slices
+	 * for that size
+	 */
+	addr = slice_find_area(mm, len, potential_mask, psize, topdown,
+			       use_cache);
+	if (addr == -ENOMEM)
+		return -ENOMEM;
+
+	mask = slice_range_to_mask(addr, len);
+	slice_dbg(" found potential area at 0x%lx\n", addr);
+	slice_print_mask(" mask", mask);
+
+ convert:
+	slice_convert(mm, mask, psize);
+	return addr;
+
+}
+EXPORT_SYMBOL_GPL(slice_get_unmapped_area);
+
+unsigned long arch_get_unmapped_area(struct file *filp,
+				     unsigned long addr,
+				     unsigned long len,
+				     unsigned long pgoff,
+				     unsigned long flags)
+{
+	return slice_get_unmapped_area(addr, len, flags,
+				       current->mm->context.user_psize,
+				       0, 1);
+}
+
+unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+					     const unsigned long addr0,
+					     const unsigned long len,
+					     const unsigned long pgoff,
+					     const unsigned long flags)
+{
+	return slice_get_unmapped_area(addr0, len, flags,
+				       current->mm->context.user_psize,
+				       1, 1);
+}
+
+unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+{
+	u64 psizes;
+	int index;
+
+	if (addr < SLICE_LOW_TOP) {
+		psizes = mm->context.low_slices_psize;
+		index = GET_LOW_SLICE_INDEX(addr);
+	} else {
+		psizes = mm->context.high_slices_psize;
+		index = GET_HIGH_SLICE_INDEX(addr);
+	}
+
+	return (psizes >> (index * 4)) & 0xf;
+}
+EXPORT_SYMBOL_GPL(get_slice_psize);
+
+/*
+ * This is called by hash_page when it needs to do a lazy conversion of
+ * an address space from real 64K pages to combo 4K pages (typically
+ * when hitting a non cacheable mapping on a processor or hypervisor
+ * that won't allow them for 64K pages).
+ *
+ * This is also called in init_new_context() to change back the user
+ * psize from whatever the parent context had it set to
+ *
+ * This function will only change the content of the {low,high)_slice_psize
+ * masks, it will not flush SLBs as this shall be handled lazily by the
+ * caller.
+ */
+void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
+{
+	unsigned long flags, lpsizes, hpsizes;
+	unsigned int old_psize;
+	int i;
+
+	slice_dbg("slice_set_user_psize(mm=%p, psize=%d)\n", mm, psize);
+
+	spin_lock_irqsave(&slice_convert_lock, flags);
+
+	old_psize = mm->context.user_psize;
+	slice_dbg(" old_psize=%d\n", old_psize);
+	if (old_psize == psize)
+		goto bail;
+
+	mm->context.user_psize = psize;
+	wmb();
+
+	lpsizes = mm->context.low_slices_psize;
+	for (i = 0; i < SLICE_NUM_LOW; i++)
+		if (((lpsizes >> (i * 4)) & 0xf) == old_psize)
+			lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	hpsizes = mm->context.high_slices_psize;
+	for (i = 0; i < SLICE_NUM_HIGH; i++)
+		if (((hpsizes >> (i * 4)) & 0xf) == old_psize)
+			hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+				(((unsigned long)psize) << (i * 4));
+
+	mm->context.low_slices_psize = lpsizes;
+	mm->context.high_slices_psize = hpsizes;
+
+	slice_dbg(" lsps=%lx, hsps=%lx\n",
+		  mm->context.low_slices_psize,
+		  mm->context.high_slices_psize);
+
+ bail:
+	spin_unlock_irqrestore(&slice_convert_lock, flags);
+}
+
+/*
+ * is_hugepage_only_range() is used by generic code to verify wether
+ * a normal mmap mapping (non hugetlbfs) is valid on a given area.
+ *
+ * until the generic code provides a more generic hook and/or starts
+ * calling arch get_unmapped_area for MAP_FIXED (which our implementation
+ * here knows how to deal with), we hijack it to keep standard mappings
+ * away from us.
+ *
+ * because of that generic code limitation, MAP_FIXED mapping cannot
+ * "convert" back a slice with no VMAs to the standard page size, only
+ * get_unmapped_area() can. It would be possible to fix it here but I
+ * prefer working on fixing the generic code instead.
+ *
+ * WARNING: This will not work if hugetlbfs isn't enabled since the
+ * generic code will redefine that function as 0 in that. This is ok
+ * for now as we only use slices with hugetlbfs enabled. This should
+ * be fixed as the generic code gets fixed.
+ */
+int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
+			   unsigned long len)
+{
+	struct slice_mask mask, available;
+
+	mask = slice_range_to_mask(addr, len);
+	available = slice_mask_for_size(mm, mm->context.user_psize);
+
+#if 0 /* too verbose */
+	slice_dbg("is_hugepage_only_range(mm=%p, addr=%lx, len=%lx)\n",
+		 mm, addr, len);
+	slice_print_mask(" mask", mask);
+	slice_print_mask(" available", available);
+#endif
+	return !slice_check_fit(mask, available);
+}
+
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index 925ff70..6a69417 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -111,7 +111,7 @@
 	if (start >= end)
 		return;
 	end = (end - 1) | ~PAGE_MASK;
-	pmd = pmd_offset(pgd_offset(mm, start), start);
+	pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
 	for (;;) {
 		pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
 		if (pmd_end > end)
@@ -169,7 +169,7 @@
 		return;
 	}
 	mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
-	pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
+	pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
 	if (!pmd_none(*pmd))
 		flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
 	FINISH_FLUSH;
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index fd8d08c..2bfc4d7 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -143,16 +143,22 @@
 	 */
 	addr &= PAGE_MASK;
 
-	/* Get page size (maybe move back to caller) */
+	/* Get page size (maybe move back to caller).
+	 *
+	 * NOTE: when using special 64K mappings in 4K environment like
+	 * for SPEs, we obtain the page size from the slice, which thus
+	 * must still exist (and thus the VMA not reused) at the time
+	 * of this call
+	 */
 	if (huge) {
 #ifdef CONFIG_HUGETLB_PAGE
 		psize = mmu_huge_psize;
 #else
 		BUG();
-		psize = pte_pagesize_index(pte); /* shutup gcc */
+		psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
 #endif
 	} else
-		psize = pte_pagesize_index(pte);
+		psize = pte_pagesize_index(mm, addr, pte);
 
 	/* Build full vaddr */
 	if (!is_kernel_addr(addr)) {
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index 626b29f..c29293b 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -747,7 +747,7 @@
 		 * counter value etc.) are not copied to the actual registers
 		 * until the performance monitor is enabled.  In order to get
 		 * this to work as desired, the permormance monitor needs to
-		 * be disabled while writting to the latches.  This is a
+		 * be disabled while writing to the latches.  This is a
 		 * HW design issue.
 		 */
 		cbe_enable_pm(cpu);
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index 7ef0c68..ba55b0f 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -15,8 +15,8 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/pci-bridge.h>
 #include <asm-powerpc/mpic.h>
 #include <asm/mpc86xx.h>
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index a35315a..cf0e7bc 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc86xads-setup.c
+/*arch/powerpc/platforms/8xx/mpc86xads_setup.c
  *
  * Platform setup for the Freescale mpc86xads board
  *
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index a57b577..c36e475 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc885ads-setup.c
+/*arch/powerpc/platforms/8xx/mpc885ads_setup.c
  *
  * Platform setup for the Freescale mpc885ads board
  *
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 8255177..9b2b386 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -35,6 +35,21 @@
 	  Units on machines implementing the Broadband Processor
 	  Architecture.
 
+config SPU_FS_64K_LS
+	bool "Use 64K pages to map SPE local  store"
+	# we depend on PPC_MM_SLICES for now rather than selecting
+	# it because we depend on hugetlbfs hooks being present. We
+	# will fix that when the generic code has been improved to
+	# not require hijacking hugetlbfs hooks.
+	depends on SPU_FS && PPC_MM_SLICES && !PPC_64K_PAGES
+	default y
+	select PPC_HAS_HASH_64K
+	help
+	  This option causes SPE local stores to be mapped in process
+	  address spaces using 64K pages while the rest of the kernel
+	  uses 4K pages. This can improve performances of applications
+	  using multiple SPEs by lowering the TLB pressure on them.
+
 config SPU_BASE
 	bool
 	default n
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index d68d920..7fb92f2 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -74,7 +74,7 @@
 	/* Fast path if we have a non-0 token, it indicates which bus we
 	 * are on.
 	 *
-	 * If the token is 0, that means either the the ioremap was done
+	 * If the token is 0, that means either that the ioremap was done
 	 * before we initialized this layer, or it's a PIO operation. We
 	 * fallback to a low path in this case. Hopefully, internal devices
 	 * which are ioremap'ed early should use in_XX/out_XX functions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index fec5152..a7f5a76 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -144,12 +144,11 @@
 
 	switch(REGION_ID(ea)) {
 	case USER_REGION_ID:
-#ifdef CONFIG_HUGETLB_PAGE
-		if (in_hugepage_area(mm->context, ea))
-			psize = mmu_huge_psize;
-		else
+#ifdef CONFIG_PPC_MM_SLICES
+		psize = get_slice_psize(mm, ea);
+#else
+		psize = mm->context.user_psize;
 #endif
-			psize = mm->context.user_psize;
 		vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
 				SLB_VSID_USER;
 		break;
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index 2cd89c1..328afcf 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,4 +1,4 @@
-obj-y += switch.o fault.o
+obj-y += switch.o fault.o lscsa_alloc.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o syscalls.o coredump.o
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index a87d9ca..8654749 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -36,10 +36,8 @@
 	/* Binding to physical processor deferred
 	 * until spu_activate().
 	 */
-	spu_init_csa(&ctx->csa);
-	if (!ctx->csa.lscsa) {
+	if (spu_init_csa(&ctx->csa))
 		goto out_free;
-	}
 	spin_lock_init(&ctx->mmio_lock);
 	spin_lock_init(&ctx->mapping_lock);
 	kref_init(&ctx->kref);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index d010b24..45614c73 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -118,14 +118,32 @@
 static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
 					  unsigned long address)
 {
-	struct spu_context *ctx = vma->vm_file->private_data;
-	unsigned long pfn, offset = address - vma->vm_start;
+	struct spu_context *ctx	= vma->vm_file->private_data;
+	unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+	struct spu_state *csa = &ctx->csa;
+	int psize;
 
-	offset += vma->vm_pgoff << PAGE_SHIFT;
+	/* Check what page size we are using */
+	psize = get_slice_psize(vma->vm_mm, address);
 
+	/* Some sanity checking */
+	BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+	/* Wow, 64K, cool, we need to align the address though */
+	if (csa->use_big_pages) {
+		BUG_ON(vma->vm_start & 0xffff);
+		address &= ~0xfffful;
+	}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
+	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
 	if (offset >= LS_SIZE)
 		return NOPFN_SIGBUS;
 
+	pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+		 addr0, address, offset);
+
 	spu_acquire(ctx);
 
 	if (ctx->state == SPU_STATE_SAVED) {
@@ -149,9 +167,24 @@
 	.nopfn = spufs_mem_mmap_nopfn,
 };
 
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
 {
+#ifdef CONFIG_SPU_FS_64K_LS
+	struct spu_context	*ctx = file->private_data;
+	struct spu_state	*csa = &ctx->csa;
+
+	/* Sanity check VMA alignment */
+	if (csa->use_big_pages) {
+		pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+			 " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+			 vma->vm_pgoff);
+		if (vma->vm_start & 0xffff)
+			return -EINVAL;
+		if (vma->vm_pgoff & 0xf)
+			return -EINVAL;
+	}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
@@ -163,13 +196,34 @@
 	return 0;
 }
 
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+				      unsigned long len, unsigned long pgoff,
+				      unsigned long flags)
+{
+	struct spu_context	*ctx = file->private_data;
+	struct spu_state	*csa = &ctx->csa;
+
+	/* If not using big pages, fallback to normal MM g_u_a */
+	if (!csa->use_big_pages)
+		return current->mm->get_unmapped_area(file, addr, len,
+						      pgoff, flags);
+
+	/* Else, try to obtain a 64K pages slice */
+	return slice_get_unmapped_area(addr, len, flags,
+				       MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 static const struct file_operations spufs_mem_fops = {
-	.open	 = spufs_mem_open,
-	.release = spufs_mem_release,
-	.read    = spufs_mem_read,
-	.write   = spufs_mem_write,
-	.llseek  = generic_file_llseek,
-	.mmap    = spufs_mem_mmap,
+	.open	 		= spufs_mem_open,
+	.read   		= spufs_mem_read,
+	.write   		= spufs_mem_write,
+	.llseek  		= generic_file_llseek,
+	.mmap    		= spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+	.get_unmapped_area	= spufs_get_unmapped_area,
+#endif
 };
 
 static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
diff --git a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
new file mode 100644
index 0000000..f4b3c05
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
@@ -0,0 +1,181 @@
+/*
+ * SPU local store allocation routines
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu.h>
+
+static int spu_alloc_lscsa_std(struct spu_state *csa)
+{
+	struct spu_lscsa *lscsa;
+	unsigned char *p;
+
+	lscsa = vmalloc(sizeof(struct spu_lscsa));
+	if (!lscsa)
+		return -ENOMEM;
+	memset(lscsa, 0, sizeof(struct spu_lscsa));
+	csa->lscsa = lscsa;
+
+	/* Set LS pages reserved to allow for user-space mapping. */
+	for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		SetPageReserved(vmalloc_to_page(p));
+
+	return 0;
+}
+
+static void spu_free_lscsa_std(struct spu_state *csa)
+{
+	/* Clear reserved bit before vfree. */
+	unsigned char *p;
+
+	if (csa->lscsa == NULL)
+		return;
+
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		ClearPageReserved(vmalloc_to_page(p));
+
+	vfree(csa->lscsa);
+}
+
+#ifdef CONFIG_SPU_FS_64K_LS
+
+#define SPU_64K_PAGE_SHIFT	16
+#define SPU_64K_PAGE_ORDER	(SPU_64K_PAGE_SHIFT - PAGE_SHIFT)
+#define SPU_64K_PAGE_COUNT	(1ul << SPU_64K_PAGE_ORDER)
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+	struct page	**pgarray;
+	unsigned char	*p;
+	int		i, j, n_4k;
+
+	/* Check availability of 64K pages */
+	if (mmu_psize_defs[MMU_PAGE_64K].shift == 0)
+		goto fail;
+
+	csa->use_big_pages = 1;
+
+	pr_debug("spu_alloc_lscsa(csa=0x%p), trying to allocate 64K pages\n",
+		 csa);
+
+	/* First try to allocate our 64K pages. We need 5 of them
+	 * with the current implementation. In the future, we should try
+	 * to separate the lscsa with the actual local store image, thus
+	 * allowing us to require only 4 64K pages per context
+	 */
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) {
+		/* XXX This is likely to fail, we should use a special pool
+		 *     similiar to what hugetlbfs does.
+		 */
+		csa->lscsa_pages[i] = alloc_pages(GFP_KERNEL,
+						  SPU_64K_PAGE_ORDER);
+		if (csa->lscsa_pages[i] == NULL)
+			goto fail;
+	}
+
+	pr_debug(" success ! creating vmap...\n");
+
+	/* Now we need to create a vmalloc mapping of these for the kernel
+	 * and SPU context switch code to use. Currently, we stick to a
+	 * normal kernel vmalloc mapping, which in our case will be 4K
+	 */
+	n_4k = SPU_64K_PAGE_COUNT * SPU_LSCSA_NUM_BIG_PAGES;
+	pgarray = kmalloc(sizeof(struct page *) * n_4k, GFP_KERNEL);
+	if (pgarray == NULL)
+		goto fail;
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+		for (j = 0; j < SPU_64K_PAGE_COUNT; j++)
+			/* We assume all the struct page's are contiguous
+			 * which should be hopefully the case for an order 4
+			 * allocation..
+			 */
+			pgarray[i * SPU_64K_PAGE_COUNT + j] =
+				csa->lscsa_pages[i] + j;
+	csa->lscsa = vmap(pgarray, n_4k, VM_USERMAP, PAGE_KERNEL);
+	kfree(pgarray);
+	if (csa->lscsa == NULL)
+		goto fail;
+
+	memset(csa->lscsa, 0, sizeof(struct spu_lscsa));
+
+	/* Set LS pages reserved to allow for user-space mapping.
+	 *
+	 * XXX isn't that a bit obsolete ? I think we should just
+	 * make sure the page count is high enough. Anyway, won't harm
+	 * for now
+	 */
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		SetPageReserved(vmalloc_to_page(p));
+
+	pr_debug(" all good !\n");
+
+	return 0;
+fail:
+	pr_debug("spufs: failed to allocate lscsa 64K pages, falling back\n");
+	spu_free_lscsa(csa);
+	return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+	unsigned char *p;
+	int i;
+
+	if (!csa->use_big_pages) {
+		spu_free_lscsa_std(csa);
+		return;
+	}
+	csa->use_big_pages = 0;
+
+	if (csa->lscsa == NULL)
+		goto free_pages;
+
+	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+		ClearPageReserved(vmalloc_to_page(p));
+
+	vunmap(csa->lscsa);
+	csa->lscsa = NULL;
+
+ free_pages:
+
+	for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+		if (csa->lscsa_pages[i])
+			__free_pages(csa->lscsa_pages[i], SPU_64K_PAGE_ORDER);
+}
+
+#else /* CONFIG_SPU_FS_64K_LS */
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+	return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+	spu_free_lscsa_std(csa);
+}
+
+#endif /* !defined(CONFIG_SPU_FS_64K_LS) */
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 29dc59c..71a0b41 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2188,40 +2188,30 @@
  * as it is by far the largest of the context save regions,
  * and may need to be pinned or otherwise specially aligned.
  */
-void spu_init_csa(struct spu_state *csa)
+int spu_init_csa(struct spu_state *csa)
 {
-	struct spu_lscsa *lscsa;
-	unsigned char *p;
+	int rc;
 
 	if (!csa)
-		return;
+		return -EINVAL;
 	memset(csa, 0, sizeof(struct spu_state));
 
-	lscsa = vmalloc(sizeof(struct spu_lscsa));
-	if (!lscsa)
-		return;
+	rc = spu_alloc_lscsa(csa);
+	if (rc)
+		return rc;
 
-	memset(lscsa, 0, sizeof(struct spu_lscsa));
-	csa->lscsa = lscsa;
 	spin_lock_init(&csa->register_lock);
 
-	/* Set LS pages reserved to allow for user-space mapping. */
-	for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-		SetPageReserved(vmalloc_to_page(p));
-
 	init_prob(csa);
 	init_priv1(csa);
 	init_priv2(csa);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(spu_init_csa);
 
 void spu_fini_csa(struct spu_state *csa)
 {
-	/* Clear reserved bit before vfree. */
-	unsigned char *p;
-	for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-		ClearPageReserved(vmalloc_to_page(p));
-
-	vfree(csa->lscsa);
+	spu_free_lscsa(csa);
 }
 EXPORT_SYMBOL_GPL(spu_fini_csa);
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 46c3a8e..761d9e9 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -7,7 +7,9 @@
 	depends on PPC_ISERIES
 
 config VIOCONS
-	tristate "iSeries Virtual Console Support (Obsolete)"
+	bool "iSeries Virtual Console Support (Obsolete)"
+	depends on !HVC_ISERIES
+	default n
 	help
 	  This is the old virtual console driver for legacy iSeries.
 	  You should use the iSeries Hypervisor Virtual Console
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 63e2306..093438b 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -100,6 +100,9 @@
 static DEFINE_SPINLOCK(slot_errbuf_lock);
 static int eeh_error_buf_size;
 
+#define EEH_PCI_REGS_LOG_LEN 4096
+static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
+
 /* System monitoring statistics */
 static unsigned long no_device;
 static unsigned long no_dn;
@@ -115,7 +118,8 @@
 /* --------------------------------------------------------------- */
 /* Below lies the EEH event infrastructure */
 
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
+static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
+                                   char *driver_log, size_t loglen)
 {
 	int config_addr;
 	unsigned long flags;
@@ -133,7 +137,8 @@
 	rc = rtas_call(ibm_slot_error_detail,
 	               8, 1, NULL, config_addr,
 	               BUID_HI(pdn->phb->buid),
-	               BUID_LO(pdn->phb->buid), NULL, 0,
+	               BUID_LO(pdn->phb->buid),
+	               virt_to_phys(driver_log), loglen,
 	               virt_to_phys(slot_errbuf),
 	               eeh_error_buf_size,
 	               severity);
@@ -144,6 +149,84 @@
 }
 
 /**
+ * gather_pci_data - copy assorted PCI config space registers to buff
+ * @pdn: device to report data for
+ * @buf: point to buffer in which to log
+ * @len: amount of room in buffer
+ *
+ * This routine captures assorted PCI configuration space data,
+ * and puts them into a buffer for RTAS error logging.
+ */
+static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+{
+	u32 cfg;
+	int cap, i;
+	int n = 0;
+
+	n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
+	printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+
+	rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+	n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
+	printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
+
+	rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+	n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
+	printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
+
+	/* Dump out the PCI-X command and status regs */
+	cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX);
+	if (cap) {
+		rtas_read_config(pdn, cap, 4, &cfg);
+		n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
+		printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
+
+		rtas_read_config(pdn, cap+4, 4, &cfg);
+		n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
+		printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
+	}
+
+	/* If PCI-E capable, dump PCI-E cap 10, and the AER */
+	cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_EXP);
+	if (cap) {
+		n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
+		printk(KERN_WARNING
+		       "EEH: PCI-E capabilities and status follow:\n");
+
+		for (i=0; i<=8; i++) {
+			rtas_read_config(pdn, cap+4*i, 4, &cfg);
+			n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+			printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
+		}
+
+		cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR);
+		if (cap) {
+			n += scnprintf(buf+n, len-n, "pci-e AER:\n");
+			printk(KERN_WARNING
+			       "EEH: PCI-E AER capability register set follows:\n");
+
+			for (i=0; i<14; i++) {
+				rtas_read_config(pdn, cap+4*i, 4, &cfg);
+				n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+				printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
+			}
+		}
+	}
+	return n;
+}
+
+void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
+{
+	size_t loglen = 0;
+	memset(pci_regs_buf, 0, EEH_PCI_REGS_LOG_LEN);
+
+	rtas_pci_enable(pdn, EEH_THAW_MMIO);
+	loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
+
+	rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+}
+
+/**
  * read_slot_reset_state - Read the reset state of a device node's slot
  * @dn: device node to read
  * @rets: array to return results in
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 3170e00..f07d849 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -361,11 +361,12 @@
 		goto hard_fail;
 	}
 
-	eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
 	printk(KERN_WARNING
-	   "EEH: This PCI device has failed %d times since last reboot: "
-		"location=%s driver=%s pci addr=%s\n",
-		frozen_pdn->eeh_freeze_count, location, drv_str, pci_str);
+	   "EEH: This PCI device has failed %d times in the last hour:\n",
+		frozen_pdn->eeh_freeze_count);
+	printk(KERN_WARNING
+		"EEH: location=%s driver=%s pci addr=%s\n",
+		location, drv_str, pci_str);
 
 	/* Walk the various device drivers attached to this slot through
 	 * a reset sequence, giving each an opportunity to do what it needs
@@ -375,6 +376,11 @@
 	 */
 	pci_walk_bus(frozen_bus, eeh_report_error, &result);
 
+	/* Since rtas may enable MMIO when posting the error log,
+	 * don't post the error log until after all dev drivers
+	 * have been informed. */
+	eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
+
 	/* If all device drivers were EEH-unaware, then shut
 	 * down all of the device drivers, and hope they
 	 * go down willingly, without panicing the system.
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 8a123c7..cad1757 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -907,7 +907,7 @@
 		struct fs_platform_info fs_enet_data;
 		const unsigned int *id;
 		const unsigned int *phy_addr;
-		void *mac_addr;
+		const void *mac_addr;
 		const phandle *ph;
 		const char *model;
 
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index c5850a2..e8e9432 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -35,7 +35,7 @@
 main(void)
 {
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
-	DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(MM, offsetof(struct task_struct, mm));
 	DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index 7ce5364..bf72204 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc866ads-setup.c
+/*arch/ppc/platforms/mpc866ads_setup.c
  *
  * Platform setup for the Freescale mpc866ads board
  *
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
index 10659c2..9192777 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/ppc/syslib/ipic.c
@@ -1,5 +1,5 @@
 /*
- * include/asm-ppc/ipic.c
+ * arch/ppc/syslib/ipic.c
  *
  * IPIC routines implementations.
  *
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index ee89b33..81a2b92 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -567,9 +567,11 @@
 {
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		appldata_online_cpu((long) hcpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		appldata_offline_cpu((long) hcpu);
 		break;
 	default:
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
index 99ff9f0..d1defbb 100644
--- a/arch/s390/crypto/Kconfig
+++ b/arch/s390/crypto/Kconfig
@@ -54,7 +54,7 @@
 	default "m"
 	help
 	  Select this option if you want to use the s390 pseudo random number
-	  generator. The PRNG is part of the cryptograhic processor functions
+	  generator. The PRNG is part of the cryptographic processor functions
 	  and uses triple-DES to generate secure random numbers like the
 	  ANSI X9.17 standard. The PRNG is usable via the char device
 	  /dev/prandom.
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index ec514fe..1375f8a 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -15,7 +15,7 @@
 
 int main(void)
 {
-	DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
+	DEFINE(__THREAD_info, offsetof(struct task_struct, stack),);
 	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
 	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
 	DEFINE(__THREAD_mm_segment,
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b797702..09f028a 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -789,10 +789,12 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		if (sysdev_create_file(s, &attr_capability))
 			return NOTIFY_BAD;
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		sysdev_remove_file(s, &attr_capability);
 		break;
 	}
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d74eb12..038179e 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -52,6 +52,9 @@
 config GENERIC_TIME
 	def_bool n
 
+config GENERIC_CLOCKEVENTS
+	def_bool n
+
 config SYS_SUPPORTS_APM_EMULATION
 	bool
 
@@ -436,11 +439,11 @@
 
 menu "Timer and clock configuration"
 
-if !GENERIC_TIME
-
 config SH_TMU
 	bool "TMU timer support"
 	depends on CPU_SH3 || CPU_SH4
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
 	default y
 	help
 	  This enables the use of the TMU as the system timer.
@@ -459,8 +462,6 @@
 	help
 	  This enables the use of the MTU2 as the system timer.
 
-endif
-
 config SH_TIMER_IRQ
 	int
 	default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
@@ -468,24 +469,6 @@
 	default "140" if CPU_SUBTYPE_SH7206
 	default "16"
 
-config NO_IDLE_HZ
-	bool "Dynamic tick timer"
-	help
-	  Select this option if you want to disable continuous timer ticks
-	  and have them programmed to occur as required. This option saves
-	  power as the system can remain in idle state for longer.
-
-	  By default dynamic tick is disabled during the boot, and can be
-	  manually enabled with:
-
-	    echo 1 > /sys/devices/system/timer/timer0/dyn_tick
-
-	  Alternatively, if you want dynamic tick automatically enabled
-	  during boot, pass "dyntick=enable" via the kernel command string.
-
-	  Please note that dynamic tick may affect the accuracy of
-	  timekeeping on some platforms depending on the implementation.
-
 config SH_PCLK_FREQ
 	int "Peripheral clock frequency (in Hz)"
 	default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
@@ -509,6 +492,8 @@
 	help
 	  MD2 - MD0 pin setting.
 
+source "kernel/time/Kconfig"
+
 endmenu
 
 menu "CPU Frequency scaling"
diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
index a83a5d9..4058b4f 100644
--- a/arch/sh/boards/landisk/setup.c
+++ b/arch/sh/boards/landisk/setup.c
@@ -93,6 +93,7 @@
  */
 struct sh_machine_vector mv_landisk __initmv = {
 	.mv_name = "LANDISK",
+	.mv_nr_irqs = 72,
 	.mv_setup = landisk_setup,
 	.mv_init_irq = init_landisk_IRQ,
 };
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index 770defe..52c7bfa 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/sh/kernel/setup_7751se.c
+ * linux/arch/sh/boards/se/7751/setup.c
  *
  * Copyright (C) 2000  Kazumoto Kojima
  *
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index 6cb9267..e13f06b 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -2,8 +2,9 @@
 # Makefile for the Linux SuperH-specific device drivers.
 #
 
+obj-y		+= dma/
+
 obj-$(CONFIG_PCI)		+= pci/
-obj-$(CONFIG_SH_DMA)		+= dma/
 obj-$(CONFIG_SUPERHYWAY)	+= superhyway/
 obj-$(CONFIG_PUSH_SWITCH)	+= push-switch.o
 obj-$(CONFIG_HEARTBEAT)		+= heartbeat.o
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index defc13c..99935f9 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -1,12 +1,12 @@
 menu "DMA support"
 
-config SH_DMA
-	bool "DMA controller (DMAC) support"
-	help
-	  Selecting this option will provide same API as PC's Direct Memory
-	  Access Controller(8237A) for SuperH DMAC.
+config SH_DMA_API
+	bool
 
-	  If unsure, say N.
+config SH_DMA
+	bool "SuperH on-chip DMA controller (DMAC) support"
+	select SH_DMA_API
+	default n
 
 config NR_ONCHIP_DMA_CHANNELS
 	depends on SH_DMA
@@ -53,4 +53,12 @@
 	  in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
 	  are dual-address capable.
 
+config SH_DMABRG
+	bool "SH7760 DMABRG support"
+	depends on CPU_SUBTYPE_SH7760
+	help
+	  The DMABRG does data transfers from main memory to Audio/USB units
+	  of the SH7760.
+	  Say Y if you want to use Audio/USB DMA on your SH7760 board.
+
 endmenu
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile
index db1295d..1ac812d 100644
--- a/arch/sh/drivers/dma/Makefile
+++ b/arch/sh/drivers/dma/Makefile
@@ -2,8 +2,8 @@
 # Makefile for the SuperH DMA specific kernel interface routines under Linux.
 #
 
-obj-y				+= dma-api.o
+obj-$(CONFIG_SH_DMA_API)	+= dma-api.o dma-sysfs.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma-isa.o
-obj-$(CONFIG_SYSFS)		+= dma-sysfs.o
 obj-$(CONFIG_SH_DMA)		+= dma-sh.o
 obj-$(CONFIG_SH_DREAMCAST)	+= dma-pvr2.o dma-g2.o
+obj-$(CONFIG_SH_DMABRG)		+= dmabrg.o
diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c
new file mode 100644
index 0000000..9d0a293
--- /dev/null
+++ b/arch/sh/drivers/dma/dmabrg.c
@@ -0,0 +1,196 @@
+/*
+ * SH7760 DMABRG IRQ handling
+ *
+ * (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *  licensed under the GPLv2.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/dmabrg.h>
+#include <asm/io.h>
+
+/*
+ * The DMABRG is a special DMA unit within the SH7760. It does transfers
+ * from USB-SRAM/Audio units to main memory (and also the LCDC; but that
+ * part is sensibly placed  in the LCDC  registers and requires no irqs)
+ * It has 3 IRQ lines which trigger 10 events, and works independently
+ * from the traditional SH DMAC (although it blocks usage of DMAC 0)
+ *
+ * BRGIRQID   | component | dir | meaning      | source
+ * -----------------------------------------------------
+ *     0      | USB-DMA   | ... | xfer done    | DMABRGI1
+ *     1      | USB-UAE   | ... | USB addr err.| DMABRGI0
+ *     2      | HAC0/SSI0 | play| all done     | DMABRGI1
+ *     3      | HAC0/SSI0 | play| half done    | DMABRGI2
+ *     4      | HAC0/SSI0 | rec | all done     | DMABRGI1
+ *     5      | HAC0/SSI0 | rec | half done    | DMABRGI2
+ *     6      | HAC1/SSI1 | play| all done     | DMABRGI1
+ *     7      | HAC1/SSI1 | play| half done    | DMABRGI2
+ *     8      | HAC1/SSI1 | rec | all done     | DMABRGI1
+ *     9      | HAC1/SSI1 | rec | half done    | DMABRGI2
+ *
+ * all can be enabled/disabled in the DMABRGCR register,
+ * as well as checked if they occured.
+ *
+ * DMABRGI0 services  USB  DMA  Address  errors,  but it still must be
+ * enabled/acked in the DMABRGCR register.  USB-DMA complete indicator
+ * is grouped together with the audio buffer end indicators, too bad...
+ *
+ * DMABRGCR:	Bits 31-24: audio-dma ENABLE flags,
+ *		Bits 23-16: audio-dma STATUS flags,
+ *		Bits  9-8:  USB error/xfer ENABLE,
+ *		Bits  1-0:  USB error/xfer STATUS.
+ *	Ack an IRQ by writing 0 to the STATUS flag.
+ *	Mask IRQ by writing 0 to ENABLE flag.
+ *
+ * Usage is almost like with any other IRQ:
+ *  dmabrg_request_irq(BRGIRQID, handler, data)
+ *  dmabrg_free_irq(BRGIRQID)
+ *
+ * handler prototype:  void brgirqhandler(void *data)
+ */
+
+#define DMARSRA		0xfe090000
+#define DMAOR		0xffa00040
+#define DMACHCR0	0xffa0000c
+#define DMABRGCR	0xfe3c0000
+
+#define DMAOR_BRG	0x0000c000
+#define DMAOR_DMEN	0x00000001
+
+#define DMABRGI0	68
+#define DMABRGI1	69
+#define DMABRGI2	70
+
+struct dmabrg_handler {
+	void (*handler)(void *);
+	void *data;
+} *dmabrg_handlers;
+
+static inline void dmabrg_call_handler(int i)
+{
+	dmabrg_handlers[i].handler(dmabrg_handlers[i].data);
+}
+
+/*
+ * main DMABRG irq handler. It acks irqs and then
+ * handles every set and unmasked bit sequentially.
+ * No locking and no validity checks; it should be
+ * as fast as possible (audio!)
+ */
+static irqreturn_t dmabrg_irq(int irq, void *data)
+{
+	unsigned long dcr;
+	unsigned int i;
+
+	dcr = ctrl_inl(DMABRGCR);
+	ctrl_outl(dcr & ~0x00ff0003, DMABRGCR);	/* ack all */
+	dcr &= dcr >> 8;	/* ignore masked */
+
+	/* USB stuff, get it out of the way first */
+	if (dcr & 1)
+		dmabrg_call_handler(DMABRGIRQ_USBDMA);
+	if (dcr & 2)
+		dmabrg_call_handler(DMABRGIRQ_USBDMAERR);
+
+	/* Audio */
+	dcr >>= 16;
+	while (dcr) {
+		i = __ffs(dcr);
+		dcr &= dcr - 1;
+		dmabrg_call_handler(i + DMABRGIRQ_A0TXF);
+	}
+	return IRQ_HANDLED;
+}
+
+static void dmabrg_disable_irq(unsigned int dmairq)
+{
+	unsigned long dcr;
+	dcr = ctrl_inl(DMABRGCR);
+	dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+	ctrl_outl(dcr, DMABRGCR);
+}
+
+static void dmabrg_enable_irq(unsigned int dmairq)
+{
+	unsigned long dcr;
+	dcr = ctrl_inl(DMABRGCR);
+	dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+	ctrl_outl(dcr, DMABRGCR);
+}
+
+int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*),
+		       void *data)
+{
+	if ((dmairq > 9) || !handler)
+		return -ENOENT;
+	if (dmabrg_handlers[dmairq].handler)
+		return -EBUSY;
+
+	dmabrg_handlers[dmairq].handler = handler;
+	dmabrg_handlers[dmairq].data = data;
+	
+	dmabrg_enable_irq(dmairq);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dmabrg_request_irq);
+
+void dmabrg_free_irq(unsigned int dmairq)
+{
+	if (likely(dmairq < 10)) {
+		dmabrg_disable_irq(dmairq);
+		dmabrg_handlers[dmairq].handler = NULL;
+		dmabrg_handlers[dmairq].data = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(dmabrg_free_irq);
+
+static int __init dmabrg_init(void)
+{
+	unsigned long or;
+	int ret;
+
+	dmabrg_handlers = kzalloc(10 * sizeof(struct dmabrg_handler),
+				  GFP_KERNEL);
+	if (!dmabrg_handlers)
+		return -ENOMEM;
+
+#ifdef CONFIG_SH_DMA
+	/* request DMAC channel 0 before anyone else can get it */
+	ret = request_dma(0, "DMAC 0 (DMABRG)");
+	if (ret < 0)
+		printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
+#endif
+
+	ctrl_outl(0, DMABRGCR);
+	ctrl_outl(0, DMACHCR0);
+	ctrl_outl(0x94000000, DMARSRA);	/* enable DMABRG in DMAC 0 */
+
+	/* enable DMABRG mode, enable the DMAC */
+	or = ctrl_inl(DMAOR);
+	ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR);
+
+	ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED,
+			"DMABRG USB address error", NULL);
+	if (ret)
+		goto out0;
+
+	ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED,
+			"DMABRG Transfer End", NULL);
+	if (ret)
+		goto out1;
+
+	ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED,
+			"DMABRG Transfer Half", NULL);
+	if (ret == 0)
+		return ret;
+
+	free_irq(DMABRGI1, 0);
+out1:	free_irq(DMABRGI0, 0);
+out0:	kfree(dmabrg_handlers);
+	return ret;
+}
+subsys_initcall(dmabrg_init);
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 350972a..965fa25 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -2,9 +2,8 @@
 # Makefile for the Linux/SuperH SH-2A backends.
 #
 
-obj-y	:= common.o probe.o
+obj-y	:= common.o probe.o opcode_helper.o
 
-common-y	+= $(addprefix ../sh2/, ex.o)
-common-y	+= $(addprefix ../sh2/, entry.o)
+common-y	+= $(addprefix ../sh2/, ex.o entry.o)
 
 obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
new file mode 100644
index 0000000..9704b79
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
@@ -0,0 +1,55 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/opcode_helper.c
+ *
+ * Helper for the SH-2A 32-bit opcodes.
+ *
+ *  Copyright (C) 2007  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+/*
+ * Instructions on SH are generally fixed at 16-bits, however, SH-2A
+ * introduces some 32-bit instructions. Since there are no real
+ * constraints on their use (and they can be mixed and matched), we need
+ * to check the instruction encoding to work out if it's a true 32-bit
+ * instruction or not.
+ *
+ * Presently, 32-bit opcodes have only slight variations in what the
+ * actual encoding looks like in the first-half of the instruction, which
+ * makes it fairly straightforward to differentiate from the 16-bit ones.
+ *
+ * First 16-bits of encoding		Used by
+ *
+ *	0011nnnnmmmm0001	mov.b, mov.w, mov.l, fmov.d,
+ *				fmov.s, movu.b, movu.w
+ *
+ *	0011nnnn0iii1001        bclr.b, bld.b, bset.b, bst.b, band.b,
+ *				bandnot.b, bldnot.b, bor.b, bornot.b,
+ *				bxor.b
+ *
+ *	0000nnnniiii0000        movi20
+ *	0000nnnniiii0001        movi20s
+ */
+unsigned int instruction_size(unsigned int insn)
+{
+	/* Look for the common cases */
+	switch ((insn & 0xf00f)) {
+	case 0x0000:	/* movi20 */
+	case 0x0001:	/* movi20s */
+	case 0x3001:	/* 32-bit mov/fmov/movu variants */
+		return 4;
+	}
+
+	/* And the special cases.. */
+	switch ((insn & 0xf08f)) {
+	case 0x3009:	/* 32-bit b*.b bit operations */
+		return 4;
+	}
+
+	return 2;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 426f6db..f455c35 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -18,6 +18,7 @@
 {
 	/* Just SH7206 for now .. */
 	current_cpu_data.type			= CPU_SH7206;
+	current_cpu_data.flags			|= CPU_HAS_OP32;
 
 	current_cpu_data.dcache.ways		= 4;
 	current_cpu_data.dcache.way_incr	= (1 << 11);
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index f3e827f..832c0b4 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/entry.S
+ * arch/sh/kernel/cpu/sh3/entry.S
  *
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
  *  Copyright (C) 2003 - 2006  Paul Mundt
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index ba3082d..2b2a9e0 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -1,7 +1,7 @@
 /*
  *  arch/sh/kernel/cpu/sh3/ex.S
  *
- *  The SH-3 exception vector table.
+ *  The SH-3 and SH-4 exception vector table.
 
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
  *  Copyright (C) 2003 - 2006  Paul Mundt
@@ -9,7 +9,6 @@
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
- *
  */
 #include <linux/linkage.h>
 
@@ -36,8 +35,12 @@
 	.long	exception_error	! address error load
 	.long	exception_error	! address error store	/* 100 */
 #endif
-	.long	exception_error	! fpu_exception	/* 120 */
-	.long	exception_error			/* 140 */
+#if defined(CONFIG_SH_FPU)
+	.long	do_fpu_error		/* 120 */
+#else
+	.long	exception_error		/* 120 */
+#endif
+	.long	exception_error		/* 140 */
 	.long	system_call	! Unconditional Trap	 /* 160 */
 	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
 	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
@@ -55,4 +58,4 @@
 	 * away offsets can be manually inserted in to their appropriate
 	 * location via set_exception_table_{evt,vec}().
 	 */
-	.balign 4096,0,4096
+	.balign	4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 19ca68c7..8add10b 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -2,10 +2,10 @@
 # Makefile for the Linux/SuperH SH-4 backends.
 #
 
-obj-y	:= ex.o probe.o common.o
-common-y	+= $(addprefix ../sh3/, entry.o)
+obj-y	:= probe.o common.o
+common-y	+= $(addprefix ../sh3/, entry.o ex.o)
 
-obj-$(CONFIG_SH_FPU)                    += fpu.o
+obj-$(CONFIG_SH_FPU)			+= fpu.o
 obj-$(CONFIG_SH_STORE_QUEUES)		+= sq.o
 
 # CPU subtype setup
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
deleted file mode 100644
index ac8ab57..0000000
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  arch/sh/kernel/cpu/sh4/ex.S
- *
- *  The SH-4 exception vector table.
-
- *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- *  Copyright (C) 2003 - 2006  Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-#include <linux/linkage.h>
-
-	.align 2
-	.data
-
-ENTRY(exception_handling_table)
-	.long	exception_error		/* 000 */
-	.long	exception_error
-#if defined(CONFIG_MMU)
-	.long	tlb_miss_load		/* 040 */
-	.long	tlb_miss_store
-	.long	initial_page_write
-	.long	tlb_protection_violation_load
-	.long	tlb_protection_violation_store
-	.long	address_error_load
-	.long	address_error_store	/* 100 */
-#else
-	.long	exception_error	! tlb miss load		/* 040 */
-	.long	exception_error	! tlb miss store
-	.long	exception_error	! initial page write
-	.long	exception_error	! tlb prot violation load
-	.long	exception_error	! tlb prot violation store
-	.long	exception_error	! address error load
-	.long	exception_error	! address error store	/* 100 */
-#endif
-#if defined(CONFIG_SH_FPU)
-	.long	do_fpu_error		/* 120 */
-#else
-	.long	exception_error		/* 120 */
-#endif
-	.long	exception_error		/* 140 */
-	.long	system_call	! Unconditional Trap	 /* 160 */
-	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
-	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
-ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
-	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
-#else
-	.long	exception_none	/* 1C0 */	! Not implemented yet
-#endif
-ENTRY(user_break_point_trap)
-	.long	break_point_trap	/* 1E0 */
-
-	/*
-	 * Pad the remainder of the table out, exceptions residing in far
-	 * away offsets can be manually inserted in to their appropriate
-	 * location via set_exception_table_{evt,vec}().
-	 */
-	.balign	4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index 7624677..d61dd59 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/processor.h>
+#include <asm/system.h>
 #include <asm/io.h>
 
 /* The PR (precision) bit in the FP Status Register must be clear when
@@ -265,7 +266,7 @@
 		nextpc = regs->pr;
 		finsn = *(unsigned short *) (regs->pc + 2);
 	} else {
-		nextpc = regs->pc + 2;
+		nextpc = regs->pc + instruction_size(insn);
 		finsn = insn;
 	}
 
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh73180.c b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
index 2fa5cb2..6d5ba37 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh73180.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh73180.c
  *
  * SH73180 support for the clock framework
  *
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
index 1707a21..7adc4f1 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7343.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7343.c
  *
  * SH7343/SH7722 support for the clock framework
  *
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
index c8694ba..8e23606 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7770.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7770.c
  *
  * SH7770 support for the clock framework
  *
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
index 9e6a216..01f3da6 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7780.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
  *
  * SH7780 support for the clock framework
  *
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 329b3f3..6b4f574 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -15,9 +15,12 @@
 #include <linux/pm.h>
 #include <linux/kallsyms.h>
 #include <linux/kexec.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
+#include <linux/tick.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
 #include <asm/ubc.h>
 
 static int hlt_counter;
@@ -58,12 +61,15 @@
 		if (!idle)
 			idle = default_idle;
 
+		tick_nohz_stop_sched_tick();
 		while (!need_resched())
 			idle();
+		tick_nohz_restart_sched_tick();
 
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
+		check_pgt_cache();
 	}
 }
 
@@ -495,9 +501,9 @@
 	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 
 	/* Rewind */
-	regs->pc -= 2;
+	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 
-	if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
+	if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
 		       SIGTRAP) == NOTIFY_STOP)
 		return;
 
@@ -514,9 +520,9 @@
 	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 
 	/* Rewind */
-	regs->pc -= 2;
+	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 
-	if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
+	if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
 		       SIGTRAP) == NOTIFY_STOP)
 		return;
 
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 477d2a8..c277291 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -431,7 +431,7 @@
 /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
 static const char *cpu_flags[] = {
 	"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
-	"ptea", "llsc", "l2", NULL
+	"ptea", "llsc", "l2", "op32", NULL
 };
 
 static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index fa91641..c1cfcb9 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -58,8 +58,6 @@
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__const_udelay);
 
-EXPORT_SYMBOL(__div64_32);
-
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
 
 /* These symbols are generated by the compiler itself */
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index eb0191c..b32c35a 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -23,7 +23,7 @@
 #include <linux/personality.h>
 #include <linux/binfmts.h>
 #include <linux/freezer.h>
-
+#include <asm/system.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -500,7 +500,9 @@
 				}
 			/* fallthrough */
 			case -ERESTARTNOINTR:
-				regs->pc -= 2;
+				regs->pc -= instruction_size(
+						ctrl_inw(regs->pc - 4));
+				break;
 		}
 	} else {
 		/* gUSA handling */
@@ -516,7 +518,8 @@
 			regs->regs[15] = regs->regs[1];
 			if (regs->pc < regs->regs[0])
 				/* Go to rewind point #1 */
-				regs->pc = regs->regs[0] + offset - 2;
+				regs->pc = regs->regs[0] + offset -
+					instruction_size(ctrl_inw(regs->pc-4));
 		}
 #ifdef CONFIG_PREEMPT
 		local_irq_restore(flags);
@@ -600,9 +603,9 @@
 		    regs->regs[0] == -ERESTARTSYS ||
 		    regs->regs[0] == -ERESTARTNOINTR) {
 			regs->regs[0] = save_r0;
-			regs->pc -= 2;
+			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 		} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
-			regs->pc -= 2;
+			regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 			regs->regs[3] = __NR_restart_syscall;
 		}
 	}
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
index 4bdd2f8..d41e561 100644
--- a/arch/sh/kernel/stacktrace.c
+++ b/arch/sh/kernel/stacktrace.c
@@ -17,7 +17,7 @@
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
  */
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
 	unsigned long *sp = (unsigned long *)current_stack_pointer;
 
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index 38fc8cd..4357d1a 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -354,3 +354,4 @@
 	.long sys_move_pages
 	.long sys_getcpu
 	.long sys_epoll_pwait
+	.long sys_utimensat		/* 320 */
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index d47e775..a3a67d1 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
  *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
- *  Copyright (C) 2002 - 2006  Paul Mundt
+ *  Copyright (C) 2002 - 2007  Paul Mundt
  *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
  *
  *  Some code taken from i386 version.
@@ -15,6 +15,7 @@
 #include <linux/profile.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
+#include <linux/clockchips.h>
 #include <asm/clock.h>
 #include <asm/rtc.h>
 #include <asm/timer.h>
@@ -38,6 +39,14 @@
 	return 0;
 }
 
+/*
+ * Null high precision timer functions for systems lacking one.
+ */
+static cycle_t null_hpt_read(void)
+{
+	return 0;
+}
+
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
@@ -101,6 +110,7 @@
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /* last time the RTC clock got updated */
 static long last_rtc_update;
 
@@ -138,6 +148,7 @@
 			last_rtc_update = xtime.tv_sec - 600;
 	}
 }
+#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 #ifdef CONFIG_PM
 int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -168,108 +179,6 @@
 	.resume	 = timer_resume,
 };
 
-#ifdef CONFIG_NO_IDLE_HZ
-static int timer_dyn_tick_enable(void)
-{
-	struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-	unsigned long flags;
-	int ret = -ENODEV;
-
-	if (dyn_tick) {
-		spin_lock_irqsave(&dyn_tick->lock, flags);
-		ret = 0;
-		if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
-			ret = dyn_tick->enable();
-
-			if (ret == 0)
-				dyn_tick->state |= DYN_TICK_ENABLED;
-		}
-		spin_unlock_irqrestore(&dyn_tick->lock, flags);
-	}
-
-	return ret;
-}
-
-static int timer_dyn_tick_disable(void)
-{
-	struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-	unsigned long flags;
-	int ret = -ENODEV;
-
-	if (dyn_tick) {
-		spin_lock_irqsave(&dyn_tick->lock, flags);
-		ret = 0;
-		if (dyn_tick->state & DYN_TICK_ENABLED) {
-			ret = dyn_tick->disable();
-
-			if (ret == 0)
-				dyn_tick->state &= ~DYN_TICK_ENABLED;
-		}
-		spin_unlock_irqrestore(&dyn_tick->lock, flags);
-	}
-
-	return ret;
-}
-
-/*
- * Reprogram the system timer for at least the calculated time interval.
- * This function should be called from the idle thread with IRQs disabled,
- * immediately before sleeping.
- */
-void timer_dyn_reprogram(void)
-{
-	struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-	unsigned long next, seq, flags;
-
-	if (!dyn_tick)
-		return;
-
-	spin_lock_irqsave(&dyn_tick->lock, flags);
-	if (dyn_tick->state & DYN_TICK_ENABLED) {
-		next = next_timer_interrupt();
-		do {
-			seq = read_seqbegin(&xtime_lock);
-			dyn_tick->reprogram(next - jiffies);
-		} while (read_seqretry(&xtime_lock, seq));
-	}
-	spin_unlock_irqrestore(&dyn_tick->lock, flags);
-}
-
-static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
-{
-	return sprintf(buf, "%i\n",
-		       (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
-}
-
-static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
-				  size_t count)
-{
-	unsigned int enable = simple_strtoul(buf, NULL, 2);
-
-	if (enable)
-		timer_dyn_tick_enable();
-	else
-		timer_dyn_tick_disable();
-
-	return count;
-}
-static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
-
-/*
- * dyntick=enable|disable
- */
-static char dyntick_str[4] __initdata = "";
-
-static int __init dyntick_setup(char *str)
-{
-	if (str)
-		strlcpy(dyntick_str, str, sizeof(dyntick_str));
-	return 1;
-}
-
-__setup("dyntick=", dyntick_setup);
-#endif
-
 static int __init timer_init_sysfs(void)
 {
 	int ret = sysdev_class_register(&timer_sysclass);
@@ -277,27 +186,51 @@
 		return ret;
 
 	sys_timer->dev.cls = &timer_sysclass;
-	ret = sysdev_register(&sys_timer->dev);
-
-#ifdef CONFIG_NO_IDLE_HZ
-	if (ret == 0 && sys_timer->dyn_tick) {
-		ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
-
-		/*
-		 * Turn on dynamic tick after calibrate delay
-		 * for correct bogomips
-		 */
-		if (ret == 0 && dyntick_str[0] == 'e')
-			ret = timer_dyn_tick_enable();
-	}
-#endif
-
-	return ret;
+	return sysdev_register(&sys_timer->dev);
 }
 device_initcall(timer_init_sysfs);
 
 void (*board_time_init)(void);
 
+/*
+ * Shamelessly based on the MIPS and Sparc64 work.
+ */
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
+unsigned long sh_hpt_frequency = 0;
+
+#define NSEC_PER_CYC_SHIFT	10
+
+struct clocksource clocksource_sh = {
+	.name		= "SuperH",
+	.rating		= 200,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.read		= null_hpt_read,
+	.shift		= 16,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init init_sh_clocksource(void)
+{
+	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
+		return;
+
+	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
+						  clocksource_sh.shift);
+
+	timer_ticks_per_nsec_quotient =
+		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
+
+	clocksource_register(&clocksource_sh);
+}
+
+#ifdef CONFIG_GENERIC_TIME
+unsigned long long sched_clock(void)
+{
+	unsigned long long ticks = clocksource_sh.read();
+	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
+}
+#endif
+
 void __init time_init(void)
 {
 	if (board_time_init)
@@ -316,10 +249,15 @@
 	sys_timer = get_sys_timer();
 	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
 
-#ifdef CONFIG_NO_IDLE_HZ
-	if (sys_timer->dyn_tick)
-		spin_lock_init(&sys_timer->dyn_tick->lock);
-#endif
+	if (sys_timer->ops->read)
+		clocksource_sh.read = sys_timer->ops->read;
+
+	init_sh_clocksource();
+
+	if (sh_hpt_frequency)
+		printk("Using %lu.%03lu MHz high precision timer.\n",
+		       ((sh_hpt_frequency + 500) / 1000) / 1000,
+		       ((sh_hpt_frequency + 500) / 1000) % 1000);
 
 #if defined(CONFIG_SH_KGDB)
 	/*
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index d9e3151..2d997e2 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -1,7 +1,7 @@
 /*
  * arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
  *
- *  Copyright (C) 2005  Paul Mundt
+ *  Copyright (C) 2005 - 2007  Paul Mundt
  *
  * TMU handling code hacked out of arch/sh/kernel/time.c
  *
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/seqlock.h>
+#include <linux/clockchips.h>
 #include <asm/timer.h>
 #include <asm/rtc.h>
 #include <asm/io.h>
@@ -25,56 +26,75 @@
 #include <asm/clock.h>
 
 #define TMU_TOCR_INIT	0x00
-#define TMU0_TCR_INIT	0x0020
-#define TMU_TSTR_INIT	1
+#define TMU_TCR_INIT	0x0020
 
-#define TMU0_TCR_CALIB	0x0000
-
-static unsigned long tmu_timer_get_offset(void)
+static int tmu_timer_start(void)
 {
-	int count;
-	static int count_p = 0x7fffffff;    /* for the first call after boot */
-	static unsigned long jiffies_p = 0;
-
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off.
-	 */
-	unsigned long jiffies_t;
-
-	/* timer count may underflow right here */
-	count = ctrl_inl(TMU0_TCNT);	/* read the latched count */
-
-	jiffies_t = jiffies;
-
-	/*
-	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there is one kind of problem that must be avoided here:
-	 *  1. the timer counter underflows
-	 */
-
-	if (jiffies_t == jiffies_p) {
-		if (count > count_p) {
-			/* the nutcase */
-			if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
-				count -= LATCH;
-			} else {
-				printk("%s (): hardware timer problem?\n",
-				       __FUNCTION__);
-			}
-		}
-	} else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	count = (count + LATCH/2) / LATCH;
-
-	return count;
+	ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
+	return 0;
 }
 
+static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
+{
+	ctrl_outl(interval, TMU0_TCNT);
+
+	/*
+	 * TCNT reloads from TCOR on underflow, clear it if we don't
+	 * intend to auto-reload
+	 */
+	if (reload)
+		ctrl_outl(interval, TMU0_TCOR);
+	else
+		ctrl_outl(0, TMU0_TCOR);
+
+	tmu_timer_start();
+}
+
+static int tmu_timer_stop(void)
+{
+	ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
+	return 0;
+}
+
+static cycle_t tmu_timer_read(void)
+{
+	return ~ctrl_inl(TMU1_TCNT);
+}
+
+static int tmu_set_next_event(unsigned long cycles,
+			      struct clock_event_device *evt)
+{
+	tmu0_timer_set_interval(cycles, 1);
+	return 0;
+}
+
+static void tmu_set_mode(enum clock_event_mode mode,
+			 struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		ctrl_outl(0, TMU0_TCOR);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		break;
+	}
+}
+
+static struct clock_event_device tmu0_clockevent = {
+	.name		= "tmu0",
+	.shift		= 32,
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= tmu_set_mode,
+	.set_next_event	= tmu_set_next_event,
+};
+
 static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
 {
+	struct clock_event_device *evt = &tmu0_clockevent;
 	unsigned long timer_status;
 
 	/* Clear UNF bit */
@@ -82,72 +102,76 @@
 	timer_status &= ~0x100;
 	ctrl_outw(timer_status, TMU0_TCR);
 
-	/*
-	 * Here we are in the timer irq handler. We just have irqs locally
-	 * disabled but we don't know if the timer_bh is running on the other
-	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-	 * the irq version of write_lock because as just said we have irq
-	 * locally disabled. -arca
-	 */
-	write_seqlock(&xtime_lock);
-	handle_timer_tick();
-	write_sequnlock(&xtime_lock);
+	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
 }
 
-static struct irqaction tmu_irq = {
-	.name		= "timer",
+static struct irqaction tmu0_irq = {
+	.name		= "periodic timer",
 	.handler	= tmu_timer_interrupt,
 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.mask		= CPU_MASK_NONE,
 };
 
-static void tmu_clk_init(struct clk *clk)
+static void tmu0_clk_init(struct clk *clk)
 {
-	u8 divisor = TMU0_TCR_INIT & 0x7;
-	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+	u8 divisor = TMU_TCR_INIT & 0x7;
+	ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
 	clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static void tmu_clk_recalc(struct clk *clk)
+static void tmu0_clk_recalc(struct clk *clk)
 {
 	u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
 	clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static struct clk_ops tmu_clk_ops = {
-	.init		= tmu_clk_init,
-	.recalc		= tmu_clk_recalc,
+static struct clk_ops tmu0_clk_ops = {
+	.init		= tmu0_clk_init,
+	.recalc		= tmu0_clk_recalc,
 };
 
 static struct clk tmu0_clk = {
 	.name		= "tmu0_clk",
-	.ops		= &tmu_clk_ops,
+	.ops		= &tmu0_clk_ops,
 };
 
-static int tmu_timer_start(void)
+static void tmu1_clk_init(struct clk *clk)
 {
-	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-	return 0;
+	u8 divisor = TMU_TCR_INIT & 0x7;
+	ctrl_outw(divisor, TMU1_TCR);
+	clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static int tmu_timer_stop(void)
+static void tmu1_clk_recalc(struct clk *clk)
 {
-	ctrl_outb(0, TMU_TSTR);
-	return 0;
+	u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
+	clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
+static struct clk_ops tmu1_clk_ops = {
+	.init		= tmu1_clk_init,
+	.recalc		= tmu1_clk_recalc,
+};
+
+static struct clk tmu1_clk = {
+	.name		= "tmu1_clk",
+	.ops		= &tmu1_clk_ops,
+};
+
 static int tmu_timer_init(void)
 {
 	unsigned long interval;
+	unsigned long frequency;
 
-	setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq);
+	setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
 
 	tmu0_clk.parent = clk_get(NULL, "module_clk");
+	tmu1_clk.parent = clk_get(NULL, "module_clk");
 
-	/* Start TMU0 */
 	tmu_timer_stop();
+
 #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7785)
@@ -155,15 +179,29 @@
 #endif
 
 	clk_register(&tmu0_clk);
+	clk_register(&tmu1_clk);
 	clk_enable(&tmu0_clk);
+	clk_enable(&tmu1_clk);
 
-	interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ;
-	printk(KERN_INFO "Interval = %ld\n", interval);
+	frequency = clk_get_rate(&tmu0_clk);
+	interval = (frequency + HZ / 2) / HZ;
 
-	ctrl_outl(interval, TMU0_TCOR);
-	ctrl_outl(interval, TMU0_TCNT);
+	sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+	ctrl_outl(~0, TMU1_TCNT);
+	ctrl_outl(~0, TMU1_TCOR);
 
-	tmu_timer_start();
+	tmu0_timer_set_interval(interval, 1);
+
+	tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
+				      tmu0_clockevent.shift);
+	tmu0_clockevent.max_delta_ns =
+			clockevent_delta2ns(-1, &tmu0_clockevent);
+	tmu0_clockevent.min_delta_ns =
+			clockevent_delta2ns(1, &tmu0_clockevent);
+
+	tmu0_clockevent.cpumask = cpumask_of_cpu(0);
+
+	clockevents_register_device(&tmu0_clockevent);
 
 	return 0;
 }
@@ -172,9 +210,7 @@
 	.init		= tmu_timer_init,
 	.start		= tmu_timer_start,
 	.stop		= tmu_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
-	.get_offset	= tmu_timer_get_offset,
-#endif
+	.read		= tmu_timer_read,
 };
 
 struct sys_timer tmu_timer = {
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 7b40f0f..3a19764 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -20,10 +20,10 @@
 #include <linux/io.h>
 #include <linux/bug.h>
 #include <linux/debug_locks.h>
+#include <linux/kdebug.h>
 #include <linux/limits.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/kdebug.h>
 
 #ifdef CONFIG_SH_KGDB
 #include <asm/kgdb.h>
@@ -76,20 +76,6 @@
 	}
 }
 
-ATOMIC_NOTIFIER_HEAD(shdie_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
 static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -505,7 +491,7 @@
  simple:
 	ret = handle_unaligned_ins(instruction,regs);
 	if (ret==0)
-		regs->pc += 2;
+		regs->pc += instruction_size(instruction);
 	return ret;
 }
 #endif /* CONFIG_CPU_SH2A */
@@ -682,7 +668,7 @@
 
 	err = do_fpu_inst(inst, regs);
 	if (!err) {
-		regs->pc += 2;
+		regs->pc += instruction_size(inst);
 		return;
 	}
 	/* not a FPU inst. */
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index 7b0f66f..e146baf 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/vsyscall.c
+ * arch/sh/kernel/vsyscall/vsyscall.c
  *
  *  Copyright (C) 2006 Paul Mundt
  *
diff --git a/arch/sh/lib/delay.c b/arch/sh/lib/delay.c
index 3517146..f3ddd21 100644
--- a/arch/sh/lib/delay.c
+++ b/arch/sh/lib/delay.c
@@ -24,9 +24,10 @@
 	__asm__("dmulu.l	%0, %2\n\t"
 		"sts	mach, %0"
 		: "=r" (xloops)
-		: "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy)
+		: "0" (xloops),
+		  "r" (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy)
 		: "macl", "mach");
-	__delay(xloops * HZ);
+	__delay(xloops);
 }
 
 void __udelay(unsigned long usecs)
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 12f3d39..253346d 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -218,6 +218,9 @@
 
 menu "Memory management options"
 
+config QUICKLIST
+	def_bool y
+
 config MMU
         bool "Support for memory management hardware"
 	depends on !CPU_SH2
@@ -300,6 +303,10 @@
 config ARCH_FLATMEM_ENABLE
 	def_bool y
 
+config MAX_ACTIVE_REGIONS
+	int
+	default "1"
+
 config ARCH_POPULATES_NODE_MAP
 	def_bool y
 
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 0ecc117..9207da6 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -15,7 +15,7 @@
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 4d03098..8fe223a 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -67,6 +67,8 @@
 	printk("%d slab pages\n", slab);
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
+	printk(KERN_INFO "Total of %ld pages in page table cache\n",
+	       quicklist_total_size());
 }
 
 #ifdef CONFIG_MMU
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index 29d7cfd..6773ed7 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -28,7 +28,7 @@
 	DEFINE(AOFF_task_gid, offsetof(struct task_struct, gid));
 	DEFINE(AOFF_task_euid, offsetof(struct task_struct, euid));
 	DEFINE(AOFF_task_egid, offsetof(struct task_struct, egid));
-	/* DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); */
+	/* DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); */
 	DEFINE(ASIZ_task_uid,	sizeof(current->uid));
 	DEFINE(ASIZ_task_gid,	sizeof(current->gid));
 	DEFINE(ASIZ_task_euid,	sizeof(current->euid));
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 3a69778..e3f5b8e 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -80,6 +80,7 @@
 /*295*/	.long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/	.long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/	.long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/	.long sys_utimensat
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
@@ -196,5 +197,6 @@
 	.long sunos_nosys, sunos_nosys, sunos_nosys
 	.long sunos_nosys, sunos_nosys, sunos_nosys
 	.long sunos_nosys
+/*310*/	.long sunos_nosys
 
 #endif
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 0ace17b..ad55a9b 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -13,16 +13,17 @@
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 
 #include <asm/system.h>
 #include <asm/page.h>
-#include <asm/pbm.h>
 #include <asm/ebus.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
+#include <asm/io.h>
 
 /* EBUS dma library. */
 
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index a44fe47..c93a15b 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -313,7 +313,7 @@
 	return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -403,15 +403,6 @@
 		if (post_kprobe_handler(args->regs))
 			ret = NOTIFY_STOP;
 		break;
-	case DIE_GPF:
-	case DIE_PAGE_FAULT:
-		/* kprobe_running() needs smp_processor_id() */
-		preempt_disable();
-		if (kprobe_running() &&
-		    kprobe_fault_handler(args->regs, args->trapnr))
-			ret = NOTIFY_STOP;
-		preempt_enable();
-		break;
 	default:
 		break;
 	}
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 966861b..d85e1ed 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -14,12 +14,12 @@
 #include <linux/sched.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <linux/pci.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
-#include <asm/pbm.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/ebus.h>
@@ -48,10 +48,10 @@
 #else
 
 /* List of all PCI controllers found in the system. */
-struct pci_controller_info *pci_controller_root = NULL;
+struct pci_pbm_info *pci_pbm_root = NULL;
 
-/* Each PCI controller found gets a unique index. */
-int pci_num_controllers = 0;
+/* Each PBM found gets a unique index. */
+int pci_num_pbms = 0;
 
 volatile int pci_poke_in_progress;
 volatile int pci_poke_cpu = -1;
@@ -291,7 +291,7 @@
 
 /* Find each controller in the system, attach and initialize
  * software state structure for each and link into the
- * pci_controller_root.  Setup the controller enough such
+ * pci_pbm_root.  Setup the controller enough such
  * that bus scanning can be done.
  */
 static void __init pci_controller_probe(void)
@@ -743,7 +743,6 @@
 
 struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
 {
-	struct pci_controller_info *p = pbm->parent;
 	struct device_node *node = pbm->prom_node;
 	struct pci_dev *host_pdev;
 	struct pci_bus *bus;
@@ -751,7 +750,7 @@
 	printk("PCI: Scanning PBM %s\n", node->full_name);
 
 	/* XXX parent device? XXX */
-	bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
+	bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
 	if (!bus) {
 		printk(KERN_ERR "Failed to create bus for %s\n",
 		       node->full_name);
@@ -776,10 +775,10 @@
 
 static void __init pci_scan_each_controller_bus(void)
 {
-	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
 
-	for (p = pci_controller_root; p; p = p->next)
-		p->scan_bus(p);
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
+		pbm->scan_bus(pbm);
 }
 
 extern void power_init(void);
@@ -787,7 +786,7 @@
 static int __init pcibios_init(void)
 {
 	pci_controller_probe();
-	if (pci_controller_root == NULL)
+	if (pci_pbm_root == NULL)
 		return 0;
 
 	pci_scan_each_controller_bus();
@@ -922,10 +921,8 @@
 				      enum pci_mmap_state mmap_state)
 {
 	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-	struct pci_controller_info *p;
 	unsigned long space_size, user_offset, user_size;
 
-	p = pbm->parent;
 	if (mmap_state == pci_mmap_io) {
 		space_size = (pbm->io_space.end -
 			      pbm->io_space.start) + 1;
@@ -1078,11 +1075,7 @@
 	if (pbm == NULL || pbm->parent == NULL) {
 		ret = -ENXIO;
 	} else {
-		struct pci_controller_info *p = pbm->parent;
-
-		ret = p->index;
-		ret = ((ret << 1) +
-		       ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
+		ret = pbm->index;
 	}
 
 	return ret;
@@ -1093,17 +1086,12 @@
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
 	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-	struct pci_controller_info *p = pbm->parent;
-	int virt_irq, err;
+	int virt_irq;
 
-	if (!pbm->msi_num || !p->setup_msi_irq)
+	if (!pbm->setup_msi_irq)
 		return -EINVAL;
 
-	err = p->setup_msi_irq(&virt_irq, pdev, desc);
-	if (err)
-		return err;
-
-	return 0;
+	return pbm->setup_msi_irq(&virt_irq, pdev, desc);
 }
 
 void arch_teardown_msi_irq(unsigned int virt_irq)
@@ -1111,12 +1099,11 @@
 	struct msi_desc *entry = get_irq_msi(virt_irq);
 	struct pci_dev *pdev = entry->dev;
 	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-	struct pci_controller_info *p = pbm->parent;
 
-	if (!pbm->msi_num || !p->setup_msi_irq)
+	if (!pbm->teardown_msi_irq)
 		return;
 
-	return p->teardown_msi_irq(virt_irq, pdev);
+	return pbm->teardown_msi_irq(virt_irq, pdev);
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 1e6aeed..76faaa8 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -9,12 +9,26 @@
 #include <linux/pci.h>
 #include <linux/device.h>
 
-#include <asm/pbm.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
 
+void pci_get_pbm_props(struct pci_pbm_info *pbm)
+{
+	const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+
+	pbm->pci_first_busno = val[0];
+	pbm->pci_last_busno = val[1];
+
+	val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+	if (val) {
+		pbm->ino_bitmap = (((u64)val[1] << 32UL) |
+				   ((u64)val[0] <<  0UL));
+	}
+}
+
 static void pci_register_legacy_regions(struct resource *io_res,
 					struct resource *mem_res)
 {
@@ -149,8 +163,7 @@
 }
 
 /* Generic helper routines for PCI error reporting. */
-void pci_scan_for_target_abort(struct pci_controller_info *p,
-			       struct pci_pbm_info *pbm,
+void pci_scan_for_target_abort(struct pci_pbm_info *pbm,
 			       struct pci_bus *pbus)
 {
 	struct pci_dev *pdev;
@@ -165,18 +178,16 @@
 				   PCI_STATUS_REC_TARGET_ABORT));
 		if (error_bits) {
 			pci_write_config_word(pdev, PCI_STATUS, error_bits);
-			printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
-			       p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-			       pci_name(pdev), status);
+			printk("%s: Device %s saw Target Abort [%016x]\n",
+			       pbm->name, pci_name(pdev), status);
 		}
 	}
 
 	list_for_each_entry(bus, &pbus->children, node)
-		pci_scan_for_target_abort(p, pbm, bus);
+		pci_scan_for_target_abort(pbm, bus);
 }
 
-void pci_scan_for_master_abort(struct pci_controller_info *p,
-			       struct pci_pbm_info *pbm,
+void pci_scan_for_master_abort(struct pci_pbm_info *pbm,
 			       struct pci_bus *pbus)
 {
 	struct pci_dev *pdev;
@@ -190,18 +201,16 @@
 			(status & (PCI_STATUS_REC_MASTER_ABORT));
 		if (error_bits) {
 			pci_write_config_word(pdev, PCI_STATUS, error_bits);
-			printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
-			       p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-			       pci_name(pdev), status);
+			printk("%s: Device %s received Master Abort [%016x]\n",
+			       pbm->name, pci_name(pdev), status);
 		}
 	}
 
 	list_for_each_entry(bus, &pbus->children, node)
-		pci_scan_for_master_abort(p, pbm, bus);
+		pci_scan_for_master_abort(pbm, bus);
 }
 
-void pci_scan_for_parity_error(struct pci_controller_info *p,
-			       struct pci_pbm_info *pbm,
+void pci_scan_for_parity_error(struct pci_pbm_info *pbm,
 			       struct pci_bus *pbus)
 {
 	struct pci_dev *pdev;
@@ -216,12 +225,11 @@
 				   PCI_STATUS_DETECTED_PARITY));
 		if (error_bits) {
 			pci_write_config_word(pdev, PCI_STATUS, error_bits);
-			printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
-			       p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-			       pci_name(pdev), status);
+			printk("%s: Device %s saw Parity Error [%016x]\n",
+			       pbm->name, pci_name(pdev), status);
 		}
 	}
 
 	list_for_each_entry(bus, &pbus->children, node)
-		pci_scan_for_parity_error(p, pbm, bus);
+		pci_scan_for_parity_error(pbm, bus);
 }
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index 0fe6266..2e0eb4e 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -7,7 +7,6 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 
-#include <asm/pbm.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 
@@ -160,21 +159,9 @@
 	.write	=	fire_write_pci_cfg,
 };
 
-static void pbm_scan_bus(struct pci_controller_info *p,
-			 struct pci_pbm_info *pbm)
+static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
 {
 	pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void pci_fire_scan_bus(struct pci_controller_info *p)
-{
-	struct device_node *dp;
-
-	if ((dp = p->pbm_A.prom_node) != NULL)
-		pbm_scan_bus(p, &p->pbm_A);
-
-	if ((dp = p->pbm_B.prom_node) != NULL)
-		pbm_scan_bus(p, &p->pbm_B);
 
 	/* XXX register error interrupt handlers XXX */
 }
@@ -313,18 +300,24 @@
 }
 
 static void pci_fire_pbm_init(struct pci_controller_info *p,
-				struct device_node *dp, u32 portid)
+			      struct device_node *dp, u32 portid)
 {
 	const struct linux_prom64_registers *regs;
 	struct pci_pbm_info *pbm;
-	const u32 *ino_bitmap;
-	const unsigned int *busrange;
 
 	if ((portid & 1) == 0)
 		pbm = &p->pbm_A;
 	else
 		pbm = &p->pbm_B;
 
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	pbm->scan_bus = pci_fire_scan_bus;
+	pbm->pci_ops = &pci_fire_ops;
+
+	pbm->index = pci_num_pbms++;
+
 	pbm->portid = portid;
 	pbm->parent = p;
 	pbm->prom_node = dp;
@@ -338,13 +331,7 @@
 
 	pci_determine_mem_io_space(pbm);
 
-	ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
-	pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
-			   ((u64)ino_bitmap[0] <<  0UL));
-
-	busrange = of_get_property(dp, "bus-range", NULL);
-	pbm->pci_first_busno = busrange[0];
-	pbm->pci_last_busno = busrange[1];
+	pci_get_pbm_props(pbm);
 
 	pci_fire_hw_init(pbm);
 	pci_fire_pbm_iommu_init(pbm);
@@ -362,19 +349,11 @@
 	struct pci_controller_info *p;
 	u32 portid = of_getintprop_default(dp, "portid", 0xff);
 	struct iommu *iommu;
+	struct pci_pbm_info *pbm;
 
-	for (p = pci_controller_root; p; p = p->next) {
-		struct pci_pbm_info *pbm;
-
-		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-			continue;
-
-		pbm = (p->pbm_A.prom_node ?
-		       &p->pbm_A :
-		       &p->pbm_B);
-
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
 		if (portid_compare(pbm->portid, portid)) {
-			pci_fire_pbm_init(p, dp, portid);
+			pci_fire_pbm_init(pbm->parent, dp, portid);
 			return;
 		}
 	}
@@ -395,14 +374,7 @@
 
 	p->pbm_B.iommu = iommu;
 
-	p->next = pci_controller_root;
-	pci_controller_root = p;
-
-	p->index = pci_num_controllers++;
-
-	p->scan_bus = pci_fire_scan_bus;
 	/* XXX MSI support XXX */
-	p->pci_ops = &pci_fire_ops;
 
 	/* Like PSYCHO and SCHIZO we have a 2GB aligned area
 	 * for memory space.
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 1208583..8e38023 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -8,15 +8,129 @@
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/iommu.h>
 
-extern struct pci_controller_info *pci_controller_root;
+/* The abstraction used here is that there are PCI controllers,
+ * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
+ * underneath.  Each PCI bus module uses an IOMMU (shared by both
+ * PBMs of a controller, or per-PBM), and if a streaming buffer
+ * is present, each PCI bus module has it's own. (ie. the IOMMU
+ * might be shared between PBMs, the STC is never shared)
+ * Furthermore, each PCI bus module controls it's own autonomous
+ * PCI bus.
+ */
+
+#define PCI_STC_FLUSHFLAG_INIT(STC) \
+	(*((STC)->strbuf_flushflag) = 0UL)
+#define PCI_STC_FLUSHFLAG_SET(STC) \
+	(*((STC)->strbuf_flushflag) != 0UL)
+
+struct pci_controller_info;
+
+struct pci_pbm_info {
+	struct pci_pbm_info		*next;
+	int				index;
+
+	/* PCI controller we sit under. */
+	struct pci_controller_info	*parent;
+
+	/* Physical address base of controller registers. */
+	unsigned long			controller_regs;
+
+	/* Physical address base of PBM registers. */
+	unsigned long			pbm_regs;
+
+	/* Physical address of DMA sync register, if any.  */
+	unsigned long			sync_reg;
+
+	/* Opaque 32-bit system bus Port ID. */
+	u32				portid;
+
+	/* Opaque 32-bit handle used for hypervisor calls.  */
+	u32				devhandle;
+
+	/* Chipset version information. */
+	int				chip_type;
+#define PBM_CHIP_TYPE_SABRE		1
+#define PBM_CHIP_TYPE_PSYCHO		2
+#define PBM_CHIP_TYPE_SCHIZO		3
+#define PBM_CHIP_TYPE_SCHIZO_PLUS	4
+#define PBM_CHIP_TYPE_TOMATILLO		5
+	int				chip_version;
+	int				chip_revision;
+
+	/* Name used for top-level resources. */
+	char				*name;
+
+	/* OBP specific information. */
+	struct device_node		*prom_node;
+	u64				ino_bitmap;
+
+	/* PBM I/O and Memory space resources. */
+	struct resource			io_space;
+	struct resource			mem_space;
+
+	/* Base of PCI Config space, can be per-PBM or shared. */
+	unsigned long			config_space;
+
+	/* State of 66MHz capabilities on this PBM. */
+	int				is_66mhz_capable;
+	int				all_devs_66mhz;
+
+#ifdef CONFIG_PCI_MSI
+	/* MSI info.  */
+	u32				msiq_num;
+	u32				msiq_ent_count;
+	u32				msiq_first;
+	u32				msiq_first_devino;
+	u32				msi_num;
+	u32				msi_first;
+	u32				msi_data_mask;
+	u32				msix_data_width;
+	u64				msi32_start;
+	u64				msi64_start;
+	u32				msi32_len;
+	u32				msi64_len;
+	void				*msi_queues;
+	unsigned long			*msi_bitmap;
+	int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
+			     struct msi_desc *entry);
+	void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
+#endif /* !(CONFIG_PCI_MSI) */
+
+	/* This PBM's streaming buffer. */
+	struct strbuf			stc;
+
+	/* IOMMU state, potentially shared by both PBM segments. */
+	struct iommu			*iommu;
+
+	/* Now things for the actual PCI bus probes. */
+	unsigned int			pci_first_busno;
+	unsigned int			pci_last_busno;
+	struct pci_bus			*pci_bus;
+	void (*scan_bus)(struct pci_pbm_info *);
+	struct pci_ops			*pci_ops;
+};
+
+struct pci_controller_info {
+	/* The PCI bus modules controlled by us. */
+	struct pci_pbm_info		pbm_A;
+	struct pci_pbm_info		pbm_B;
+};
+
+extern struct pci_pbm_info *pci_pbm_root;
 extern unsigned long pci_memspace_mask;
 
-extern int pci_num_controllers;
+extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
+extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize,
+				 u32 dma_offset, u32 dma_addr_mask);
+extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
 extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
@@ -30,9 +144,9 @@
 					 u32 value);
 
 /* Error reporting support. */
-extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *);
 
 /* Configuration space access. */
 extern void pci_config_read8(u8 *addr, u8 *ret);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 9e405cb..dfd6f9f 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -8,10 +8,12 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 
-#include <asm/pbm.h>
+#include <asm/oplib.h>
 
 #include "iommu_common.h"
+#include "pci_impl.h"
 
 #define PCI_STC_CTXMATCH_ADDR(STC, CTX)	\
 	((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 253d40e..2edcb1d 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -12,12 +12,12 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/starfire.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -98,13 +98,8 @@
 			       unsigned char bus,
 			       unsigned char devfn)
 {
-	return ((pbm->parent == 0) ||
-		((pbm == &pbm->parent->pbm_B) &&
-		 (bus == pbm->pci_first_busno) &&
-		 PCI_SLOT(devfn) > 8) ||
-		((pbm == &pbm->parent->pbm_A) &&
-		 (bus == pbm->pci_first_busno) &&
-		 PCI_SLOT(devfn) > 8));
+	return ((bus == pbm->pci_first_busno) &&
+		PCI_SLOT(devfn) > 8);
 }
 
 /* PSYCHO PCI configuration space accessors. */
@@ -265,12 +260,11 @@
 static unsigned long stc_tag_buf[16];
 static unsigned long stc_line_buf[16];
 
-static void __psycho_check_one_stc(struct pci_controller_info *p,
-				   struct pci_pbm_info *pbm,
+static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
 				   int is_pbm_a)
 {
 	struct strbuf *strbuf = &pbm->stc;
-	unsigned long regbase = p->pbm_A.controller_regs;
+	unsigned long regbase = pbm->controller_regs;
 	unsigned long err_base, tag_base, line_base;
 	u64 control;
 	int i;
@@ -326,9 +320,8 @@
 			unsigned long errval = stc_error_buf[j];
 			if (errval != 0) {
 				saw_error++;
-				printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n",
-				       p->index,
-				       (is_pbm_a ? 'A' : 'B'),
+				printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
+				       pbm->name,
 				       j,
 				       (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
 				       (errval & PSYCHO_STCERR_READ) ? 1 : 0);
@@ -337,18 +330,16 @@
 		if (saw_error != 0) {
 			unsigned long tagval = stc_tag_buf[i];
 			unsigned long lineval = stc_line_buf[i];
-			printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
-			       p->index,
-			       (is_pbm_a ? 'A' : 'B'),
+			printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
+			       pbm->name,
 			       i,
 			       ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
 			       (tagval & PSYCHO_STCTAG_VPN),
 			       ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
 			       ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
-			printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+			printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
 			       "V(%d)FOFN(%d)]\n",
-			       p->index,
-			       (is_pbm_a ? 'A' : 'B'),
+			       pbm->name,
 			       i,
 			       ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
 			       ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
@@ -362,20 +353,13 @@
 	spin_unlock(&stc_buf_lock);
 }
 
-static void __psycho_check_stc_error(struct pci_controller_info *p,
+static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
 				     unsigned long afsr,
 				     unsigned long afar,
 				     enum psycho_error_type type)
 {
-	struct pci_pbm_info *pbm;
-
-	pbm = &p->pbm_A;
-	if (pbm->stc.strbuf_enabled)
-		__psycho_check_one_stc(p, pbm, 1);
-
-	pbm = &p->pbm_B;
-	if (pbm->stc.strbuf_enabled)
-		__psycho_check_one_stc(p, pbm, 0);
+	__psycho_check_one_stc(pbm,
+			       (pbm == &pbm->parent->pbm_A));
 }
 
 /* When an Uncorrectable Error or a PCI Error happens, we
@@ -413,12 +397,12 @@
 #define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
 #define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
 #define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_controller_info *p,
+static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
 				     unsigned long afsr,
 				     unsigned long afar,
 				     enum psycho_error_type type)
 {
-	struct iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long iommu_tag[16];
 	unsigned long iommu_data[16];
 	unsigned long flags;
@@ -449,8 +433,8 @@
 			type_string = "ECC Error";
 			break;
 		};
-		printk("PSYCHO%d: IOMMU Error, type[%s]\n",
-		       p->index, type_string);
+		printk("%s: IOMMU Error, type[%s]\n",
+		       pbm->name, type_string);
 
 		/* Put the IOMMU into diagnostic mode and probe
 		 * it's TLB for entries with error status.
@@ -465,7 +449,7 @@
 		psycho_write(iommu->iommu_control,
 			     control | PSYCHO_IOMMU_CTRL_DENAB);
 		for (i = 0; i < 16; i++) {
-			unsigned long base = p->pbm_A.controller_regs;
+			unsigned long base = pbm->controller_regs;
 
 			iommu_tag[i] =
 				psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
@@ -503,20 +487,20 @@
 				type_string = "ECC Error";
 				break;
 			};
-			printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
-			       p->index, i, type_string,
+			printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
+			       pbm->name, i, type_string,
 			       ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
 			       ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
 			       ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
 			       (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
-			printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-			       p->index, i,
+			printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+			       pbm->name, i,
 			       ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
 			       ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
 			       (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
 		}
 	}
-	__psycho_check_stc_error(p, afsr, afar, type);
+	__psycho_check_stc_error(pbm, afsr, afar, type);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -541,9 +525,10 @@
 
 static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
-	unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	struct pci_controller_info *p = pbm->parent;
+	unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -560,22 +545,22 @@
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: Uncorrectable Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & PSYCHO_UEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & PSYCHO_UEAFSR_PDRD) ?
 		  "DMA Read" :
 		  ((error_bits & PSYCHO_UEAFSR_PDWR) ?
 		   "DMA Write" : "???")))));
-	printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
-	       p->index,
+	printk("%s: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
+	       pbm->name,
 	       (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL,
 	       (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL,
 	       (afsr & PSYCHO_UEAFSR_MID) >> 24UL,
 	       ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0));
-	printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar);
-	printk("PSYCHO%d: UE Secondary errors [", p->index);
+	printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: UE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & PSYCHO_UEAFSR_SPIO) {
 		reported++;
@@ -593,8 +578,9 @@
 		printk("(none)");
 	printk("]\n");
 
-	/* Interrogate IOMMU for error status. */
-	psycho_check_iommu_error(p, afsr, afar, UE_ERR);
+	/* Interrogate both IOMMUs for error status. */
+	psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
+	psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
 
 	return IRQ_HANDLED;
 }
@@ -618,9 +604,9 @@
 
 static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
-	unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -637,8 +623,8 @@
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: Correctable Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & PSYCHO_CEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & PSYCHO_CEAFSR_PDRD) ?
@@ -649,16 +635,16 @@
 	/* XXX Use syndrome and afar to print out module string just like
 	 * XXX UDB CE trap handler does... -DaveM
 	 */
-	printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+	printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
 	       "UPA_MID[%02lx] was_block(%d)\n",
-	       p->index,
+	       pbm->name,
 	       (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,
 	       (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,
 	       (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,
 	       (afsr & PSYCHO_CEAFSR_MID) >> 24UL,
 	       ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));
-	printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);
-	printk("PSYCHO%d: CE Secondary errors [", p->index);
+	printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: CE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & PSYCHO_CEAFSR_SPIO) {
 		reported++;
@@ -773,8 +759,8 @@
 	psycho_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",
-	       p->index, (is_pbm_a ? 'A' : 'B'),
+	printk("%s: PCI Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & PSYCHO_PCIAFSR_PMA) ?
 		 "Master Abort" :
 		 ((error_bits & PSYCHO_PCIAFSR_PTA) ?
@@ -783,15 +769,13 @@
 		   "Excessive Retries" :
 		   ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
 		    "Parity Error" : "???"))))));
-	printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
-	       p->index, (is_pbm_a ? 'A' : 'B'),
+	printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+	       pbm->name,
 	       (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
 	       (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
 	       (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
-	printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",
-	       p->index, (is_pbm_a ? 'A' : 'B'), afar);
-	printk("PSYCHO%d(PBM%c): PCI Secondary errors [",
-	       p->index, (is_pbm_a ? 'A' : 'B'));
+	printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: PCI Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & PSYCHO_PCIAFSR_SMA) {
 		reported++;
@@ -823,11 +807,11 @@
 	 * a bug in the IOMMU support code or a PCI device driver.
 	 */
 	if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
-		psycho_check_iommu_error(p, afsr, afar, PCI_ERR);
-		pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+		psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+		pci_scan_for_target_abort(pbm, pbm->pci_bus);
 	}
 	if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
-		pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+		pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
 	/* For excessive retries, PSYCHO/PBM will abort the device
 	 * and there is no way to specifically check for excessive
@@ -837,7 +821,7 @@
 	 */
 
 	if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
-		pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+		pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
 	return IRQ_HANDLED;
 }
@@ -847,34 +831,49 @@
 #define  PSYCHO_ECCCTRL_EE	 0x8000000000000000UL /* Enable ECC Checking */
 #define  PSYCHO_ECCCTRL_UE	 0x4000000000000000UL /* Enable UE Interrupts */
 #define  PSYCHO_ECCCTRL_CE	 0x2000000000000000UL /* Enable CE INterrupts */
-static void psycho_register_error_handlers(struct pci_controller_info *p)
+static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
 	struct of_device *op = of_find_device_by_node(pbm->prom_node);
-	unsigned long base = p->pbm_A.controller_regs;
+	unsigned long base = pbm->controller_regs;
 	u64 tmp;
+	int err;
 
 	if (!op)
 		return;
 
 	/* Psycho interrupt property order is:
-	 * 0: PCIERR PBM B INO
+	 * 0: PCIERR INO for this PBM
 	 * 1: UE ERR
 	 * 2: CE ERR
 	 * 3: POWER FAIL
 	 * 4: SPARE HARDWARE
-	 * 5: PCIERR PBM A INO
+	 * 5: POWER MANAGEMENT
 	 */
 
 	if (op->num_irqs < 6)
 		return;
 
-	request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
-	request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
-	request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
-		    "PSYCHO PCIERR-A", &p->pbm_A);
-	request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
-		    "PSYCHO PCIERR-B", &p->pbm_B);
+	/* We really mean to ignore the return result here.  Two
+	 * PCI controller share the same interrupt numbers and
+	 * drive the same front-end hardware.  Whichever of the
+	 * two get in here first will register the IRQ handler
+	 * the second will just error out since we do not pass in
+	 * IRQF_SHARED.
+	 */
+	err = request_irq(op->irqs[1], psycho_ue_intr, 0,
+			  "PSYCHO_UE", pbm);
+	err = request_irq(op->irqs[2], psycho_ce_intr, 0,
+			  "PSYCHO_CE", pbm);
+
+	/* This one, however, ought not to fail.  We can just warn
+	 * about it since the system can still operate properly even
+	 * if this fails.
+	 */
+	err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
+			  "PSYCHO_PCIERR", pbm);
+	if (err)
+		printk(KERN_WARNING "%s: Could not register PCIERR, "
+		       "err=%d\n", pbm->name, err);
 
 	/* Enable UE and CE interrupts for controller. */
 	psycho_write(base + PSYCHO_ECC_CTRL,
@@ -918,54 +917,45 @@
 	pci_config_write8(addr, 64);
 }
 
-static void pbm_scan_bus(struct pci_controller_info *p,
-			 struct pci_pbm_info *pbm)
+static void psycho_scan_bus(struct pci_pbm_info *pbm)
 {
+	pbm_config_busmastering(pbm);
+	pbm->is_66mhz_capable = 0;
 	pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void psycho_scan_bus(struct pci_controller_info *p)
-{
-	pbm_config_busmastering(&p->pbm_B);
-	p->pbm_B.is_66mhz_capable = 0;
-	pbm_config_busmastering(&p->pbm_A);
-	p->pbm_A.is_66mhz_capable = 1;
-	pbm_scan_bus(p, &p->pbm_B);
-	pbm_scan_bus(p, &p->pbm_A);
 
 	/* After the PCI bus scan is complete, we can register
 	 * the error interrupt handlers.
 	 */
-	psycho_register_error_handlers(p);
+	psycho_register_error_handlers(pbm);
 }
 
-static void psycho_iommu_init(struct pci_controller_info *p)
+static void psycho_iommu_init(struct pci_pbm_info *pbm)
 {
-	struct iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long i;
 	u64 control;
 
 	/* Register addresses. */
-	iommu->iommu_control  = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE;
-	iommu->iommu_flush    = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH;
+	iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+	iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
 	/* PSYCHO's IOMMU lacks ctx flushing. */
 	iommu->iommu_ctxflush = 0;
 
 	/* We use the main control register of PSYCHO as the write
 	 * completion register.
 	 */
-	iommu->write_complete_reg = p->pbm_A.controller_regs + PSYCHO_CONTROL;
+	iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
 
 	/*
 	 * Invalidate TLB Entries.
 	 */
-	control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+	control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
 	control |= PSYCHO_IOMMU_CTRL_DENAB;
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
 	for(i = 0; i < 16; i++) {
-		psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-		psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+		psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
+		psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -973,17 +963,17 @@
 	 */
 	pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
 
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE,
+	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
 		     __pa(iommu->page_table));
 
-	control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+	control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
 	control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
 	control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+	psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
 
 	/* If necessary, hook us up for starfire IRQ translations. */
 	if (this_is_starfire)
-		starfire_hookup(p->pbm_A.portid);
+		starfire_hookup(pbm->portid);
 }
 
 #define PSYCHO_IRQ_RETRY	0x1a00UL
@@ -998,36 +988,35 @@
 #define  PSYCHO_PCIDIAG_IPAPAR	 0x0000000000000002UL /* Invert PIO address parity    */
 #define  PSYCHO_PCIDIAG_LPBACK	 0x0000000000000001UL /* Enable loopback mode         */
 
-static void psycho_controller_hwinit(struct pci_controller_info *p)
+static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
 {
 	u64 tmp;
 
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5);
+	psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
 
 	/* Enable arbiter for all PCI slots. */
-	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
+	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp);
+	psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
 
-	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL);
+	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
 	tmp |= PSYCHO_PCICTRL_AEN;
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp);
+	psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
 
 	/* Disable DMA write / PIO read synchronization on
 	 * both PCI bus segments.
 	 * [ U2P Erratum 1243770, STP2223BGA data sheet ]
 	 */
-	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG);
+	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp);
+	psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
 
-	tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG);
+	tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
 	tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
+	psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
 }
 
-static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
-				   struct pci_pbm_info *pbm,
+static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
 				   int is_pbm_a)
 {
 	unsigned long base = pbm->controller_regs;
@@ -1088,7 +1077,6 @@
 static void psycho_pbm_init(struct pci_controller_info *p,
 			    struct device_node *dp, int is_pbm_a)
 {
-	unsigned int *busrange;
 	struct property *prop;
 	struct pci_pbm_info *pbm;
 
@@ -1097,6 +1085,14 @@
 	else
 		pbm = &p->pbm_B;
 
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	pbm->scan_bus = psycho_scan_bus;
+	pbm->pci_ops = &psycho_ops;
+
+	pbm->index = pci_num_pbms++;
+
 	pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
 	pbm->chip_version = 0;
 	prop = of_find_property(dp, "version#", NULL);
@@ -1117,12 +1113,9 @@
 
 	pci_determine_mem_io_space(pbm);
 
-	prop = of_find_property(dp, "bus-range", NULL);
-	busrange = prop->value;
-	pbm->pci_first_busno = busrange[0];
-	pbm->pci_last_busno = busrange[1];
+	pci_get_pbm_props(pbm);
 
-	psycho_pbm_strbuf_init(p, pbm, is_pbm_a);
+	psycho_pbm_strbuf_init(pbm, is_pbm_a);
 }
 
 #define PSYCHO_CONFIGSPACE	0x001000000UL
@@ -1131,6 +1124,7 @@
 {
 	struct linux_prom64_registers *pr_regs;
 	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
 	struct property *prop;
 	u32 upa_portid;
@@ -1141,7 +1135,9 @@
 	if (prop)
 		upa_portid = *(u32 *) prop->value;
 
-	for(p = pci_controller_root; p; p = p->next) {
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+		struct pci_controller_info *p = pbm->parent;
+
 		if (p->pbm_A.portid == upa_portid) {
 			is_pbm_a = (p->pbm_A.prom_node == NULL);
 			psycho_pbm_init(p, dp, is_pbm_a);
@@ -1161,14 +1157,8 @@
 	}
 	p->pbm_A.iommu = p->pbm_B.iommu = iommu;
 
-	p->next = pci_controller_root;
-	pci_controller_root = p;
-
 	p->pbm_A.portid = upa_portid;
 	p->pbm_B.portid = upa_portid;
-	p->index = pci_num_controllers++;
-	p->scan_bus = psycho_scan_bus;
-	p->pci_ops = &psycho_ops;
 
 	prop = of_find_property(dp, "reg", NULL);
 	pr_regs = prop->value;
@@ -1185,9 +1175,9 @@
 	 */
 	pci_memspace_mask = 0x7fffffffUL;
 
-	psycho_controller_hwinit(p);
+	psycho_controller_hwinit(&p->pbm_A);
 
-	psycho_iommu_init(p);
+	psycho_iommu_init(&p->pbm_A);
 
 	is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
 	psycho_pbm_init(p, dp, is_pbm_a);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 397862f..4cefe6e 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -13,12 +13,12 @@
 #include <linux/interrupt.h>
 
 #include <asm/apb.h>
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/smp.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/of_device.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -494,11 +494,11 @@
 };
 
 /* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_controller_info *p,
+static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
 				    unsigned long afsr,
 				    unsigned long afar)
 {
-	struct iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long iommu_tag[16];
 	unsigned long iommu_data[16];
 	unsigned long flags;
@@ -526,8 +526,8 @@
 			type_string = "Unknown";
 			break;
 		};
-		printk("SABRE%d: IOMMU Error, type[%s]\n",
-		       p->index, type_string);
+		printk("%s: IOMMU Error, type[%s]\n",
+		       pbm->name, type_string);
 
 		/* Enter diagnostic mode and probe for error'd
 		 * entries in the IOTLB.
@@ -536,7 +536,7 @@
 		sabre_write(iommu->iommu_control,
 			    (control | SABRE_IOMMUCTRL_DENAB));
 		for (i = 0; i < 16; i++) {
-			unsigned long base = p->pbm_A.controller_regs;
+			unsigned long base = pbm->controller_regs;
 
 			iommu_tag[i] =
 				sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
@@ -566,13 +566,13 @@
 				type_string = "Unknown";
 				break;
 			};
-			printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
-			       p->index, i, tag, type_string,
+			printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
+			       pbm->name, i, tag, type_string,
 			       ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
 			       ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
 			       ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
-			printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
-			       p->index, i, data,
+			printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
+			       pbm->name, i, data,
 			       ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
 			       ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
 			       ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
@@ -584,9 +584,9 @@
 
 static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
-	unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -604,21 +604,21 @@
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",
-	       p->index,
+	printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
+	       pbm->name,
 	       ((error_bits & SABRE_UEAFSR_PDRD) ?
 		"DMA Read" :
 		((error_bits & SABRE_UEAFSR_PDWR) ?
 		 "DMA Write" : "???")),
 	       ((error_bits & SABRE_UEAFSR_PDTE) ?
 		":Translation Error" : ""));
-	printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
-	       p->index,
+	printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
+	       pbm->name,
 	       (afsr & SABRE_UEAFSR_BMSK) >> 32UL,
 	       (afsr & SABRE_UEAFSR_OFF) >> 29UL,
 	       ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));
-	printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);
-	printk("SABRE%d: UE Secondary errors [", p->index);
+	printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: UE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & SABRE_UEAFSR_SDRD) {
 		reported++;
@@ -637,16 +637,16 @@
 	printk("]\n");
 
 	/* Interrogate IOMMU for error status. */
-	sabre_check_iommu_error(p, afsr, afar);
+	sabre_check_iommu_error(pbm, afsr, afar);
 
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
-	unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
@@ -663,8 +663,8 @@
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("SABRE%d: Correctable Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: Correctable Error, primary error type[%s]\n",
+	       pbm->name,
 	       ((error_bits & SABRE_CEAFSR_PDRD) ?
 		"DMA Read" :
 		((error_bits & SABRE_CEAFSR_PDWR) ?
@@ -673,15 +673,15 @@
 	/* XXX Use syndrome and afar to print out module string just like
 	 * XXX UDB CE trap handler does... -DaveM
 	 */
-	printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+	printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
 	       "was_block(%d)\n",
-	       p->index,
+	       pbm->name,
 	       (afsr & SABRE_CEAFSR_ESYND) >> 48UL,
 	       (afsr & SABRE_CEAFSR_BMSK) >> 32UL,
 	       (afsr & SABRE_CEAFSR_OFF) >> 29UL,
 	       ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));
-	printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);
-	printk("SABRE%d: CE Secondary errors [", p->index);
+	printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: CE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & SABRE_CEAFSR_SDRD) {
 		reported++;
@@ -698,13 +698,13 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
+static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
 {
 	unsigned long csr_reg, csr, csr_error_bits;
 	irqreturn_t ret = IRQ_NONE;
 	u16 stat;
 
-	csr_reg = p->pbm_A.controller_regs + SABRE_PCICTRL;
+	csr_reg = pbm->controller_regs + SABRE_PCICTRL;
 	csr = sabre_read(csr_reg);
 	csr_error_bits =
 		csr & SABRE_PCICTRL_SERR;
@@ -714,8 +714,8 @@
 
 		/* Log 'em.  */
 		if (csr_error_bits & SABRE_PCICTRL_SERR)
-			printk("SABRE%d: PCI SERR signal asserted.\n",
-			       p->index);
+			printk("%s: PCI SERR signal asserted.\n",
+			       pbm->name);
 		ret = IRQ_HANDLED;
 	}
 	pci_bus_read_config_word(sabre_root_bus, 0,
@@ -725,8 +725,8 @@
 		    PCI_STATUS_REC_TARGET_ABORT |
 		    PCI_STATUS_REC_MASTER_ABORT |
 		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
-		printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
-		       p->index, stat);
+		printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
+		       pbm->name, stat);
 		pci_bus_write_config_word(sabre_root_bus, 0,
 					  PCI_STATUS, 0xffff);
 		ret = IRQ_HANDLED;
@@ -736,13 +736,13 @@
 
 static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
+	struct pci_pbm_info *pbm = dev_id;
 	unsigned long afsr_reg, afar_reg;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
-	afsr_reg = p->pbm_A.controller_regs + SABRE_PIOAFSR;
-	afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR;
+	afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
+	afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
 
 	/* Latch error status. */
 	afar = sabre_read(afar_reg);
@@ -755,12 +755,12 @@
 		 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
 		 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
 	if (!error_bits)
-		return sabre_pcierr_intr_other(p);
+		return sabre_pcierr_intr_other(pbm);
 	sabre_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("SABRE%d: PCI Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: PCI Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & SABRE_PIOAFSR_PMA) ?
 		 "Master Abort" :
 		 ((error_bits & SABRE_PIOAFSR_PTA) ?
@@ -769,12 +769,12 @@
 		   "Excessive Retries" :
 		   ((error_bits & SABRE_PIOAFSR_PPERR) ?
 		    "Parity Error" : "???"))))));
-	printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",
-	       p->index,
+	printk("%s: bytemask[%04lx] was_block(%d)\n",
+	       pbm->name,
 	       (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
 	       (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
-	printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);
-	printk("SABRE%d: PCI Secondary errors [", p->index);
+	printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: PCI Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & SABRE_PIOAFSR_SMA) {
 		reported++;
@@ -806,11 +806,11 @@
 	 * a bug in the IOMMU support code or a PCI device driver.
 	 */
 	if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
-		sabre_check_iommu_error(p, afsr, afar);
-		pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+		sabre_check_iommu_error(pbm, afsr, afar);
+		pci_scan_for_target_abort(pbm, pbm->pci_bus);
 	}
 	if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
-		pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+		pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
 	/* For excessive retries, SABRE/PBM will abort the device
 	 * and there is no way to specifically check for excessive
@@ -820,18 +820,18 @@
 	 */
 
 	if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
-		pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
+		pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
 	return IRQ_HANDLED;
 }
 
-static void sabre_register_error_handlers(struct pci_controller_info *p)
+static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
 	struct device_node *dp = pbm->prom_node;
 	struct of_device *op;
 	unsigned long base = pbm->controller_regs;
 	u64 tmp;
+	int err;
 
 	if (pbm->chip_type == PBM_CHIP_TYPE_SABRE)
 		dp = dp->parent;
@@ -858,22 +858,31 @@
 		     SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
 		     SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
 
-	request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p);
+	err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
+	if (err)
+		printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
+		       pbm->name, err);
 
 	sabre_write(base + SABRE_CE_AFSR,
 		    (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
 		     SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
 
-	request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p);
-	request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED,
-		    "SABRE PCIERR", p);
+	err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
+	if (err)
+		printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
+		       pbm->name, err);
+	err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+			  "SABRE_PCIERR", pbm);
+	if (err)
+		printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
+		       pbm->name, err);
 
 	tmp = sabre_read(base + SABRE_PCICTRL);
 	tmp |= SABRE_PCICTRL_ERREN;
 	sabre_write(base + SABRE_PCICTRL, tmp);
 }
 
-static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
+static void apb_init(struct pci_bus *sabre_bus)
 {
 	struct pci_dev *pdev;
 
@@ -909,7 +918,7 @@
 	}
 }
 
-static void sabre_scan_bus(struct pci_controller_info *p)
+static void sabre_scan_bus(struct pci_pbm_info *pbm)
 {
 	static int once;
 	struct pci_bus *pbus;
@@ -918,7 +927,7 @@
 	 * at 66Mhz, but the front side of APB runs at 33Mhz
 	 * for both segments.
 	 */
-	p->pbm_A.is_66mhz_capable = 0;
+	pbm->is_66mhz_capable = 0;
 
 	/* This driver has not been verified to handle
 	 * multiple SABREs yet, so trap this.
@@ -932,41 +941,41 @@
 	}
 	once++;
 
-	pbus = pci_scan_one_pbm(&p->pbm_A);
+	pbus = pci_scan_one_pbm(pbm);
 	if (!pbus)
 		return;
 
 	sabre_root_bus = pbus;
 
-	apb_init(p, pbus);
+	apb_init(pbus);
 
-	sabre_register_error_handlers(p);
+	sabre_register_error_handlers(pbm);
 }
 
-static void sabre_iommu_init(struct pci_controller_info *p,
+static void sabre_iommu_init(struct pci_pbm_info *pbm,
 			     int tsbsize, unsigned long dvma_offset,
 			     u32 dma_mask)
 {
-	struct iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long i;
 	u64 control;
 
 	/* Register addresses. */
-	iommu->iommu_control  = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
-	iommu->iommu_tsbbase  = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE;
-	iommu->iommu_flush    = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH;
-	iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC;
+	iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
+	iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
+	iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
 	/* Sabre's IOMMU lacks ctx flushing. */
 	iommu->iommu_ctxflush = 0;
                                         
 	/* Invalidate TLB Entries. */
-	control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+	control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
 	control |= SABRE_IOMMUCTRL_DENAB;
-	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+	sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
 
 	for(i = 0; i < 16; i++) {
-		sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-		sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+		sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
+		sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
 	}
 
 	/* Leave diag mode enabled for full-flushing done
@@ -974,10 +983,10 @@
 	 */
 	pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
 
-	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE,
+	sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
 		    __pa(iommu->page_table));
 
-	control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+	control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
 	control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
 	control |= SABRE_IOMMUCTRL_ENAB;
 	switch(tsbsize) {
@@ -992,22 +1001,23 @@
 		prom_halt();
 		break;
 	}
-	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+	sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
 }
 
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
+static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
 {
-	struct pci_pbm_info *pbm;
-
-	pbm = &p->pbm_A;
 	pbm->name = dp->full_name;
 	printk("%s: SABRE PCI Bus Module\n", pbm->name);
 
+	pbm->scan_bus = sabre_scan_bus;
+	pbm->pci_ops = &sabre_ops;
+
+	pbm->index = pci_num_pbms++;
+
 	pbm->chip_type = PBM_CHIP_TYPE_SABRE;
 	pbm->parent = p;
 	pbm->prom_node = dp;
-	pbm->pci_first_busno = p->pci_first_busno;
-	pbm->pci_last_busno = p->pci_last_busno;
+	pci_get_pbm_props(pbm);
 
 	pci_determine_mem_io_space(pbm);
 }
@@ -1016,9 +1026,9 @@
 {
 	const struct linux_prom64_registers *pr_regs;
 	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
 	int tsbsize;
-	const u32 *busrange;
 	const u32 *vdma;
 	u32 upa_portid, dma_mask;
 	u64 clear_irq;
@@ -1053,17 +1063,15 @@
 		prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
 		prom_halt();
 	}
-	p->pbm_A.iommu = iommu;
+	pbm = &p->pbm_A;
+	pbm->iommu = iommu;
 
 	upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-	p->next = pci_controller_root;
-	pci_controller_root = p;
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
 
-	p->pbm_A.portid = upa_portid;
-	p->index = pci_num_controllers++;
-	p->scan_bus = sabre_scan_bus;
-	p->pci_ops = &sabre_ops;
+	pbm->portid = upa_portid;
 
 	/*
 	 * Map in SABRE register set and report the presence of this SABRE.
@@ -1074,26 +1082,26 @@
 	/*
 	 * First REG in property is base of entire SABRE register space.
 	 */
-	p->pbm_A.controller_regs = pr_regs[0].phys_addr;
+	pbm->controller_regs = pr_regs[0].phys_addr;
 
 	/* Clear interrupts */
 
 	/* PCI first */
 	for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-		sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+		sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
 
 	/* Then OBIO */
 	for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-		sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+		sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
 
 	/* Error interrupts are enabled later after the bus scan. */
-	sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL,
+	sabre_write(pbm->controller_regs + SABRE_PCICTRL,
 		    (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
 		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
 
 	/* Now map in PCI config space for entire SABRE. */
-	p->pbm_A.config_space =
-		(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
+	pbm->config_space =
+		(pbm->controller_regs + SABRE_CONFIGSPACE);
 
 	vdma = of_get_property(dp, "virtual-dma", NULL);
 
@@ -1117,14 +1125,10 @@
 			prom_halt();
 	}
 
-	sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
-
-	busrange = of_get_property(dp, "bus-range", NULL);
-	p->pci_first_busno = busrange[0];
-	p->pci_last_busno = busrange[1];
+	sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
 
 	/*
 	 * Look for APB underneath.
 	 */
-	sabre_pbm_init(p, dp);
+	sabre_pbm_init(p, pbm, dp);
 }
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 91a7385..e375d72 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -10,12 +10,13 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -238,25 +239,6 @@
 #define SCHIZO_PCIERR_B_INO	0x33 /* PBM B PCI bus error */
 #define SCHIZO_SERR_INO		0x34 /* Safari interface error */
 
-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
-{
-	ino &= IMAP_INO;
-	if (p->pbm_A.ino_bitmap & (1UL << ino))
-		return &p->pbm_A;
-	if (p->pbm_B.ino_bitmap & (1UL << ino))
-		return &p->pbm_B;
-
-	printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
-	       "PBM_A[%016lx] PBM_B[%016lx]",
-	       p->index, ino,
-	       p->pbm_A.ino_bitmap,
-	       p->pbm_B.ino_bitmap);
-	printk("PCI%d: Using PBM_A, report this problem immediately.\n",
-	       p->index);
-
-	return &p->pbm_A;
-}
-
 #define SCHIZO_STC_ERR	0xb800UL /* --> 0xba00 */
 #define SCHIZO_STC_TAG	0xba00UL /* --> 0xba80 */
 #define SCHIZO_STC_LINE	0xbb00UL /* --> 0xbb80 */
@@ -522,9 +504,10 @@
 
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
-	unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	struct pci_controller_info *p = pbm->parent;
+	unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported, limit;
 
@@ -549,28 +532,28 @@
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: Uncorrectable Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & SCHIZO_UEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & SCHIZO_UEAFSR_PDRD) ?
 		  "DMA Read" :
 		  ((error_bits & SCHIZO_UEAFSR_PDWR) ?
 		   "DMA Write" : "???")))));
-	printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
-	       p->index,
+	printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+	       pbm->name,
 	       (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
 	       (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
 	       (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
-	printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
-	       p->index,
+	printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+	       pbm->name,
 	       (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
 	       (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
 	       (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
 	       (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
 	       (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
-	printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
-	printk("PCI%d: UE Secondary errors [", p->index);
+	printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: UE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & SCHIZO_UEAFSR_SPIO) {
 		reported++;
@@ -610,9 +593,9 @@
 
 static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
-	unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
-	unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
+	struct pci_pbm_info *pbm = dev_id;
+	unsigned long afsr_reg = pbm->controller_regs + SCHIZO_CE_AFSR;
+	unsigned long afar_reg = pbm->controller_regs + SCHIZO_CE_AFAR;
 	unsigned long afsr, afar, error_bits;
 	int reported, limit;
 
@@ -637,8 +620,8 @@
 	schizo_write(afsr_reg, error_bits);
 
 	/* Log the error. */
-	printk("PCI%d: Correctable Error, primary error type[%s]\n",
-	       p->index,
+	printk("%s: Correctable Error, primary error type[%s]\n",
+	       pbm->name,
 	       (((error_bits & SCHIZO_CEAFSR_PPIO) ?
 		 "PIO" :
 		 ((error_bits & SCHIZO_CEAFSR_PDRD) ?
@@ -649,20 +632,20 @@
 	/* XXX Use syndrome and afar to print out module string just like
 	 * XXX UDB CE trap handler does... -DaveM
 	 */
-	printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
-	       p->index,
+	printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+	       pbm->name,
 	       (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
 	       (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
 	       (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
-	printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
-	       p->index,
+	printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+	       pbm->name,
 	       (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
 	       (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
 	       (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
 	       (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
 	       (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
-	printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
-	printk("PCI%d: CE Secondary errors [", p->index);
+	printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+	printk("%s: CE Secondary errors [", pbm->name);
 	reported = 0;
 	if (afsr & SCHIZO_CEAFSR_SPIO) {
 		reported++;
@@ -881,10 +864,10 @@
 	 */
 	if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
 		schizo_check_iommu_error(p, PCI_ERR);
-		pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+		pci_scan_for_target_abort(pbm, pbm->pci_bus);
 	}
 	if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
-		pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+		pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
 	/* For excessive retries, PSYCHO/PBM will abort the device
 	 * and there is no way to specifically check for excessive
@@ -894,7 +877,7 @@
 	 */
 
 	if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
-		pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+		pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
 	return IRQ_HANDLED;
 }
@@ -940,22 +923,23 @@
  */
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
-	struct pci_controller_info *p = dev_id;
+	struct pci_pbm_info *pbm = dev_id;
+	struct pci_controller_info *p = pbm->parent;
 	u64 errlog;
 
-	errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
-	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
+	errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
 		     errlog & ~(SAFARI_ERRLOG_ERROUT));
 
 	if (!(errlog & BUS_ERROR_UNMAP)) {
-		printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
-		       p->index, errlog);
+		printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
+		       pbm->name, errlog);
 
 		return IRQ_HANDLED;
 	}
 
-	printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
-	       p->index);
+	printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+	       pbm->name);
 	schizo_check_iommu_error(p, SAFARI_ERR);
 
 	return IRQ_HANDLED;
@@ -972,6 +956,16 @@
 #define SCHIZO_SAFARI_IRQCTRL	0x10010UL
 #define  SCHIZO_SAFIRQCTRL_EN	 0x8000000000000000UL
 
+static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
+{
+	ino &= IMAP_INO;
+
+	if (pbm->ino_bitmap & (1UL << ino))
+		return 1;
+
+	return 0;
+}
+
 /* How the Tomatillo IRQs are routed around is pure guesswork here.
  *
  * All the Tomatillo devices I see in prtconf dumps seem to have only
@@ -986,11 +980,11 @@
  * PCI bus units of the same Tomatillo.  I still have not really
  * figured this out...
  */
-static void tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct pci_pbm_info *pbm;
-	struct of_device *op;
+	struct of_device *op = of_find_device_by_node(pbm->prom_node);
 	u64 tmp, err_mask, err_no_mask;
+	int err;
 
 	/* Tomatillo IRQ property layout is:
 	 * 0: PCIERR
@@ -1000,44 +994,42 @@
 	 * 4: POWER FAIL?
 	 */
 
-	pbm = pbm_for_ino(p, SCHIZO_UE_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
-			    "TOMATILLO_UE", p);
+	if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+		err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+				  "TOMATILLO_UE", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register UE, "
+			       "err=%d\n", pbm->name, err);
+	}
+	if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+		err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+				  "TOMATILLO_CE", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register CE, "
+			       "err=%d\n", pbm->name, err);
+	}
+	err = 0;
+	if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+		err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+				  "TOMATILLO_PCIERR", pbm);
+	} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+		err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+				  "TOMATILLO_PCIERR", pbm);
+	}
+	if (err)
+		printk(KERN_WARNING "%s: Could not register PCIERR, "
+		       "err=%d\n", pbm->name, err);
 
-	pbm = pbm_for_ino(p, SCHIZO_CE_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
-			    "TOMATILLO CE", p);
-
-	pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-			    "TOMATILLO PCIERR-A", pbm);
-
-
-	pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-			    "TOMATILLO PCIERR-B", pbm);
-
-	pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
-			    "TOMATILLO SERR", p);
+	if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+		err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+				  "TOMATILLO_SERR", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register SERR, "
+			       "err=%d\n", pbm->name, err);
+	}
 
 	/* Enable UE and CE interrupts for controller. */
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
-		     (SCHIZO_ECCCTRL_EE |
-		      SCHIZO_ECCCTRL_UE |
-		      SCHIZO_ECCCTRL_CE));
-
-	schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
+	schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
 		     (SCHIZO_ECCCTRL_EE |
 		      SCHIZO_ECCCTRL_UE |
 		      SCHIZO_ECCCTRL_CE));
@@ -1053,15 +1045,10 @@
 
 	err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-	tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 	tmp |= err_mask;
 	tmp &= ~err_no_mask;
-	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
-	tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
-	tmp |= err_mask;
-	tmp &= ~err_no_mask;
-	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
 	err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
 		    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -1070,8 +1057,7 @@
 		    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
 		    SCHIZO_PCIAFSR_STTO);
 
-	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
-	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
 
 	err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
 		    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -1083,22 +1069,18 @@
 		    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
 		    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
-		     (SCHIZO_SAFERRCTRL_EN | err_mask));
-	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
 		     (SCHIZO_SAFERRCTRL_EN | err_mask));
 
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
-		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
-	schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
 		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
-static void schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-	struct pci_pbm_info *pbm;
-	struct of_device *op;
+	struct of_device *op = of_find_device_by_node(pbm->prom_node);
 	u64 tmp, err_mask, err_no_mask;
+	int err;
 
 	/* Schizo IRQ property layout is:
 	 * 0: PCIERR
@@ -1108,39 +1090,42 @@
 	 * 4: POWER FAIL?
 	 */
 
-	pbm = pbm_for_ino(p, SCHIZO_UE_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
-			    "SCHIZO_UE", p);
+	if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+		err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+				  "SCHIZO_UE", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register UE, "
+			       "err=%d\n", pbm->name, err);
+	}
+	if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+		err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+				  "SCHIZO_CE", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register CE, "
+			       "err=%d\n", pbm->name, err);
+	}
+	err = 0;
+	if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+		err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+				  "SCHIZO_PCIERR", pbm);
+	} else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+		err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+				  "SCHIZO_PCIERR", pbm);
+	}
+	if (err)
+		printk(KERN_WARNING "%s: Could not register PCIERR, "
+		       "err=%d\n", pbm->name, err);
 
-	pbm = pbm_for_ino(p, SCHIZO_CE_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
-			    "SCHIZO CE", p);
-
-	pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-			    "SCHIZO PCIERR-A", pbm);
-
-
-	pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-			    "SCHIZO PCIERR-B", pbm);
-
-	pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
-	op = of_find_device_by_node(pbm->prom_node);
-	if (op)
-		request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
-			    "SCHIZO SERR", p);
+	if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+		err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+				  "SCHIZO_SERR", pbm);
+		if (err)
+			printk(KERN_WARNING "%s: Could not register SERR, "
+			       "err=%d\n", pbm->name, err);
+	}
 
 	/* Enable UE and CE interrupts for controller. */
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
+	schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
 		     (SCHIZO_ECCCTRL_EE |
 		      SCHIZO_ECCCTRL_UE |
 		      SCHIZO_ECCCTRL_CE));
@@ -1159,25 +1144,12 @@
 	/* Enable PCI Error interrupts and clear error
 	 * bits for each PBM.
 	 */
-	tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
+	tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 	tmp |= err_mask;
 	tmp &= ~err_no_mask;
-	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
-	schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR,
-		     (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-		      SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-		      SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-		      SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-		      SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-		      SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
-
-	tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
-	tmp |= err_mask;
-	tmp &= ~err_no_mask;
-	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
-	schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
+	schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
 		     (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
 		      SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
 		      SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
@@ -1210,11 +1182,8 @@
 		      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+	schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
 		     (SCHIZO_SAFERRCTRL_EN | err_mask));
-
-	schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
-		     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1234,27 +1203,19 @@
 	pci_config_write8(addr, 64);
 }
 
-static void schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_pbm_info *pbm)
 {
-	pbm_config_busmastering(&p->pbm_B);
-	p->pbm_B.is_66mhz_capable =
-		(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
-		 != NULL);
-	pbm_config_busmastering(&p->pbm_A);
-	p->pbm_A.is_66mhz_capable =
-		(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
+	pbm_config_busmastering(pbm);
+	pbm->is_66mhz_capable =
+		(of_find_property(pbm->prom_node, "66mhz-capable", NULL)
 		 != NULL);
 
-	p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
-	p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
+	pbm->pci_bus = pci_scan_one_pbm(pbm);
 
-	/* After the PCI bus scan is complete, we can register
-	 * the error interrupt handlers.
-	 */
-	if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
-		tomatillo_register_error_handlers(p);
+	if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+		tomatillo_register_error_handlers(pbm);
 	else
-		schizo_register_error_handlers(p);
+		schizo_register_error_handlers(pbm);
 }
 
 #define SCHIZO_STRBUF_CONTROL		(0x02800UL)
@@ -1491,10 +1452,8 @@
 			    int chip_type)
 {
 	const struct linux_prom64_registers *regs;
-	const unsigned int *busrange;
 	struct pci_pbm_info *pbm;
 	const char *chipset_name;
-	const u32 *ino_bitmap;
 	int is_pbm_a;
 
 	switch (chip_type) {
@@ -1531,6 +1490,14 @@
 	else
 		pbm = &p->pbm_B;
 
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	pbm->scan_bus = schizo_scan_bus;
+	pbm->pci_ops = &schizo_ops;
+
+	pbm->index = pci_num_pbms++;
+
 	pbm->portid = portid;
 	pbm->parent = p;
 	pbm->prom_node = dp;
@@ -1555,13 +1522,7 @@
 
 	pci_determine_mem_io_space(pbm);
 
-	ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
-	pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
-			   ((u64)ino_bitmap[0] <<  0UL));
-
-	busrange = of_get_property(dp, "bus-range", NULL);
-	pbm->pci_first_busno = busrange[0];
-	pbm->pci_last_busno = busrange[1];
+	pci_get_pbm_props(pbm);
 
 	schizo_pbm_iommu_init(pbm);
 	schizo_pbm_strbuf_init(pbm);
@@ -1580,23 +1541,15 @@
 static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
 {
 	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
 	u32 portid;
 
 	portid = of_getintprop_default(dp, "portid", 0xff);
 
-	for (p = pci_controller_root; p; p = p->next) {
-		struct pci_pbm_info *pbm;
-
-		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-			continue;
-
-		pbm = (p->pbm_A.prom_node ?
-		       &p->pbm_A :
-		       &p->pbm_B);
-
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
 		if (portid_compare(pbm->portid, portid, chip_type)) {
-			schizo_pbm_init(p, dp, portid, chip_type);
+			schizo_pbm_init(pbm->parent, dp, portid, chip_type);
 			return;
 		}
 	}
@@ -1617,13 +1570,6 @@
 
 	p->pbm_B.iommu = iommu;
 
-	p->next = pci_controller_root;
-	pci_controller_root = p;
-
-	p->index = pci_num_controllers++;
-	p->scan_bus = schizo_scan_bus;
-	p->pci_ops = &schizo_ops;
-
 	/* Like PSYCHO we have a 2GB aligned area for memory space. */
 	pci_memspace_mask = 0x7fffffffUL;
 
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 1ccf4c9..0c76a88 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -13,7 +13,6 @@
 #include <linux/irq.h>
 #include <linux/msi.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/upa.h>
@@ -677,29 +676,15 @@
 };
 
 
-static void pbm_scan_bus(struct pci_controller_info *p,
-			 struct pci_pbm_info *pbm)
-{
-	pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void pci_sun4v_scan_bus(struct pci_controller_info *p)
+static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
 {
 	struct property *prop;
 	struct device_node *dp;
 
-	if ((dp = p->pbm_A.prom_node) != NULL) {
-		prop = of_find_property(dp, "66mhz-capable", NULL);
-		p->pbm_A.is_66mhz_capable = (prop != NULL);
-
-		pbm_scan_bus(p, &p->pbm_A);
-	}
-	if ((dp = p->pbm_B.prom_node) != NULL) {
-		prop = of_find_property(dp, "66mhz-capable", NULL);
-		p->pbm_B.is_66mhz_capable = (prop != NULL);
-
-		pbm_scan_bus(p, &p->pbm_B);
-	}
+	dp = pbm->prom_node;
+	prop = of_find_property(dp, "66mhz-capable", NULL);
+	pbm->is_66mhz_capable = (prop != NULL);
+	pbm->pci_bus = pci_scan_one_pbm(pbm);
 
 	/* XXX register error interrupt handlers XXX */
 }
@@ -802,20 +787,6 @@
 		       pbm->name, sz);
 }
 
-static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
-{
-	struct property *prop;
-	unsigned int *busrange;
-
-	prop = of_find_property(pbm->prom_node, "bus-range", NULL);
-
-	busrange = prop->value;
-
-	pbm->pci_first_busno = busrange[0];
-	pbm->pci_last_busno = busrange[1];
-
-}
-
 #ifdef CONFIG_PCI_MSI
 struct pci_sun4v_msiq_entry {
 	u64		version_type;
@@ -1019,114 +990,6 @@
 	return -EINVAL;
 }
 
-static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
-{
-	const u32 *val;
-	int len;
-
-	val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
-	if (!val || len != 4)
-		goto no_msi;
-	pbm->msiq_num = *val;
-	if (pbm->msiq_num) {
-		const struct msiq_prop {
-			u32 first_msiq;
-			u32 num_msiq;
-			u32 first_devino;
-		} *mqp;
-		const struct msi_range_prop {
-			u32 first_msi;
-			u32 num_msi;
-		} *mrng;
-		const struct addr_range_prop {
-			u32 msi32_high;
-			u32 msi32_low;
-			u32 msi32_len;
-			u32 msi64_high;
-			u32 msi64_low;
-			u32 msi64_len;
-		} *arng;
-
-		val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
-		if (!val || len != 4)
-			goto no_msi;
-
-		pbm->msiq_ent_count = *val;
-
-		mqp = of_get_property(pbm->prom_node,
-				      "msi-eq-to-devino", &len);
-		if (!mqp || len != sizeof(struct msiq_prop))
-			goto no_msi;
-
-		pbm->msiq_first = mqp->first_msiq;
-		pbm->msiq_first_devino = mqp->first_devino;
-
-		val = of_get_property(pbm->prom_node, "#msi", &len);
-		if (!val || len != 4)
-			goto no_msi;
-		pbm->msi_num = *val;
-
-		mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
-		if (!mrng || len != sizeof(struct msi_range_prop))
-			goto no_msi;
-		pbm->msi_first = mrng->first_msi;
-
-		val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
-		if (!val || len != 4)
-			goto no_msi;
-		pbm->msi_data_mask = *val;
-
-		val = of_get_property(pbm->prom_node, "msix-data-width", &len);
-		if (!val || len != 4)
-			goto no_msi;
-		pbm->msix_data_width = *val;
-
-		arng = of_get_property(pbm->prom_node, "msi-address-ranges",
-				       &len);
-		if (!arng || len != sizeof(struct addr_range_prop))
-			goto no_msi;
-		pbm->msi32_start = ((u64)arng->msi32_high << 32) |
-			(u64) arng->msi32_low;
-		pbm->msi64_start = ((u64)arng->msi64_high << 32) |
-			(u64) arng->msi64_low;
-		pbm->msi32_len = arng->msi32_len;
-		pbm->msi64_len = arng->msi64_len;
-
-		if (msi_bitmap_alloc(pbm))
-			goto no_msi;
-
-		if (msi_queue_alloc(pbm)) {
-			msi_bitmap_free(pbm);
-			goto no_msi;
-		}
-
-		printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
-		       "devino[0x%x]\n",
-		       pbm->name,
-		       pbm->msiq_first, pbm->msiq_num,
-		       pbm->msiq_ent_count,
-		       pbm->msiq_first_devino);
-		printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
-		       "width[%u]\n",
-		       pbm->name,
-		       pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
-		       pbm->msix_data_width);
-		printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
-		       "addr64[0x%lx:0x%x]\n",
-		       pbm->name,
-		       pbm->msi32_start, pbm->msi32_len,
-		       pbm->msi64_start, pbm->msi64_len);
-		printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
-		       pbm->name,
-		       pbm->msi_queues);
-	}
-
-	return;
-
-no_msi:
-	pbm->msiq_num = 0;
-	printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
-}
 
 static int alloc_msi(struct pci_pbm_info *pbm)
 {
@@ -1245,6 +1108,117 @@
 	 */
 	sun4v_destroy_msi(virt_irq);
 }
+
+static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
+{
+	const u32 *val;
+	int len;
+
+	val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+	if (!val || len != 4)
+		goto no_msi;
+	pbm->msiq_num = *val;
+	if (pbm->msiq_num) {
+		const struct msiq_prop {
+			u32 first_msiq;
+			u32 num_msiq;
+			u32 first_devino;
+		} *mqp;
+		const struct msi_range_prop {
+			u32 first_msi;
+			u32 num_msi;
+		} *mrng;
+		const struct addr_range_prop {
+			u32 msi32_high;
+			u32 msi32_low;
+			u32 msi32_len;
+			u32 msi64_high;
+			u32 msi64_low;
+			u32 msi64_len;
+		} *arng;
+
+		val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+		if (!val || len != 4)
+			goto no_msi;
+
+		pbm->msiq_ent_count = *val;
+
+		mqp = of_get_property(pbm->prom_node,
+				      "msi-eq-to-devino", &len);
+		if (!mqp || len != sizeof(struct msiq_prop))
+			goto no_msi;
+
+		pbm->msiq_first = mqp->first_msiq;
+		pbm->msiq_first_devino = mqp->first_devino;
+
+		val = of_get_property(pbm->prom_node, "#msi", &len);
+		if (!val || len != 4)
+			goto no_msi;
+		pbm->msi_num = *val;
+
+		mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+		if (!mrng || len != sizeof(struct msi_range_prop))
+			goto no_msi;
+		pbm->msi_first = mrng->first_msi;
+
+		val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+		if (!val || len != 4)
+			goto no_msi;
+		pbm->msi_data_mask = *val;
+
+		val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+		if (!val || len != 4)
+			goto no_msi;
+		pbm->msix_data_width = *val;
+
+		arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+				       &len);
+		if (!arng || len != sizeof(struct addr_range_prop))
+			goto no_msi;
+		pbm->msi32_start = ((u64)arng->msi32_high << 32) |
+			(u64) arng->msi32_low;
+		pbm->msi64_start = ((u64)arng->msi64_high << 32) |
+			(u64) arng->msi64_low;
+		pbm->msi32_len = arng->msi32_len;
+		pbm->msi64_len = arng->msi64_len;
+
+		if (msi_bitmap_alloc(pbm))
+			goto no_msi;
+
+		if (msi_queue_alloc(pbm)) {
+			msi_bitmap_free(pbm);
+			goto no_msi;
+		}
+
+		printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
+		       "devino[0x%x]\n",
+		       pbm->name,
+		       pbm->msiq_first, pbm->msiq_num,
+		       pbm->msiq_ent_count,
+		       pbm->msiq_first_devino);
+		printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
+		       "width[%u]\n",
+		       pbm->name,
+		       pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
+		       pbm->msix_data_width);
+		printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
+		       "addr64[0x%lx:0x%x]\n",
+		       pbm->name,
+		       pbm->msi32_start, pbm->msi32_len,
+		       pbm->msi64_start, pbm->msi64_len);
+		printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
+		       pbm->name,
+		       pbm->msi_queues);
+	}
+	pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
+	pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
+
+	return;
+
+no_msi:
+	pbm->msiq_num = 0;
+	printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+}
 #else /* CONFIG_PCI_MSI */
 static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 {
@@ -1260,6 +1234,14 @@
 	else
 		pbm = &p->pbm_A;
 
+	pbm->next = pci_pbm_root;
+	pci_pbm_root = pbm;
+
+	pbm->scan_bus = pci_sun4v_scan_bus;
+	pbm->pci_ops = &pci_sun4v_ops;
+
+	pbm->index = pci_num_pbms++;
+
 	pbm->parent = p;
 	pbm->prom_node = dp;
 
@@ -1271,7 +1253,7 @@
 
 	pci_determine_mem_io_space(pbm);
 
-	pci_sun4v_get_bus_range(pbm);
+	pci_get_pbm_props(pbm);
 	pci_sun4v_iommu_init(pbm);
 	pci_sun4v_msi_init(pbm);
 }
@@ -1279,6 +1261,7 @@
 void sun4v_pci_init(struct device_node *dp, char *model_name)
 {
 	struct pci_controller_info *p;
+	struct pci_pbm_info *pbm;
 	struct iommu *iommu;
 	struct property *prop;
 	struct linux_prom64_registers *regs;
@@ -1290,18 +1273,9 @@
 
 	devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
 
-	for (p = pci_controller_root; p; p = p->next) {
-		struct pci_pbm_info *pbm;
-
-		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-			continue;
-
-		pbm = (p->pbm_A.prom_node ?
-		       &p->pbm_A :
-		       &p->pbm_B);
-
+	for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
 		if (pbm->devhandle == (devhandle ^ 0x40)) {
-			pci_sun4v_pbm_init(p, dp, devhandle);
+			pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
 			return;
 		}
 	}
@@ -1331,18 +1305,6 @@
 
 	p->pbm_B.iommu = iommu;
 
-	p->next = pci_controller_root;
-	pci_controller_root = p;
-
-	p->index = pci_num_controllers++;
-
-	p->scan_bus = pci_sun4v_scan_bus;
-#ifdef CONFIG_PCI_MSI
-	p->setup_msi_irq = pci_sun4v_setup_msi_irq;
-	p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
-#endif
-	p->pci_ops = &pci_sun4v_ops;
-
 	/* Like PSYCHO and SCHIZO we have a 2GB aligned area
 	 * for memory space.
 	 */
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 3b05428..91f6e2a 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -1002,24 +1002,24 @@
 	u64 control;
 
 	irq = sbus_build_irq(sbus, SYSIO_UE_INO);
-	if (request_irq(irq, sysio_ue_handler,
-			IRQF_SHARED, "SYSIO UE", sbus) < 0) {
+	if (request_irq(irq, sysio_ue_handler, 0,
+			"SYSIO_UE", sbus) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
 			    sbus->portid);
 		prom_halt();
 	}
 
 	irq = sbus_build_irq(sbus, SYSIO_CE_INO);
-	if (request_irq(irq, sysio_ce_handler,
-			IRQF_SHARED, "SYSIO CE", sbus) < 0) {
+	if (request_irq(irq, sysio_ce_handler, 0,
+			"SYSIO_CE", sbus) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
 			    sbus->portid);
 		prom_halt();
 	}
 
 	irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
-	if (request_irq(irq, sysio_sbus_error_handler,
-			IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) {
+	if (request_irq(irq, sysio_sbus_error_handler, 0,
+			"SYSIO_SBERR", sbus) < 0) {
 		prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
 			    sbus->portid);
 		prom_halt();
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 692e46a..abd8312 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -793,7 +793,7 @@
 		tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
 	}
 
-	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL);
+	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
 }
 
 /* These are here just in case some old sparc32 binary calls it. */
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 48c36fe..5fe7f9a 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -81,6 +81,7 @@
 	.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/	.word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
 	.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
+/*310*/	.word compat_sys_utimensat
 
 #endif /* CONFIG_COMPAT */
 
@@ -152,6 +153,7 @@
 	.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/	.word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 	.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/	.word sys_utimensat
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -269,5 +271,6 @@
 	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_nosys
+/*310*/	.long sunos_nosys
 
 #endif
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index dc652f2..d0fde36 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/kdebug.h>
 
+#include <asm/smp.h>
 #include <asm/delay.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index c32e309..b582024 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -32,36 +32,23 @@
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
+	int ret = 0;
 
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
-
-static inline int notify_page_fault(enum die_val val, const char *str,
-			struct pt_regs *regs, long err, int trap, int sig)
-{
-	struct die_args args = {
-		.regs = regs,
-		.str = str,
-		.err = err,
-		.trapnr = trap,
-		.signr = sig
-	};
-	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+	/* kprobe_running() needs smp_processor_id() */
+	if (!user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, 0))
+			ret = 1;
+		preempt_enable();
+	}
+	return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, const char *str,
-			struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-	return NOTIFY_DONE;
+	return 0;
 }
 #endif
 
@@ -120,9 +107,6 @@
 	printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
 	       (tsk->mm ? (unsigned long) tsk->mm->pgd :
 		          (unsigned long) tsk->active_mm->pgd));
-	if (notify_die(DIE_GPF, "general protection fault", regs,
-		       0, 0, SIGSEGV) == NOTIFY_STOP)
-		return;
 	die_if_kernel("Oops", regs);
 }
 
@@ -299,8 +283,7 @@
 
 	fault_code = get_thread_fault_code();
 
-	if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
-		       fault_code, 0, SIGSEGV) == NOTIFY_STOP)
+	if (notify_page_fault(regs))
 		return;
 
 	si_code = SEGV_MAPERR;
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 354cc6b..b9c0f30 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -320,21 +320,7 @@
 
 source "lib/Kconfig"
 
-menu "SCSI support"
-depends on BROKEN
-
-config SCSI
-	tristate "SCSI support"
-
-# This gives us free_dma, which scsi.c wants.
-config GENERIC_ISA_DMA
-	bool
-	depends on SCSI
-	default y
-
-source "arch/um/Kconfig.scsi"
-
-endmenu
+source "drivers/scsi/Kconfig"
 
 source "drivers/md/Kconfig"
 
diff --git a/arch/um/Kconfig.scsi b/arch/um/Kconfig.scsi
deleted file mode 100644
index c291c94..0000000
--- a/arch/um/Kconfig.scsi
+++ /dev/null
@@ -1,58 +0,0 @@
-comment "SCSI support type (disk, tape, CD-ROM)"
-	depends on SCSI
-
-config BLK_DEV_SD
-	tristate "SCSI disk support"
-	depends on SCSI
-
-config SD_EXTRA_DEVS
-	int "Maximum number of SCSI disks that can be loaded as modules"
-	depends on BLK_DEV_SD
-	default "40"
-
-config CHR_DEV_ST
-	tristate "SCSI tape support"
-	depends on SCSI
-
-config BLK_DEV_SR
-	tristate "SCSI CD-ROM support"
-	depends on SCSI
-
-config BLK_DEV_SR_VENDOR
-	bool "Enable vendor-specific extensions (for SCSI CDROM)"
-	depends on BLK_DEV_SR
-
-config SR_EXTRA_DEVS
-	int "Maximum number of CDROM devices that can be loaded as modules"
-	depends on BLK_DEV_SR
-	default "2"
-
-config CHR_DEV_SG
-	tristate "SCSI generic support"
-	depends on SCSI
-
-comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
-	depends on SCSI
-
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-config SCSI_DEBUG_QUEUES
-	bool "Enable extra checks in new queueing code"
-	depends on SCSI
-
-#fi
-config SCSI_MULTI_LUN
-	bool "Probe all LUNs on each SCSI device"
-	depends on SCSI
-
-config SCSI_CONSTANTS
-	bool "Verbose SCSI error reporting (kernel size +=12K)"
-	depends on SCSI
-
-config SCSI_LOGGING
-	bool "SCSI logging facility"
-	depends on SCSI
-
-config SCSI_DEBUG
-	tristate "SCSI debugging host simulator (EXPERIMENTAL)"
-	depends on SCSI
-
diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h
index 11bafab..0f31208 100644
--- a/arch/um/include/sysdep-i386/archsetjmp.h
+++ b/arch/um/include/sysdep-i386/archsetjmp.h
@@ -1,5 +1,5 @@
 /*
- * arch/i386/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-i386/archsetjmp.h
  */
 
 #ifndef _KLIBC_ARCHSETJMP_H
diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h
index 9a5e1a6..2af8f12 100644
--- a/arch/um/include/sysdep-x86_64/archsetjmp.h
+++ b/arch/um/include/sysdep-x86_64/archsetjmp.h
@@ -1,5 +1,5 @@
 /*
- * arch/x86_64/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-x86_64/archsetjmp.h
  */
 
 #ifndef _KLIBC_ARCHSETJMP_H
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index ef36fac..a96ae1a 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -178,20 +178,23 @@
 
 int external_pid_skas(struct task_struct *task)
 {
-#warning Need to look up userspace_pid by cpu
+	/* FIXME: Need to look up userspace_pid by cpu */
 	return(userspace_pid[0]);
 }
 
 int thread_pid_skas(struct task_struct *task)
 {
-#warning Need to look up userspace_pid by cpu
+	/* FIXME: Need to look up userspace_pid by cpu */
 	return(userspace_pid[0]);
 }
 
 void kill_off_processes_skas(void)
 {
 	if(proc_mm)
-#warning need to loop over userspace_pids in kill_off_processes_skas
+		/*
+		 * FIXME: need to loop over userspace_pids in
+		 * kill_off_processes_skas
+		 */
 		os_kill_ptraced_process(userspace_pid[0], 1);
 	else {
 		struct task_struct *p;
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 92a7b591..2d9d2ca 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -239,6 +239,7 @@
 	return ok;
 }
 
+#ifdef UML_CONFIG_MODE_TT
 void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
 {
 	int flags = 0, pages;
@@ -260,6 +261,7 @@
 			      "errno = %d\n", errno);
 	}
 }
+#endif
 
 void init_new_thread_signals(void)
 {
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 8e490ff..5c894632 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -68,7 +68,7 @@
 	int err, pid = mm_idp->u.pid;
 
 	if(proc_mm)
-#warning Need to look up userspace_pid by cpu
+		/* FIXME: Need to look up userspace_pid by cpu */
 		pid = userspace_pid[0];
 
 	multi_count++;
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 5c088a5..6a0e466 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -586,7 +586,7 @@
 {
 	int err;
 
-#warning need cpu pid in switch_mm_skas
+	/* FIXME: need cpu pid in switch_mm_skas */
 	if(proc_mm){
 		err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
 			     mm_idp->u.mm_fd);
diff --git a/arch/v850/kernel/asm-offsets.c b/arch/v850/kernel/asm-offsets.c
index 24f2913..cee5c31 100644
--- a/arch/v850/kernel/asm-offsets.c
+++ b/arch/v850/kernel/asm-offsets.c
@@ -29,7 +29,7 @@
 	DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace));
 	DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked));
 	DEFINE (TASK_THREAD, offsetof (struct task_struct, thread));
-	DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+	DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, stack));
 	DEFINE (TASK_MM, offsetof (struct task_struct, mm));
 	DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
 	DEFINE (TASK_PID, offsetof (struct task_struct, pid));
diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
index 8bc521c..e4327a8 100644
--- a/arch/v850/kernel/entry.S
+++ b/arch/v850/kernel/entry.S
@@ -523,7 +523,7 @@
 
 
 /* This the initial entry point for a new child thread, with an appropriate
-   stack in place that makes it look the the child is in the middle of an
+   stack in place that makes it look that the child is in the middle of an
    syscall.  This function is actually `returned to' from switch_thread
    (copy_thread makes ret_from_fork the return address in each new thread's
    saved context).  */
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 4d58258..d8bfe31 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -1413,7 +1413,7 @@
 
 	/*
 	 * We must acknowledge the irq before we move it or the acknowledge will
-	 * not propogate properly.
+	 * not propagate properly.
 	 */
 	ack_APIC_irq();
 
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index 3bc30d2..3eaceac 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -32,7 +32,7 @@
  */
 static inline void stack_overflow_check(struct pt_regs *regs)
 {
-	u64 curbase = (u64) current->thread_info;
+	u64 curbase = (u64)task_stack_page(current);
 	static unsigned long warned = -60*HZ;
 
 	if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 44216964..a14375d 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -720,9 +720,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		mce_create_device(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		mce_remove_device(cpu);
 		break;
 	}
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
index d0bd5d6..03356e6 100644
--- a/arch/x86_64/kernel/mce_amd.c
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -654,9 +654,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		threshold_create_device(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		threshold_remove_device(cpu);
 		break;
 	default:
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index dc32cef..51d4c6f 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -327,7 +327,7 @@
 cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
 {
 	long cpu = (long)arg;
-	if (action == CPU_ONLINE)
+	if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
 		smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1);
 	return NOTIFY_DONE;
 }
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index b256cfb..698079b 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -70,7 +70,7 @@
 	DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
 	DEFINE(TASK_PID, offsetof (struct task_struct, pid));
 	DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
-	DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+	DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
 	DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
 	BLANK();
 
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index ca76f07..f5319d7 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -1,5 +1,5 @@
 /*
- * arch/xtensa/pci-dma.c
+ * arch/xtensa/kernel/pci-dma.c
  *
  * DMA coherent memory allocation.
  *
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 640aa83..109e91b 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -1306,7 +1306,7 @@
 	struct as_data *ad = e->elevator_data;
 
 	del_timer_sync(&ad->antic_timer);
-	kblockd_flush();
+	kblockd_flush_work(&ad->antic_work);
 
 	BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
 	BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
diff --git a/block/genhd.c b/block/genhd.c
index b566444..93a2cf6 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -213,6 +213,59 @@
 	return  kobj ? to_disk(kobj) : NULL;
 }
 
+/*
+ * print a full list of all partitions - intended for places where the root
+ * filesystem can't be mounted and thus to give the victim some idea of what
+ * went wrong
+ */
+void __init printk_all_partitions(void)
+{
+	int n;
+	struct gendisk *sgp;
+
+	mutex_lock(&block_subsys_lock);
+	/* For each block device... */
+	list_for_each_entry(sgp, &block_subsys.list, kobj.entry) {
+		char buf[BDEVNAME_SIZE];
+		/*
+		 * Don't show empty devices or things that have been surpressed
+		 */
+		if (get_capacity(sgp) == 0 ||
+		    (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
+			continue;
+
+		/*
+		 * Note, unlike /proc/partitions, I am showing the numbers in
+		 * hex - the same format as the root= option takes.
+		 */
+		printk("%02x%02x %10llu %s",
+			sgp->major, sgp->first_minor,
+			(unsigned long long)get_capacity(sgp) >> 1,
+			disk_name(sgp, 0, buf));
+		if (sgp->driverfs_dev != NULL &&
+		    sgp->driverfs_dev->driver != NULL)
+			printk(" driver: %s\n",
+				sgp->driverfs_dev->driver->name);
+		else
+			printk(" (driver?)\n");
+
+		/* now show the partitions */
+		for (n = 0; n < sgp->minors - 1; ++n) {
+			if (sgp->part[n] == NULL)
+				continue;
+			if (sgp->part[n]->nr_sects == 0)
+				continue;
+			printk("  %02x%02x %10llu %s\n",
+				sgp->major, n + 1 + sgp->first_minor,
+				(unsigned long long)sgp->part[n]->nr_sects >> 1,
+				disk_name(sgp, n + 1, buf));
+		} /* partition subloop */
+	} /* Block device loop */
+
+	mutex_unlock(&block_subsys_lock);
+	return;
+}
+
 #ifdef CONFIG_PROC_FS
 /* iterator */
 static void *part_start(struct seq_file *part, loff_t *pos)
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index d99d402..17e1889 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1704,7 +1704,7 @@
  *     on a queue, such as calling the unplug function after a timeout.
  *     A block device may call blk_sync_queue to ensure that any
  *     such activity is cancelled, thus allowing it to release resources
- *     the the callbacks might use. The caller must already have made sure
+ *     that the callbacks might use. The caller must already have made sure
  *     that its ->make_request_fn will not re-add plugging prior to calling
  *     this function.
  *
@@ -1712,7 +1712,6 @@
 void blk_sync_queue(struct request_queue *q)
 {
 	del_timer_sync(&q->unplug_timer);
-	kblockd_flush();
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -3508,7 +3507,7 @@
 	 * If a CPU goes away, splice its entries to the current CPU
 	 * and trigger a run of the softirq
 	 */
-	if (action == CPU_DEAD) {
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
 		int cpu = (unsigned long) hcpu;
 
 		local_irq_disable();
@@ -3632,11 +3631,11 @@
 
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-void kblockd_flush(void)
+void kblockd_flush_work(struct work_struct *work)
 {
-	flush_workqueue(kblockd_workqueue);
+	cancel_work_sync(work);
 }
-EXPORT_SYMBOL(kblockd_flush);
+EXPORT_SYMBOL(kblockd_flush_work);
 
 int __init blk_dev_init(void)
 {
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 620e14c..4ca0ab3 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -271,7 +271,7 @@
 
 	  Keys are allowed to be from 0 to 256 bits in length, in steps
 	  of 8 bits.  Also includes the 'Tnepres' algorithm, a reversed
-	  variant of Serpent for compatibility with old kerneli code.
+	  variant of Serpent for compatibility with old kerneli.org code.
 
 	  See also:
 	  <http://www.cl.cam.ac.uk/~rja14/serpent.html>
diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
index 6958ea8..e5fb7cc 100644
--- a/crypto/cryptomgr.c
+++ b/crypto/cryptomgr.c
@@ -24,8 +24,6 @@
 #include "internal.h"
 
 struct cryptomgr_param {
-	struct task_struct *thread;
-
 	struct rtattr *tb[CRYPTOA_MAX];
 
 	struct {
@@ -81,6 +79,7 @@
 
 static int cryptomgr_schedule_probe(struct crypto_larval *larval)
 {
+	struct task_struct *thread;
 	struct cryptomgr_param *param;
 	const char *name = larval->alg.cra_name;
 	const char *p;
@@ -130,8 +129,8 @@
 
 	memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
 
-	param->thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
-	if (IS_ERR(param->thread))
+	thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
+	if (IS_ERR(thread))
 		goto err_free_param;
 
 	return NOTIFY_STOP;
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 4dd0dab..8fcd6a1 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -228,7 +228,7 @@
 	return 0;
 }
 
-int __meminit acpi_get_pxm(acpi_handle h)
+int acpi_get_pxm(acpi_handle h)
 {
 	unsigned long pxm;
 	acpi_status status;
@@ -246,7 +246,7 @@
 }
 EXPORT_SYMBOL(acpi_get_pxm);
 
-int __meminit acpi_get_node(acpi_handle *handle)
+int acpi_get_node(acpi_handle *handle)
 {
 	int pxm, node = -1;
 
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index f8c6341..52b2347 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -29,7 +29,6 @@
 	[PM_SUSPEND_ON] = ACPI_STATE_S0,
 	[PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
 	[PM_SUSPEND_MEM] = ACPI_STATE_S3,
-	[PM_SUSPEND_DISK] = ACPI_STATE_S4,
 	[PM_SUSPEND_MAX] = ACPI_STATE_S5
 };
 
@@ -94,14 +93,6 @@
 		do_suspend_lowlevel();
 		break;
 
-	case PM_SUSPEND_DISK:
-		if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
-			status = acpi_enter_sleep_state(acpi_state);
-		break;
-	case PM_SUSPEND_MAX:
-		acpi_power_off();
-		break;
-
 	default:
 		return -EINVAL;
 	}
@@ -157,12 +148,13 @@
 	suspend_state_t states[] = {
 		[1] = PM_SUSPEND_STANDBY,
 		[3] = PM_SUSPEND_MEM,
-		[4] = PM_SUSPEND_DISK,
 		[5] = PM_SUSPEND_MAX
 	};
 
 	if (acpi_state < 6 && states[acpi_state])
 		return pm_suspend(states[acpi_state]);
+	if (acpi_state == 4)
+		return hibernate();
 	return -EINVAL;
 }
 
@@ -189,6 +181,49 @@
 	.finish = acpi_pm_finish,
 };
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static int acpi_hibernation_prepare(void)
+{
+	return acpi_sleep_prepare(ACPI_STATE_S4);
+}
+
+static int acpi_hibernation_enter(void)
+{
+	acpi_status status = AE_OK;
+	unsigned long flags = 0;
+
+	ACPI_FLUSH_CPU_CACHE();
+
+	local_irq_save(flags);
+	acpi_enable_wakeup_device(ACPI_STATE_S4);
+	/* This shouldn't return.  If it returns, we have a problem */
+	status = acpi_enter_sleep_state(ACPI_STATE_S4);
+	local_irq_restore(flags);
+
+	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_finish(void)
+{
+	acpi_leave_sleep_state(ACPI_STATE_S4);
+	acpi_disable_wakeup_device(ACPI_STATE_S4);
+
+	/* reset firmware waking vector */
+	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+	if (init_8259A_after_S1) {
+		printk("Broken toshiba laptop -> kicking interrupts\n");
+		init_8259A(0);
+	}
+}
+
+static struct hibernation_ops acpi_hibernation_ops = {
+	.prepare = acpi_hibernation_prepare,
+	.enter = acpi_hibernation_enter,
+	.finish = acpi_hibernation_finish,
+};
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
 /*
  * Toshiba fails to preserve interrupts over S1, reinitialization
  * of 8259 is needed after S1 resume.
@@ -227,14 +262,18 @@
 			sleep_states[i] = 1;
 			printk(" S%d", i);
 		}
-		if (i == ACPI_STATE_S4) {
-			if (sleep_states[i])
-				acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
-		}
 	}
 	printk(")\n");
 
 	pm_set_ops(&acpi_pm_ops);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	if (sleep_states[ACPI_STATE_S4])
+		hibernation_set_ops(&acpi_hibernation_ops);
+#else
+	sleep_states[ACPI_STATE_S4] = 0;
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 5a76e5b..76b45f0 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -60,7 +60,7 @@
 	state = simple_strtoul(str, NULL, 0);
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	if (state == 4) {
-		error = pm_suspend(PM_SUSPEND_DISK);
+		error = hibernate();
 		goto Done;
 	}
 #endif
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 45dbdc1..c721966 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -435,7 +435,7 @@
 	help
 	  This option enables DMA/PIO support for the later OPTi
 	  controllers found on some old motherboards and in some
-	  latops
+	  laptops.
 
 	  If unsure, say N.
 
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 03a0acf..cb3eab6e 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -489,8 +489,7 @@
 
 	/* convert gtf to tf */
 	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
-	tf.protocol = atadev->class == ATA_DEV_ATAPI ?
-		ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
+	tf.protocol = ATA_PROT_NODATA;
 	tf.feature = gtf->tfa[0];	/* 0x1f1 */
 	tf.nsect   = gtf->tfa[1];	/* 0x1f2 */
 	tf.lbal    = gtf->tfa[2];	/* 0x1f3 */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index a795088..4595d1f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -895,6 +895,7 @@
 /**
  *	ata_set_native_max_address_ext	-	LBA48 native max set
  *	@dev: Device to query
+ *	@new_sectors: new max sectors value to set for the device
  *
  *	Perform an LBA48 size set max upon the device in question. Return the
  *	actual LBA48 size or zero if the command fails.
@@ -932,6 +933,7 @@
 /**
  *	ata_set_native_max_address	-	LBA28 native max set
  *	@dev: Device to query
+ *	@new_sectors: new max sectors value to set for the device
  *
  *	Perform an LBA28 size set max upon the device in question. Return the
  *	actual LBA28 size or zero if the command fails.
@@ -1316,7 +1318,7 @@
 	spin_unlock_irqrestore(ap->lock, flags);
 
 	DPRINTK("flush #1\n");
-	flush_workqueue(ata_wq);
+	cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */
 
 	/*
 	 * At this point, if a task is running, it's guaranteed to see
@@ -1327,7 +1329,7 @@
 		if (ata_msg_ctl(ap))
 			ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
 					__FUNCTION__);
-		flush_workqueue(ata_wq);
+		cancel_work_sync(&ap->port_task.work);
 	}
 
 	spin_lock_irqsave(ap->lock, flags);
@@ -6475,9 +6477,9 @@
 	/* Flush hotplug task.  The sequence is similar to
 	 * ata_port_flush_task().
 	 */
-	flush_workqueue(ata_aux_wq);
+	cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */
 	cancel_delayed_work(&ap->hotplug_task);
-	flush_workqueue(ata_aux_wq);
+	cancel_work_sync(&ap->hotplug_task.work);
 
  skip_eh:
 	/* remove the associated SCSI host */
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 75dc847..11245e3 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -357,6 +357,7 @@
 	PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),	/* I-O Data CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),	/* Mitsubishi CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 27685ce..fb8c9e1 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -375,7 +375,7 @@
 				res = inb(port + 3);
 				if (res & 1) {
 					/* Single channel mode */
-					if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04))
+					if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
 						ct++;
 				} else {
 					/* Dual channel mode */
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 5df354d..203f463 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -1142,14 +1142,14 @@
 	static int printed_version;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
 	const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
-	struct device *dev = &pdev->dev;
+	struct ata_host *host;
 	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev,
 			   "version " DRV_VERSION "\n");
 
-	host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
 	if (!host)
 		return -ENOMEM;
 
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index e2e795e..a097595 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -257,6 +257,8 @@
 static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
 static int nv_adma_port_resume(struct ata_port *ap);
 #endif
+static void nv_adma_freeze(struct ata_port *ap);
+static void nv_adma_thaw(struct ata_port *ap);
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -444,8 +446,8 @@
 	.bmdma_status		= ata_bmdma_status,
 	.qc_prep		= nv_adma_qc_prep,
 	.qc_issue		= nv_adma_qc_issue,
-	.freeze			= nv_ck804_freeze,
-	.thaw			= nv_ck804_thaw,
+	.freeze			= nv_adma_freeze,
+	.thaw			= nv_adma_thaw,
 	.error_handler		= nv_adma_error_handler,
 	.post_internal_cmd	= nv_adma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
@@ -815,8 +817,16 @@
 			u16 status;
 			u32 gen_ctl;
 			u32 notifier, notifier_error;
+			
+			/* if ADMA is disabled, use standard ata interrupt handler */
+			if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+				u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+					>> (NV_INT_PORT_SHIFT * i);
+				handled += nv_host_intr(ap, irq_stat);
+				continue;
+			}
 
-			/* if in ATA register mode, use standard ata interrupt handler */
+			/* if in ATA register mode, check for standard interrupts */
 			if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
 				u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
 					>> (NV_INT_PORT_SHIFT * i);
@@ -826,7 +836,6 @@
 					    command is active, to prevent losing interrupts. */
 					irq_stat |= NV_INT_DEV;
 				handled += nv_host_intr(ap, irq_stat);
-				continue;
 			}
 
 			notifier = readl(mmio + NV_ADMA_NOTIFIER);
@@ -912,22 +921,77 @@
 	return IRQ_RETVAL(handled);
 }
 
+static void nv_adma_freeze(struct ata_port *ap)
+{
+	struct nv_adma_port_priv *pp = ap->private_data;
+	void __iomem *mmio = pp->ctl_block;
+	u16 tmp;
+
+	nv_ck804_freeze(ap);
+
+	if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+		return;
+
+	/* clear any outstanding CK804 notifications */
+	writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+		ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
+
+	/* Disable interrupt */
+	tmp = readw(mmio + NV_ADMA_CTL);
+	writew( tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+		mmio + NV_ADMA_CTL);
+	readw( mmio + NV_ADMA_CTL );	/* flush posted write */
+}
+
+static void nv_adma_thaw(struct ata_port *ap)
+{
+	struct nv_adma_port_priv *pp = ap->private_data;
+	void __iomem *mmio = pp->ctl_block;
+	u16 tmp;
+
+	nv_ck804_thaw(ap);
+
+	if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+		return;
+
+	/* Enable interrupt */
+	tmp = readw(mmio + NV_ADMA_CTL);
+	writew( tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+		mmio + NV_ADMA_CTL);
+	readw( mmio + NV_ADMA_CTL );	/* flush posted write */
+}
+
 static void nv_adma_irq_clear(struct ata_port *ap)
 {
 	struct nv_adma_port_priv *pp = ap->private_data;
 	void __iomem *mmio = pp->ctl_block;
-	u16 status = readw(mmio + NV_ADMA_STAT);
-	u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
-	u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
-	void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+	u32 notifier_clears[2];
+
+	if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+		ata_bmdma_irq_clear(ap);
+		return;
+	}
+
+	/* clear any outstanding CK804 notifications */
+	writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+		ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
 
 	/* clear ADMA status */
-	writew(status, mmio + NV_ADMA_STAT);
-	writel(notifier | notifier_error,
-	       pp->notifier_clear_block);
-
-	/** clear legacy status */
-	iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
+	writew(0xffff, mmio + NV_ADMA_STAT);
+	
+	/* clear notifiers - note both ports need to be written with
+	   something even though we are only clearing on one */
+	if (ap->port_no == 0) {
+		notifier_clears[0] = 0xFFFFFFFF;
+		notifier_clears[1] = 0;
+	} else {
+		notifier_clears[0] = 0;
+		notifier_clears[1] = 0xFFFFFFFF;
+	}
+	pp = ap->host->ports[0]->private_data;
+	writel(notifier_clears[0], pp->notifier_clear_block);
+	pp = ap->host->ports[1]->private_data;
+	writel(notifier_clears[1], pp->notifier_clear_block);
 }
 
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index f56549b..3a7d9b5 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,7 +45,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME	"sata_promise"
-#define DRV_VERSION	"2.05"
+#define DRV_VERSION	"2.07"
 
 
 enum {
@@ -653,6 +653,8 @@
 	qc->err_mask |= ac_err_mask;
 
 	pdc_reset_port(ap);
+
+	ata_port_abort(ap);
 }
 
 static inline unsigned int pdc_host_intr( struct ata_port *ap,
@@ -924,6 +926,7 @@
 	struct ata_host *host;
 	void __iomem *base;
 	int n_ports, i, rc;
+	int is_sataii_tx4;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -962,10 +965,23 @@
 	}
 	host->iomap = pcim_iomap_table(pdev);
 
-	for (i = 0; i < host->n_ports; i++)
+	is_sataii_tx4 = 0;
+	if ((pi->flags & (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) == (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) {
+		is_sataii_tx4 = 1;
+		dev_printk(KERN_INFO, &pdev->dev, "applying SATAII TX4 port numbering workaround\n");
+	}
+	for (i = 0; i < host->n_ports; i++) {
+		static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2};
+		int ata_nr;
+
+		ata_nr = i;
+		if (is_sataii_tx4)
+			ata_nr = sataii_tx4_port_remap[i];
+
 		pdc_ata_setup_port(host->ports[i],
-				   base + 0x200 + i * 0x80,
-				   base + 0x400 + i * 0x100);
+				   base + 0x200 + ata_nr * 0x80,
+				   base + 0x400 + ata_nr * 0x100);
+	}
 
 	/* initialize adapter */
 	pdc_host_init(host);
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 305ab7c..939c924 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -93,6 +93,10 @@
 	.name			= DRV_NAME,
 	.id_table		= svia_pci_tbl,
 	.probe			= svia_init_one,
+#ifdef CONFIG_PM
+	.suspend		= ata_pci_device_suspend,
+	.resume			= ata_pci_device_resume,
+#endif
 	.remove			= ata_pci_remove_one,
 };
 
@@ -112,6 +116,10 @@
 	.slave_configure	= ata_scsi_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
+#ifdef CONFIG_PM
+	.suspend		= ata_scsi_device_suspend,
+	.resume			= ata_scsi_device_resume,
+#endif
 };
 
 static const struct ata_port_operations vt6420_sata_ops = {
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index e177c95..e1c0730 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -101,19 +101,6 @@
 	list_add_tail(&node->entry, &dev->devres_head);
 }
 
-/**
- * devres_alloc - Allocate device resource data
- * @release: Release function devres will be associated with
- * @size: Allocation size
- * @gfp: Allocation flags
- *
- * allocate devres of @size bytes.  The allocated area is zeroed, then
- * associated with @release.  The returned pointer can be passed to
- * other devres_*() functions.
- *
- * RETURNS:
- * Pointer to allocated devres on success, NULL on failure.
- */
 #ifdef CONFIG_DEBUG_DEVRES
 void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
 		      const char *name)
@@ -128,6 +115,19 @@
 }
 EXPORT_SYMBOL_GPL(__devres_alloc);
 #else
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * Allocate devres of @size bytes.  The allocated area is zeroed, then
+ * associated with @release.  The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
 void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
 {
 	struct devres *dr;
@@ -416,7 +416,7 @@
 }
 
 /**
- * devres_release_all - Release all resources
+ * devres_release_all - Release all managed resources
  * @dev: Device to release resources for
  *
  * Release all resources associated with @dev.  This function is
@@ -600,7 +600,7 @@
 }
 
 /**
- * devm_kzalloc - Managed kzalloc
+ * devm_kzalloc - Resource-managed kzalloc
  * @dev: Device to allocate memory for
  * @size: Allocation size
  * @gfp: Allocation gfp flags
@@ -628,7 +628,7 @@
 EXPORT_SYMBOL_GPL(devm_kzalloc);
 
 /**
- * devm_kfree - Managed kfree
+ * devm_kfree - Resource-managed kfree
  * @dev: Device this memory belongs to
  * @p: Memory to free
  *
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index eb84d9d..869ff8c 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -360,7 +360,7 @@
  *	This function creates a simple platform device that requires minimal
  *	resource and memory management. Canned release function freeing
  *	memory allocated for the device allows drivers using such devices
- *	to be unloaded iwithout waiting for the last reference to the device
+ *	to be unloaded without waiting for the last reference to the device
  *	to be dropped.
  *
  *	This interface is primarily intended for use with legacy drivers
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 067a9e8..8d8cdfe 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -126,10 +126,13 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		rc = topology_add_dev(cpu);
 		break;
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		topology_remove_dev(cpu);
 		break;
 	}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index af6d7274..18cdd8c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -243,17 +243,13 @@
 		transfer_result = lo_do_transfer(lo, WRITE, page, offset,
 				bvec->bv_page, bv_offs, size, IV);
 		if (unlikely(transfer_result)) {
-			char *kaddr;
-
 			/*
 			 * The transfer failed, but we still write the data to
 			 * keep prepare/commit calls balanced.
 			 */
 			printk(KERN_ERR "loop: transfer error block %llu\n",
 			       (unsigned long long)index);
-			kaddr = kmap_atomic(page, KM_USER0);
-			memset(kaddr + offset, 0, size);
-			kunmap_atomic(kaddr, KM_USER0);
+			zero_user_page(page, offset, size, KM_USER0);
 		}
 		flush_dcache_page(page);
 		ret = aops->commit_write(file, page, offset,
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 090796b..069ae39 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -366,20 +366,25 @@
 	.show = pid_show,
 };
 
-static void nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *lo)
 {
 	struct request *req;
+	int ret;
 
 	BUG_ON(lo->magic != LO_MAGIC);
 
 	lo->pid = current->pid;
-	sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+	ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+	if (ret) {
+		printk(KERN_ERR "nbd: sysfs_create_file failed!");
+		return ret;
+	}
 
 	while ((req = nbd_read_stat(lo)) != NULL)
 		nbd_end_request(req);
 
 	sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
-	return;
+	return 0;
 }
 
 static void nbd_clear_que(struct nbd_device *lo)
@@ -569,7 +574,9 @@
 	case NBD_DO_IT:
 		if (!lo->file)
 			return -EINVAL;
-		nbd_do_it(lo);
+		error = nbd_do_it(lo);
+		if (error)
+			return error;
 		/* on return tidy up in case we have a signal */
 		/* Forcibly shutdown the socket causing all listeners
 		 * to error
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 43d4ebc..a1512da 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -151,7 +151,7 @@
 }
 
 /*
- * ->writepage to the the blockdev's mapping has to redirty the page so that the
+ * ->writepage to the blockdev's mapping has to redirty the page so that the
  * VM doesn't go and steal it.  We return AOP_WRITEPAGE_ACTIVATE so that the VM
  * won't try to (pointlessly) write the page again for a while.
  *
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1e32fb8..2df42fd 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -631,7 +631,8 @@
 
 config HVC_ISERIES
 	bool "iSeries Hypervisor Virtual Console support"
-	depends on PPC_ISERIES && !VIOCONS
+	depends on PPC_ISERIES
+	default y
 	select HVC_DRIVER
 	help
 	  iSeries machines support a hypervisor virtual console.
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 892db70..32ed19c 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -65,7 +65,7 @@
  * \param dev DRM device.
  *
  * Free all pages associated with DMA buffers, the buffers and pages lists, and
- * finally the the drm_device::dma structure itself.
+ * finally the drm_device::dma structure itself.
  */
 void drm_dma_takedown(drm_device_t * dev)
 {
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 35540cf..b5c5b9f 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -157,7 +157,7 @@
  * \param address access address.
  * \return pointer to the page structure.
  *
- * Get the the mapping, find the real physical page to map, get the page, and
+ * Get the mapping, find the real physical page to map, get the page, and
  * return it.
  */
 static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index a881f96..ecda760 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -293,7 +293,7 @@
 #       define R300_PVS_CNTL_1_PROGRAM_START_SHIFT   0
 #       define R300_PVS_CNTL_1_POS_END_SHIFT         10
 #       define R300_PVS_CNTL_1_PROGRAM_END_SHIFT     20
-/* Addresses are relative the the vertex program parameters area. */
+/* Addresses are relative to the vertex program parameters area. */
 #define R300_VAP_PVS_CNTL_2                 0x22D4
 #       define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
 #       define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT  16
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 49f914e..9e1fc02 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -12,7 +12,7 @@
  *
  *	This driver allows use of the real time clock (built into
  *	nearly all computers) from user space. It exports the /dev/rtc
- *	interface supporting various ioctl() and also the /proc/dev/rtc
+ *	interface supporting various ioctl() and also the /proc/driver/rtc
  *	pseudo-file for status information.
  *
  *	The ioctls can be used to set the interrupt behaviour where
@@ -377,7 +377,7 @@
 #ifdef CONFIG_PROC_FS
 
 /*
- *	Info exported via "/proc/rtc".
+ *	Info exported via "/proc/driver/rtc".
  */
 
 static int gen_rtc_proc_output(char *buf)
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5f3acd8..7cda04b 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -91,3 +91,17 @@
 	  module will be called omap-rng.
 
  	  If unsure, say Y.
+
+config HW_RANDOM_PASEMI
+	tristate "PA Semi HW Random Number Generator support"
+	depends on HW_RANDOM && PPC_PASEMI
+	default HW_RANDOM
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on PA6T-1682M processor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pasemi-rng.
+
+	  If unsure, say Y.
+
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c41fa19..c8b7300 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
 obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644
index 0000000..fa6040b
--- /dev/null
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip rng
+ *
+ * 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 License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+
+#define SDCRNG_CTL_REG			0x00
+#define   SDCRNG_CTL_FVLD_M		0x0000f000
+#define   SDCRNG_CTL_FVLD_S		12
+#define   SDCRNG_CTL_KSZ		0x00000800
+#define   SDCRNG_CTL_RSRC_CRG		0x00000010
+#define   SDCRNG_CTL_RSRC_RRG		0x00000000
+#define   SDCRNG_CTL_CE			0x00000004
+#define   SDCRNG_CTL_RE			0x00000002
+#define   SDCRNG_CTL_DR			0x00000001
+#define   SDCRNG_CTL_SELECT_RRG_RNG	(SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
+#define   SDCRNG_CTL_SELECT_CRG_RNG	(SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
+#define SDCRNG_VAL_REG			0x20
+
+#define MODULE_NAME "pasemi_rng"
+
+static int pasemi_rng_data_present(struct hwrng *rng)
+{
+	void __iomem *rng_regs = (void __iomem *)rng->priv;
+
+	return (in_le32(rng_regs + SDCRNG_CTL_REG)
+		& SDCRNG_CTL_FVLD_M) ? 1 : 0;
+}
+
+static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	void __iomem *rng_regs = (void __iomem *)rng->priv;
+	*data = in_le32(rng_regs + SDCRNG_VAL_REG);
+	return 4;
+}
+
+static int pasemi_rng_init(struct hwrng *rng)
+{
+	void __iomem *rng_regs = (void __iomem *)rng->priv;
+	u32 ctl;
+
+	ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
+	out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
+	out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
+
+	return 0;
+}
+
+static void pasemi_rng_cleanup(struct hwrng *rng)
+{
+	void __iomem *rng_regs = (void __iomem *)rng->priv;
+	u32 ctl;
+
+	ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
+	out_le32(rng_regs + SDCRNG_CTL_REG,
+		 in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
+}
+
+static struct hwrng pasemi_rng = {
+	.name		= MODULE_NAME,
+	.init		= pasemi_rng_init,
+	.cleanup	= pasemi_rng_cleanup,
+	.data_present	= pasemi_rng_data_present,
+	.data_read	= pasemi_rng_data_read,
+};
+
+static int __devinit rng_probe(struct of_device *ofdev,
+			       const struct of_device_id *match)
+{
+	void __iomem *rng_regs;
+	struct device_node *rng_np = ofdev->node;
+	struct resource res;
+	int err = 0;
+
+	err = of_address_to_resource(rng_np, 0, &res);
+	if (err)
+		return -ENODEV;
+
+	rng_regs = ioremap(res.start, 0x100);
+
+	if (!rng_regs)
+		return -ENOMEM;
+
+	pasemi_rng.priv = (unsigned long)rng_regs;
+
+	printk(KERN_INFO "Registering PA Semi RNG\n");
+
+	err = hwrng_register(&pasemi_rng);
+
+	if (err)
+		iounmap(rng_regs);
+
+	return err;
+}
+
+static int __devexit rng_remove(struct of_device *dev)
+{
+	void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
+
+	hwrng_unregister(&pasemi_rng);
+	iounmap(rng_regs);
+
+	return 0;
+}
+
+static struct of_device_id rng_match[] = {
+	{
+		.compatible      = "1682m-rng",
+	},
+	{},
+};
+
+static struct of_platform_driver rng_driver = {
+	.name		= "pasemi-rng",
+	.match_table	= rng_match,
+	.probe		= rng_probe,
+	.remove		= rng_remove,
+};
+
+static int __init rng_init(void)
+{
+	return of_register_platform_driver(&rng_driver);
+}
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+	of_unregister_platform_driver(&rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index c091603..6e55cfb 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -705,15 +705,13 @@
 	maxn++;
 
 	/* Allocate list of node ptrs to mmtimer_t's */
-	timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+	timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
 	if (timers == NULL) {
 		printk(KERN_ERR "%s: failed to allocate memory for device\n",
 				MMTIMER_NAME);
 		goto out3;
 	}
 
-	memset(timers,0,(sizeof(mmtimer_t *)*maxn));
-
 	/* Allocate mmtimer_t's for each online node */
 	for_each_online_node(node) {
 		timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index 27c1179..f25facd 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -21,6 +21,7 @@
 config CARDMAN_4000
 	tristate "Omnikey Cardman 4000 support"
 	depends on PCMCIA
+	select BITREVERSE
 	help
 	  Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
 	  reader.
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e91b43a..fee58e0 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
+#include <linux/bitrev.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -194,41 +195,17 @@
 }
 #endif
 
-#define	b_0000	15
-#define	b_0001	14
-#define	b_0010	13
-#define	b_0011	12
-#define	b_0100	11
-#define	b_0101	10
-#define	b_0110	9
-#define	b_0111	8
-#define	b_1000	7
-#define	b_1001	6
-#define	b_1010	5
-#define	b_1011	4
-#define	b_1100	3
-#define	b_1101	2
-#define	b_1110	1
-#define	b_1111	0
-
-static unsigned char irtab[16] = {
-	b_0000, b_1000, b_0100, b_1100,
-	b_0010, b_1010, b_0110, b_1110,
-	b_0001, b_1001, b_0101, b_1101,
-	b_0011, b_1011, b_0111, b_1111
-};
+static inline unsigned char invert_revert(unsigned char ch)
+{
+	return bitrev8(~ch);
+}
 
 static void str_invert_revert(unsigned char *b, int len)
 {
 	int i;
 
 	for (i = 0; i < len; i++)
-		b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
-}
-
-static unsigned char invert_revert(unsigned char ch)
-{
-	return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+		b[i] = invert_revert(b[i]);
 }
 
 #define	ATRLENCK(dev,pos) \
@@ -1114,7 +1091,7 @@
 	/*
 	 * wait for atr to become valid.
 	 * note: it is important to lock this code. if we dont, the monitor
-	 * could be run between test_bit and the the call the sleep on the
+	 * could be run between test_bit and the call to sleep on the
 	 * atr-queue.  if *then* the monitor detects atr valid, it will wake up
 	 * any process on the atr-queue, *but* since we have been interrupted,
 	 * we do not yet sleep on this queue. this would result in a missed
@@ -1881,8 +1858,11 @@
 	init_waitqueue_head(&dev->readq);
 
 	ret = cm4000_config(link, i);
-	if (ret)
+	if (ret) {
+		dev_table[i] = NULL;
+		kfree(dev);
 		return ret;
+	}
 
 	class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
 			    "cmm%d", i);
@@ -1907,7 +1887,7 @@
 	cm4000_release(link);
 
 	dev_table[devno] = NULL;
- 	kfree(dev);
+	kfree(dev);
 
 	class_device_destroy(cmm_class, MKDEV(major, devno));
 
@@ -1956,12 +1936,14 @@
 	if (major < 0) {
 		printk(KERN_WARNING MODULE_NAME
 			": could not get major number\n");
+		class_destroy(cmm_class);
 		return major;
 	}
 
 	rc = pcmcia_register_driver(&cm4000_driver);
 	if (rc < 0) {
 		unregister_chrdev(major, DEVICE_NAME);
+		class_destroy(cmm_class);
 		return rc;
 	}
 
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index f2e4ec4..af88181 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -636,8 +636,11 @@
 	setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
 
 	ret = reader_config(link, i);
-	if (ret)
+	if (ret) {
+		dev_table[i] = NULL;
+		kfree(dev);
 		return ret;
+	}
 
 	class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
 			    "cmx%d", i);
@@ -708,12 +711,14 @@
 	if (major < 0) {
 		printk(KERN_WARNING MODULE_NAME
 			": could not get major number\n");
+		class_destroy(cmx_class);
 		return major;
 	}
 
 	rc = pcmcia_register_driver(&reader_driver);
 	if (rc < 0) {
 		unregister_chrdev(major, DEVICE_NAME);
+		class_destroy(cmx_class);
 		return rc;
 	}
 
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index fe00c7d..11089be 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -33,7 +33,7 @@
 	tristate "National Semiconductor TPM Interface"
 	depends on TCG_TPM && PNPACPI
 	---help---
-	  If you have a TPM security chip from National Semicondutor 
+	  If you have a TPM security chip from National Semiconductor 
 	  say Yes and it will be accessible from within Linux.  To 
 	  compile this driver as a module, choose M here; the module 
 	  will be called tpm_nsc.
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7710a6a..fc662e4 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -934,13 +934,6 @@
 		return -EINVAL;
 
 	/*
-	 *	No more input please, we are switching. The new ldisc
-	 *	will update this value in the ldisc open function
-	 */
-
-	tty->receive_room = 0;
-
-	/*
 	 *	Problem: What do we do if this blocks ?
 	 */
 
@@ -951,6 +944,13 @@
 		return 0;
 	}
 
+	/*
+	 *	No more input please, we are switching. The new ldisc
+	 *	will update this value in the ldisc open function
+	 */
+
+	tty->receive_room = 0;
+
 	o_ldisc = tty->ldisc;
 	o_tty = tty->link;
 
@@ -1573,11 +1573,11 @@
 
 
 /**
- *	stop_tty	-	propogate flow control
+ *	stop_tty	-	propagate flow control
  *	@tty: tty to stop
  *
  *	Perform flow control to the driver. For PTY/TTY pairs we
- *	must also propogate the TIOCKPKT status. May be called
+ *	must also propagate the TIOCKPKT status. May be called
  *	on an already stopped device and will not re-call the driver
  *	method.
  *
@@ -1607,11 +1607,11 @@
 EXPORT_SYMBOL(stop_tty);
 
 /**
- *	start_tty	-	propogate flow control
+ *	start_tty	-	propagate flow control
  *	@tty: tty to start
  *
  *	Start a tty that has been stopped if at all possible. Perform
- *	any neccessary wakeups and propogate the TIOCPKT status. If this
+ *	any neccessary wakeups and propagate the TIOCPKT status. If this
  *	is the tty was previous stopped and is being started then the
  *	driver start method is invoked and the line discipline woken.
  *
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 893dbaf..eb37fba 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1685,9 +1685,11 @@
 	if (sys_dev) {
 		switch (action) {
 		case CPU_ONLINE:
+		case CPU_ONLINE_FROZEN:
 			cpufreq_add_dev(sys_dev);
 			break;
 		case CPU_DOWN_PREPARE:
+		case CPU_DOWN_PREPARE_FROZEN:
 			if (unlikely(lock_policy_rwsem_write(cpu)))
 				BUG();
 
@@ -1699,6 +1701,7 @@
 			__cpufreq_remove_dev(sys_dev);
 			break;
 		case CPU_DOWN_FAILED:
+		case CPU_DOWN_FAILED_FROZEN:
 			cpufreq_add_dev(sys_dev);
 			break;
 		}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d1c7cac..d2f0cbd 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -313,9 +313,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		cpufreq_update_policy(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		cpufreq_stats_free_table(cpu);
 		break;
 	}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index f21fe66..f4c6345 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,7 +51,7 @@
 	default m
 	help
 	  Say 'Y' here to use the AMD Geode LX processor on-board AES
-	  engine for the CryptoAPI AES alogrithm.
+	  engine for the CryptoAPI AES algorithm.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called geode-aes.
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 3215f9c..b51c104 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -981,7 +981,7 @@
 static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
 	applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
 \
-static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \
+static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
 	applesmc_show_fan_position, NULL, offset-1); \
 \
 static struct attribute *fan##offset##_attributes[] = { \
@@ -991,7 +991,7 @@
 	&sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
 	&sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
 	&sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
-	&sensor_dev_attr_fan##offset##_position.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
 	NULL \
 };
 
@@ -1190,7 +1190,8 @@
 	if (ret)
 		goto out_region;
 
-	pdev = platform_device_register_simple("applesmc", -1, NULL, 0);
+	pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
+					       NULL, 0);
 	if (IS_ERR(pdev)) {
 		ret = PTR_ERR(pdev);
 		goto out_driver;
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 03b1f65..75e3911 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -309,9 +309,11 @@
 
 	switch (action) {
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		coretemp_device_add(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		coretemp_device_remove(cpu);
 		break;
 	}
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 7ed92dc..3c3f2eb 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -354,7 +354,7 @@
 			 * also needs to get error handling and probably
 			 * an #ifdef CONFIG_SOFTWARE_SUSPEND
 			 */
-			pm_suspend(PM_SUSPEND_DISK);
+			hibernate();
 #endif
 			poll = 1;
 		}
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 5bdf64b..1d06b41 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -291,6 +291,17 @@
 
 	  If you are unsure, say N here.
 
+config IDE_PROC_FS
+	bool "legacy /proc/ide/ support"
+	depends on IDE && PROC_FS
+	default y
+	help
+	  This option enables support for the various files in
+	  /proc/ide.  In Linux 2.6 this has been superseded by
+	  files in sysfs but many legacy applications rely on this.
+
+	  If unsure say Y.
+
 comment "IDE chipset support/bugfixes"
 
 config IDE_GENERIC
@@ -360,6 +371,9 @@
 	  It is safe to say Y to this question, in most cases.
 	  If unsure, say N.
 
+config IDEPCI_PCIBUS_ORDER
+	def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+
 config BLK_DEV_OFFBOARD
 	bool "Boot off-board chipsets first support"
 	depends on PCI && BLK_DEV_IDEPCI
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index d9f029e..75dc696 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -20,7 +20,7 @@
 # Core IDE code - must come before legacy
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
-ide-core-$(CONFIG_PROC_FS)		+= ide-proc.o
+ide-core-$(CONFIG_IDE_PROC_FS)		+= ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
 
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index 9d474e5..f7449d0 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -45,7 +45,7 @@
 	hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
 	hw.irq = irq;
 
-	ide_register_hw(&hw, hwif);
+	ide_register_hw(&hw, 0, hwif);
 
 	return 0;
 }
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index e2953fc..1fe0457 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -342,7 +342,7 @@
 	 * Enable DMA on any drive that has multiword DMA
 	 */
 	if (id->field_valid & 2) {
-		xfer_mode = ide_dma_speed(drive, 0);
+		xfer_mode = ide_max_dma_mode(drive);
 		goto out;
 	}
 
@@ -591,7 +591,8 @@
 	state->hwif[0] = hwif;
 
 	probe_hwif_init(hwif);
-	create_proc_ide_interfaces();
+
+	ide_proc_register_port(hwif);
 
 	return 0;
 }
@@ -679,7 +680,9 @@
 
 	probe_hwif_init(hwif);
 	probe_hwif_init(mate);
-	create_proc_ide_interfaces();
+
+	ide_proc_register_port(hwif);
+	ide_proc_register_port(mate);
 
 	return 0;
 
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index 23488c4..a3d6744 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -38,6 +38,6 @@
 		memset(&hw, 0, sizeof(hw));
 		ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
 		hw.irq = IDE_ARM_IRQ;
-		ide_register_hw(&hw, NULL);
+		ide_register_hw(&hw, 1, NULL);
 	}
 }
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index 9c6c49f..890ea3f 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -76,7 +76,7 @@
 		hwif->gendev.parent = &ec->dev;
 		hwif->noprobe = 0;
 		probe_hwif_init(hwif);
-		create_proc_ide_interfaces();
+		ide_proc_register_port(hwif);
 		ecard_set_drvdata(ec, hwif);
 		goto out;
 	}
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 5e8efc8..c04cb25 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -796,7 +796,7 @@
 		                ide_offsets,
 		                0, 0, cris_ide_ack_intr,
 		                ide_default_irq(0));
-		ide_register_hw(&hw, &hwif);
+		ide_register_hw(&hw, 1, &hwif);
 		hwif->mmio = 1;
 		hwif->chipset = ide_etrax100;
 		hwif->tuneproc = &tune_cris_ide;
@@ -1004,7 +1004,7 @@
 
 static int cris_config_drive_for_dma (ide_drive_t *drive)
 {
-	u8 speed = ide_dma_speed(drive, 1);
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!speed)
 		return 0;
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 88750a3..6d26ad7 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -101,7 +101,7 @@
 	hw_setup(&hw);
 
 	/* register if */
-	idx = ide_register_hw(&hw, &hwif);
+	idx = ide_register_hw(&hw, 1, &hwif);
 	if (idx == -1) {
 		printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
 		return;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 638becd..252ab82 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -3059,10 +3059,14 @@
 	return nslots;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void ide_cdrom_add_settings(ide_drive_t *drive)
 {
-	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
+	ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
 }
+#else
+static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  * standard prep_rq_fn that builds 10 byte cmds
@@ -3274,7 +3278,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static
 sector_t ide_cdrom_capacity (ide_drive_t *drive)
 {
@@ -3291,7 +3295,7 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 
-	ide_unregister_subdriver(drive, info->driver);
+	ide_proc_unregister_driver(drive, info->driver);
 
 	del_gendisk(info->disk);
 
@@ -3321,7 +3325,7 @@
 
 static int ide_cd_probe(ide_drive_t *);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idecd_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -3336,8 +3340,6 @@
 	{ "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
 	{ NULL, 0, NULL, NULL }
 };
-#else
-# define idecd_proc	NULL
 #endif
 
 static ide_driver_t ide_cdrom_driver = {
@@ -3355,7 +3357,9 @@
 	.end_request		= ide_end_request,
 	.error			= __ide_error,
 	.abort			= __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
 	.proc			= idecd_proc,
+#endif
 };
 
 static int idecd_open(struct inode * inode, struct file * file)
@@ -3517,7 +3521,7 @@
 
 	ide_init_disk(g, drive);
 
-	ide_register_subdriver(drive, &ide_cdrom_driver);
+	ide_proc_register_driver(drive, &ide_cdrom_driver);
 
 	kref_init(&info->kref);
 
@@ -3534,7 +3538,7 @@
 	g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
 	if (ide_cdrom_setup(drive)) {
 		struct cdrom_device_info *devinfo = &info->devinfo;
-		ide_unregister_subdriver(drive, &ide_cdrom_driver);
+		ide_proc_unregister_driver(drive, &ide_cdrom_driver);
 		kfree(info->buffer);
 		kfree(info->toc);
 		kfree(info->changer_info);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 37aa6dd..7fff773 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -559,8 +559,7 @@
 	return drive->capacity64 - drive->sect0;
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int smart_enable(ide_drive_t *drive)
 {
 	ide_task_t args;
@@ -678,12 +677,7 @@
 	{ "smart_thresholds",	S_IFREG|S_IRUSR,	proc_idedisk_read_smart_thresholds,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define	idedisk_proc	NULL
-
-#endif	/* CONFIG_PROC_FS */
+#endif	/* CONFIG_IDE_PROC_FS */
 
 static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
 {
@@ -737,6 +731,9 @@
 {
 	struct request rq;
 
+	if (arg < 0 || arg > drive->id->max_multsect)
+		return -EINVAL;
+
 	if (drive->special.b.set_multmode)
 		return -EBUSY;
 	ide_init_drive_cmd (&rq);
@@ -749,6 +746,9 @@
 
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
+
 	if (ide_spin_wait_hwgroup(drive))
 		return -EBUSY;
 	drive->nowerr = arg;
@@ -800,6 +800,9 @@
 	ide_task_t args;
 	int err = 1;
 
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
+
 	if (ide_id_has_flush_cache(drive->id)) {
 		memset(&args, 0, sizeof(ide_task_t));
 		args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
@@ -835,6 +838,9 @@
 {
 	ide_task_t args;
 
+	if (arg < 0 || arg > 254)
+		return -EINVAL;
+
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
 							  SETFEATURES_DIS_AAM;
@@ -855,6 +861,9 @@
  */
 static int set_lba_addressing(ide_drive_t *drive, int arg)
 {
+	if (arg < 0 || arg > 2)
+		return -EINVAL;
+
 	drive->addressing =  0;
 
 	if (HWIF(drive)->no_lba48)
@@ -866,23 +875,27 @@
 	return 0;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idedisk_add_settings(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
-	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
-	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
-	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
-	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
-	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
-	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
-	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
-	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
- 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
- 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	TYPE_INT,	0,	65535,			1,	1,	&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,			1,	1,	&drive->bios_head,	NULL);
+	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,			1,	1,	&drive->bios_sect,	NULL);
+	ide_add_setting(drive,	"address",	SETTING_RW,	TYPE_BYTE,	0,	2,			1,	1,	&drive->addressing,	set_lba_addressing);
+	ide_add_setting(drive,	"bswap",	SETTING_READ,	TYPE_BYTE,	0,	1,			1,	1,	&drive->bswap,		NULL);
+	ide_add_setting(drive,	"multcount",	SETTING_RW,	TYPE_BYTE,	0,	id->max_multsect,	1,	1,	&drive->mult_count,	set_multcount);
+	ide_add_setting(drive,	"nowerr",	SETTING_RW,	TYPE_BYTE,	0,	1,			1,	1,	&drive->nowerr,		set_nowerr);
+	ide_add_setting(drive,	"lun",		SETTING_RW,	TYPE_INT,	0,	7,			1,	1,	&drive->lun,		NULL);
+	ide_add_setting(drive,	"wcache",	SETTING_RW,	TYPE_BYTE,	0,	1,			1,	1,	&drive->wcache,		write_cache);
+	ide_add_setting(drive,	"acoustic",	SETTING_RW,	TYPE_BYTE,	0,	254,			1,	1,	&drive->acoustic,	set_acoustic);
+ 	ide_add_setting(drive,	"failures",	SETTING_RW,	TYPE_INT,	0,	65535,			1,	1,	&drive->failures,	NULL);
+ 	ide_add_setting(drive,	"max_failures",	SETTING_RW,	TYPE_INT,	0,	65535,			1,	1,	&drive->max_failures,	NULL);
 }
+#else
+static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 static void idedisk_setup (ide_drive_t *drive)
 {
@@ -1001,7 +1014,7 @@
 	struct ide_disk_obj *idkp = drive->driver_data;
 	struct gendisk *g = idkp->disk;
 
-	ide_unregister_subdriver(drive, idkp->driver);
+	ide_proc_unregister_driver(drive, idkp->driver);
 
 	del_gendisk(g);
 
@@ -1066,7 +1079,9 @@
 	.end_request		= ide_end_request,
 	.error			= __ide_error,
 	.abort			= __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
 	.proc			= idedisk_proc,
+#endif
 };
 
 static int idedisk_open(struct inode *inode, struct file *filp)
@@ -1140,9 +1155,49 @@
 static int idedisk_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
+	unsigned long flags;
 	struct block_device *bdev = inode->i_bdev;
 	struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
-	return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg);
+	ide_drive_t *drive = idkp->drive;
+	int err, (*setfunc)(ide_drive_t *, int);
+	u8 *val;
+
+	switch (cmd) {
+	case HDIO_GET_ADDRESS:	 val = &drive->addressing;	goto read_val;
+	case HDIO_GET_MULTCOUNT: val = &drive->mult_count;	goto read_val;
+	case HDIO_GET_NOWERR:	 val = &drive->nowerr;		goto read_val;
+	case HDIO_GET_WCACHE:	 val = &drive->wcache;		goto read_val;
+	case HDIO_GET_ACOUSTIC:	 val = &drive->acoustic;	goto read_val;
+	case HDIO_SET_ADDRESS:	 setfunc = set_lba_addressing;	goto set_val;
+	case HDIO_SET_MULTCOUNT: setfunc = set_multcount;	goto set_val;
+	case HDIO_SET_NOWERR:	 setfunc = set_nowerr;		goto set_val;
+	case HDIO_SET_WCACHE:	 setfunc = write_cache;		goto set_val;
+	case HDIO_SET_ACOUSTIC:	 setfunc = set_acoustic;	goto set_val;
+	}
+
+	return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+read_val:
+	down(&ide_setting_sem);
+	spin_lock_irqsave(&ide_lock, flags);
+	err = *val;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	up(&ide_setting_sem);
+	return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+	if (bdev != bdev->bd_contains)
+		err = -EINVAL;
+	else {
+		if (!capable(CAP_SYS_ADMIN))
+			err = -EACCES;
+		else {
+			down(&ide_setting_sem);
+			err = setfunc(drive, arg);
+			up(&ide_setting_sem);
+		}
+	}
+	return err;
 }
 
 static int idedisk_media_changed(struct gendisk *disk)
@@ -1202,7 +1257,7 @@
 
 	ide_init_disk(g, drive);
 
-	ide_register_subdriver(drive, &idedisk_driver);
+	ide_proc_register_driver(drive, &idedisk_driver);
 
 	kref_init(&idkp->kref);
 
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index fd21308..5fe8519 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -705,6 +705,100 @@
 
 EXPORT_SYMBOL_GPL(ide_use_dma);
 
+static const u8 xfer_mode_bases[] = {
+	XFER_UDMA_0,
+	XFER_MW_DMA_0,
+	XFER_SW_DMA_0,
+};
+
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = drive->hwif;
+	unsigned int mask = 0;
+
+	switch(base) {
+	case XFER_UDMA_0:
+		if ((id->field_valid & 4) == 0)
+			break;
+
+		mask = id->dma_ultra & hwif->ultra_mask;
+
+		if (hwif->udma_filter)
+			mask &= hwif->udma_filter(drive);
+
+		if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+			mask &= 0x07;
+		break;
+	case XFER_MW_DMA_0:
+		mask = id->dma_mword & hwif->mwdma_mask;
+		break;
+	case XFER_SW_DMA_0:
+		mask = id->dma_1word & hwif->swdma_mask;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	return mask;
+}
+
+/**
+ *	ide_max_dma_mode	-	compute DMA speed
+ *	@drive: IDE device
+ *
+ *	Checks the drive capabilities and returns the speed to use
+ *	for the DMA transfer.  Returns 0 if the drive is incapable
+ *	of DMA transfers.
+ */
+
+u8 ide_max_dma_mode(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	unsigned int mask;
+	int x, i;
+	u8 mode = 0;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
+		mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
+		x = fls(mask) - 1;
+		if (x >= 0) {
+			mode = xfer_mode_bases[i] + x;
+			break;
+		}
+	}
+
+	printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
+
+	return mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_max_dma_mode);
+
+int ide_tune_dma(ide_drive_t *drive)
+{
+	u8 speed;
+
+	/* TODO: use only ide_max_dma_mode() */
+	if (!ide_use_dma(drive))
+		return 0;
+
+	speed = ide_max_dma_mode(drive);
+
+	if (!speed)
+		return 0;
+
+	drive->hwif->speedproc(drive, speed);
+
+	return ide_dma_enable(drive);
+}
+
+EXPORT_SYMBOL_GPL(ide_tune_dma);
+
 void ide_dma_verbose(ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 57cd21c..f429be8 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1811,18 +1811,22 @@
 	return 0;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idefloppy_add_settings(ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 /*
- *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ *			drive	setting name	read/write	data type	min	max	mul_factor	div_factor	data pointer		set function
  */
-	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	1023,				1,	1,	&drive->bios_cyl,		NULL);
-	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
-	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
-	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	TYPE_INT,	0,	1023,		1,		1,	&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,		1,		1,	&drive->bios_head,	NULL);
+	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,		1,		1,	&drive->bios_sect,	NULL);
+	ide_add_setting(drive,	"ticks",	SETTING_RW,	TYPE_BYTE,	0,	255,		1,		1,	&floppy->ticks,		NULL);
 }
+#else
+static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *	Driver initialization.
@@ -1873,7 +1877,7 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	struct gendisk *g = floppy->disk;
 
-	ide_unregister_subdriver(drive, floppy->driver);
+	ide_proc_unregister_driver(drive, floppy->driver);
 
 	del_gendisk(g);
 
@@ -1892,8 +1896,7 @@
 	kfree(floppy);
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idefloppy_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -1909,12 +1912,7 @@
 	{ "geometry",	S_IFREG|S_IRUGO,	proc_ide_read_geometry,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define	idefloppy_proc	NULL
-
-#endif	/* CONFIG_PROC_FS */
+#endif	/* CONFIG_IDE_PROC_FS */
 
 static int ide_floppy_probe(ide_drive_t *);
 
@@ -1933,7 +1931,9 @@
 	.end_request		= idefloppy_do_end_request,
 	.error			= __ide_error,
 	.abort			= __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
 	.proc			= idefloppy_proc,
+#endif
 };
 
 static int idefloppy_open(struct inode *inode, struct file *filp)
@@ -2159,7 +2159,7 @@
 
 	ide_init_disk(g, drive);
 
-	ide_register_subdriver(drive, &idefloppy_driver);
+	ide_proc_register_driver(drive, &idefloppy_driver);
 
 	kref_init(&floppy->kref);
 
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 99fd561..0f72b98 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -22,8 +22,6 @@
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
 		ide_release_lock();	/* for atari only */
 
-	create_proc_ide_interfaces();
-
 	return 0;
 }
 
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 8670112..8e56814 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -172,15 +172,6 @@
 
 	memset(args, 0, sizeof(*args));
 
-	if (drive->media != ide_disk) {
-		/*
-		 * skip idedisk_pm_restore_pio and idedisk_pm_idle for ATAPI
-		 * devices
-		 */
-		if (pm->pm_step == idedisk_pm_restore_pio)
-			pm->pm_step = ide_pm_restore_dma;
-	}
-
 	switch (pm->pm_step) {
 	case ide_pm_flush_cache:	/* Suspend step 1 (flush cache) */
 		if (drive->media != ide_disk)
@@ -207,7 +198,13 @@
 	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
 		if (drive->hwif->tuneproc != NULL)
 			drive->hwif->tuneproc(drive, 255);
-		ide_complete_power_step(drive, rq, 0, 0);
+		/*
+		 * skip idedisk_pm_idle for ATAPI devices
+		 */
+		if (drive->media != ide_disk)
+			pm->pm_step = ide_pm_restore_dma;
+		else
+			ide_complete_power_step(drive, rq, 0, 0);
 		return ide_stopped;
 
 	case idedisk_pm_idle:		/* Resume step 2 (idle) */
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 3caa176b..f0be5f6 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -571,51 +571,54 @@
  */
 u8 eighty_ninty_three (ide_drive_t *drive)
 {
-	if(HWIF(drive)->udma_four == 0)
-		return 0;
+	ide_hwif_t *hwif = drive->hwif;
+	struct hd_driveid *id = drive->id;
+
+	if (hwif->udma_four == 0)
+		goto no_80w;
 
 	/* Check for SATA but only if we are ATA5 or higher */
-	if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0))
+	if (id->hw_config == 0 && (id->major_rev_num & 0x7FE0))
 		return 1;
-	if (!(drive->id->hw_config & 0x6000))
-		return 0;
-#ifndef CONFIG_IDEDMA_IVB
-	if(!(drive->id->hw_config & 0x4000))
-		return 0;
-#endif /* CONFIG_IDEDMA_IVB */
+
 	/*
 	 * FIXME:
 	 * - change master/slave IDENTIFY order
 	 * - force bit13 (80c cable present) check
 	 *   (unless the slave device is pre-ATA3)
 	 */
-	return 1;
-}
+#ifndef CONFIG_IDEDMA_IVB
+	if (id->hw_config & 0x4000)
+#else
+	if (id->hw_config & 0x6000)
+#endif
+		return 1;
 
-EXPORT_SYMBOL(eighty_ninty_three);
+no_80w:
+	if (drive->udma33_warned == 1)
+		return 0;
+
+	printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
+			    "limiting max speed to UDMA33\n",
+			    drive->name, hwif->udma_four ? "drive" : "host");
+
+	drive->udma33_warned = 1;
+
+	return 0;
+}
 
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
 	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
 	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
 	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-#ifndef CONFIG_IDEDMA_IVB
-		if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-		if (((drive->id->hw_config & 0x2000) == 0) ||
-		    ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-			printk("%s: Speed warnings UDMA 3/4/5 is not "
-				"functional.\n", drive->name);
-			return 1;
-		}
-		if (!HWIF(drive)->udma_four) {
-			printk("%s: Speed warnings UDMA 3/4/5 is not "
-				"functional.\n",
-				HWIF(drive)->name);
+		if (eighty_ninty_three(drive) == 0) {
+			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+					    "be set\n", drive->name);
 			return 1;
 		}
 	}
+
 	return 0;
 }
 
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 6871931..3be3c69 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -69,123 +69,41 @@
 EXPORT_SYMBOL(ide_xfer_verbose);
 
 /**
- *	ide_dma_speed	-	compute DMA speed
- *	@drive: drive
- *	@mode:	modes available
- *
- *	Checks the drive capabilities and returns the speed to use
- *	for the DMA transfer.  Returns 0 if the drive is incapable
- *	of DMA transfers.
- */
- 
-u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
-{
-	struct hd_driveid *id   = drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 ultra_mask, mwdma_mask, swdma_mask;
-	u8 speed = 0;
-
-	if (drive->media != ide_disk && hwif->atapi_dma == 0)
-		return 0;
-
-	/* Capable of UltraDMA modes? */
-	ultra_mask = id->dma_ultra & hwif->ultra_mask;
-
-	if (!(id->field_valid & 4))
-		mode = 0;	/* fallback to MW/SW DMA if no UltraDMA */
-
-	switch (mode) {
-	case 4:
-		if (ultra_mask & 0x40) {
-			speed = XFER_UDMA_6;
-			break;
-		}
-	case 3:
-		if (ultra_mask & 0x20) {
-			speed = XFER_UDMA_5;
-			break;
-		}
-	case 2:
-		if (ultra_mask & 0x10) {
-			speed = XFER_UDMA_4;
-			break;
-		}
-		if (ultra_mask & 0x08) {
-			speed = XFER_UDMA_3;
-			break;
-		}
-	case 1:
-		if (ultra_mask & 0x04) {
-			speed = XFER_UDMA_2;
-			break;
-		}
-		if (ultra_mask & 0x02) {
-			speed = XFER_UDMA_1;
-			break;
-		}
-		if (ultra_mask & 0x01) {
-			speed = XFER_UDMA_0;
-			break;
-		}
-	case 0:
-		mwdma_mask = id->dma_mword & hwif->mwdma_mask;
-
-		if (mwdma_mask & 0x04) {
-			speed = XFER_MW_DMA_2;
-			break;
-		}
-		if (mwdma_mask & 0x02) {
-			speed = XFER_MW_DMA_1;
-			break;
-		}
-		if (mwdma_mask & 0x01) {
-			speed = XFER_MW_DMA_0;
-			break;
-		}
-
-		swdma_mask = id->dma_1word & hwif->swdma_mask;
-
-		if (swdma_mask & 0x04) {
-			speed = XFER_SW_DMA_2;
-			break;
-		}
-		if (swdma_mask & 0x02) {
-			speed = XFER_SW_DMA_1;
-			break;
-		}
-		if (swdma_mask & 0x01) {
-			speed = XFER_SW_DMA_0;
-			break;
-		}
-	}
-
-	return speed;
-}
-EXPORT_SYMBOL(ide_dma_speed);
-
-
-/**
- *	ide_rate_filter		-	return best speed for mode
- *	@mode: modes available
+ *	ide_rate_filter		-	filter transfer mode
+ *	@drive: IDE device
  *	@speed: desired speed
  *
- *	Given the available DMA/UDMA mode this function returns
+ *	Given the available transfer modes this function returns
  *	the best available speed at or below the speed requested.
+ *
+ *	FIXME: filter also PIO/SWDMA/MWDMA modes
  */
 
-u8 ide_rate_filter (u8 mode, u8 speed) 
+u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	static u8 speed_max[] = {
-		XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
-		XFER_UDMA_5, XFER_UDMA_6
-	};
+	ide_hwif_t *hwif = drive->hwif;
+	u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+
+	if (hwif->udma_filter)
+		mask = hwif->udma_filter(drive);
+
+	/*
+	 * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false
+	 * cable warning from eighty_ninty_three(), moving ide_rate_filter()
+	 * calls from ->speedproc to core code will make this hack go away
+	 */
+	if (speed > XFER_UDMA_2) {
+		if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+			mask &= 0x07;
+	}
+
+	if (mask)
+		mode = fls(mask) - 1 + XFER_UDMA_0;
 
 //	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
 
-	/* So that we remember to update this if new modes appear */
-	BUG_ON(mode > 4);
-	return min(speed, speed_max[mode]);
+	return min(speed, mode);
 #else /* !CONFIG_BLK_DEV_IDEDMA */
 	return min(speed, (u8)XFER_PIO_4);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 98410ca..2b8009c 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -42,7 +42,7 @@
 	hw.irq = pnp_irq(dev, 0);
 	hw.dma = NO_DMA;
 
-	index = ide_register_hw(&hw, &hwif);
+	index = ide_register_hw(&hw, 1, &hwif);
 
 	if (index != -1) {
 	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 8f15c23..3cebed7 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1427,6 +1427,9 @@
 				}
 		}
 	}
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			ide_proc_register_port(&ide_hwifs[index]);
 	return 0;
 }
 
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index a9e0b30..d50bd99 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 1997-1998	Mark Lord
  *  Copyright (C) 2003		Red Hat <alan@redhat.com>
+ *
+ *  Some code was moved here from ide.c, see it for original copyrights.
  */
 
 /*
@@ -37,6 +39,8 @@
 
 #include <asm/io.h>
 
+static struct proc_dir_entry *proc_ide_root;
+
 static int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -121,6 +125,265 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+/**
+ *	__ide_add_setting	-	add an ide setting option
+ *	@drive: drive to use
+ *	@name: setting name
+ *	@rw: true if the function is read write
+ *	@data_type: type of data
+ *	@min: range minimum
+ *	@max: range maximum
+ *	@mul_factor: multiplication scale
+ *	@div_factor: divison scale
+ *	@data: private data field
+ *	@set: setting
+ *	@auto_remove: setting auto removal flag
+ *
+ *	Removes the setting named from the device if it is present.
+ *	The function takes the settings_lock to protect against
+ *	parallel changes. This function must not be called from IRQ
+ *	context. Returns 0 on success or -1 on failure.
+ *
+ *	BUGS: This code is seriously over-engineered. There is also
+ *	magic about how the driver specific features are setup. If
+ *	a driver is attached we assume the driver settings are auto
+ *	remove.
+ */
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
+{
+	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
+
+	down(&ide_setting_sem);
+	while ((*p) && strcmp((*p)->name, name) < 0)
+		p = &((*p)->next);
+	if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+		goto abort;
+	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
+		goto abort;
+	strcpy(setting->name, name);
+	setting->rw = rw;
+	setting->data_type = data_type;
+	setting->min = min;
+	setting->max = max;
+	setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;
+	setting->data = data;
+	setting->set = set;
+
+	setting->next = *p;
+	if (auto_remove)
+		setting->auto_remove = 1;
+	*p = setting;
+	up(&ide_setting_sem);
+	return 0;
+abort:
+	up(&ide_setting_sem);
+	kfree(setting);
+	return -1;
+}
+
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+	return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
+EXPORT_SYMBOL(ide_add_setting);
+
+/**
+ *	__ide_remove_setting	-	remove an ide setting option
+ *	@drive: drive to use
+ *	@name: setting name
+ *
+ *	Removes the setting named from the device if it is present.
+ *	The caller must hold the setting semaphore.
+ */
+
+static void __ide_remove_setting (ide_drive_t *drive, char *name)
+{
+	ide_settings_t **p, *setting;
+
+	p = (ide_settings_t **) &drive->settings;
+
+	while ((*p) && strcmp((*p)->name, name))
+		p = &((*p)->next);
+	if ((setting = (*p)) == NULL)
+		return;
+
+	(*p) = setting->next;
+
+	kfree(setting->name);
+	kfree(setting);
+}
+
+/**
+ *	auto_remove_settings	-	remove driver specific settings
+ *	@drive: drive
+ *
+ *	Automatically remove all the driver specific settings for this
+ *	drive. This function may not be called from IRQ context. The
+ *	caller must hold ide_setting_sem.
+ */
+
+static void auto_remove_settings (ide_drive_t *drive)
+{
+	ide_settings_t *setting;
+repeat:
+	setting = drive->settings;
+	while (setting) {
+		if (setting->auto_remove) {
+			__ide_remove_setting(drive, setting->name);
+			goto repeat;
+		}
+		setting = setting->next;
+	}
+}
+
+/**
+ *	ide_find_setting_by_name	-	find a drive specific setting
+ *	@drive: drive to scan
+ *	@name: setting name
+ *
+ *	Scan's the device setting table for a matching entry and returns
+ *	this or NULL if no entry is found. The caller must hold the
+ *	setting semaphore
+ */
+
+static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+{
+	ide_settings_t *setting = drive->settings;
+
+	while (setting) {
+		if (strcmp(setting->name, name) == 0)
+			break;
+		setting = setting->next;
+	}
+	return setting;
+}
+
+/**
+ *	ide_read_setting	-	read an IDE setting
+ *	@drive: drive to read from
+ *	@setting: drive setting
+ *
+ *	Read a drive setting and return the value. The caller
+ *	must hold the ide_setting_sem when making this call.
+ *
+ *	BUGS: the data return and error are the same return value
+ *	so an error -EINVAL and true return of the same value cannot
+ *	be told apart
+ */
+
+static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+{
+	int		val = -EINVAL;
+	unsigned long	flags;
+
+	if ((setting->rw & SETTING_READ)) {
+		spin_lock_irqsave(&ide_lock, flags);
+		switch(setting->data_type) {
+			case TYPE_BYTE:
+				val = *((u8 *) setting->data);
+				break;
+			case TYPE_SHORT:
+				val = *((u16 *) setting->data);
+				break;
+			case TYPE_INT:
+				val = *((u32 *) setting->data);
+				break;
+		}
+		spin_unlock_irqrestore(&ide_lock, flags);
+	}
+	return val;
+}
+
+/**
+ *	ide_write_setting	-	read an IDE setting
+ *	@drive: drive to read from
+ *	@setting: drive setting
+ *	@val: value
+ *
+ *	Write a drive setting if it is possible. The caller
+ *	must hold the ide_setting_sem when making this call.
+ *
+ *	BUGS: the data return and error are the same return value
+ *	so an error -EINVAL and true return of the same value cannot
+ *	be told apart
+ *
+ *	FIXME:  This should be changed to enqueue a special request
+ *	to the driver to change settings, and then wait on a sema for completion.
+ *	The current scheme of polling is kludgy, though safe enough.
+ */
+
+static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (setting->set)
+		return setting->set(drive, val);
+	if (!(setting->rw & SETTING_WRITE))
+		return -EPERM;
+	if (val < setting->min || val > setting->max)
+		return -EINVAL;
+	if (ide_spin_wait_hwgroup(drive))
+		return -EBUSY;
+	switch (setting->data_type) {
+		case TYPE_BYTE:
+			*((u8 *) setting->data) = val;
+			break;
+		case TYPE_SHORT:
+			*((u16 *) setting->data) = val;
+			break;
+		case TYPE_INT:
+			*((u32 *) setting->data) = val;
+			break;
+	}
+	spin_unlock_irq(&ide_lock);
+	return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+	int err;
+
+	if (arg < 0 || arg > 70)
+		return -EINVAL;
+
+	err = ide_wait_cmd(drive,
+			WIN_SETFEATURES, (u8) arg,
+			SETFEATURES_XFER, 0, NULL);
+
+	if (!err && arg) {
+		ide_set_xfer_rate(drive, (u8) arg);
+		ide_driveid_update(drive);
+	}
+	return err;
+}
+
+/**
+ *	ide_add_generic_settings	-	generic ide settings
+ *	@drive: drive being configured
+ *
+ *	Add the generic parts of the system settings to the /proc files.
+ *	The caller must not be holding the ide_setting_sem.
+ */
+
+void ide_add_generic_settings (ide_drive_t *drive)
+{
+/*
+ *			  drive		setting name		read/write access				data type	min	max				mul_factor	div_factor	data pointer			set function
+ */
+	__ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
+	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL,		0);
+	__ide_add_setting(drive,	"nice1",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
+	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
+	__ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL,		0);
+	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
+	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
+	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
+	__ide_add_setting(drive,	"number",		SETTING_RW,					TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
+}
+
 static void proc_ide_settings_warn(void)
 {
 	static int warned = 0;
@@ -399,7 +662,7 @@
 	{ NULL,	0, NULL, NULL }
 };
 
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
+static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
 {
 	struct proc_dir_entry *ent;
 
@@ -415,7 +678,7 @@
 	}
 }
 
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
+static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
 	if (!dir || !p)
 		return;
@@ -425,6 +688,51 @@
 	}
 }
 
+void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+	ide_add_proc_entries(drive->proc, driver->proc, drive);
+}
+
+EXPORT_SYMBOL(ide_proc_register_driver);
+
+/**
+ *	ide_proc_unregister_driver	-	remove driver specific data
+ *	@drive: drive
+ *	@driver: driver
+ *
+ *	Clean up the driver specific /proc files and IDE settings
+ *	for a given drive.
+ *
+ *	Takes ide_setting_sem and ide_lock.
+ *	Caller must hold none of the locks.
+ */
+
+void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+	unsigned long flags;
+
+	ide_remove_proc_entries(drive->proc, driver->proc);
+
+	down(&ide_setting_sem);
+	spin_lock_irqsave(&ide_lock, flags);
+	/*
+	 * ide_setting_sem protects the settings list
+	 * ide_lock protects the use of settings
+	 *
+	 * so we need to hold both, ide_settings_sem because we want to
+	 * modify the settings list, and ide_lock because we cannot take
+	 * a setting out that is being used.
+	 *
+	 * OTOH both ide_{read,write}_setting are only ever used under
+	 * ide_setting_sem.
+	 */
+	auto_remove_settings(drive);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	up(&ide_setting_sem);
+}
+
+EXPORT_SYMBOL(ide_proc_unregister_driver);
+
 static void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
@@ -477,26 +785,24 @@
 	{ NULL,	0, NULL, NULL }
 };
 
-void create_proc_ide_interfaces(void)
+void ide_proc_register_port(ide_hwif_t *hwif)
 {
-	int	h;
+	if (!hwif->present)
+		return;
 
-	for (h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
+	if (!hwif->proc) {
+		hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
 
-		if (!hwif->present)
-			continue;
-		if (!hwif->proc) {
-			hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
-			if (!hwif->proc)
-				return;
-			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
-		}
-		create_proc_ide_drives(hwif);
+		if (!hwif->proc)
+			return;
+
+		ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
 	}
+
+	create_proc_ide_drives(hwif);
 }
 
-EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL_GPL(ide_proc_register_port);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
@@ -507,7 +813,7 @@
 EXPORT_SYMBOL_GPL(ide_pci_create_host_proc);
 #endif
 
-void destroy_proc_ide_interface(ide_hwif_t *hwif)
+void ide_proc_unregister_port(ide_hwif_t *hwif)
 {
 	if (hwif->proc) {
 		destroy_proc_ide_drives(hwif);
@@ -554,11 +860,11 @@
 {
 	struct proc_dir_entry *entry;
 
+	proc_ide_root = proc_mkdir("ide", NULL);
+
 	if (!proc_ide_root)
 		return;
 
-	create_proc_ide_interfaces();
-
 	entry = create_proc_entry("drivers", 0, proc_ide_root);
 	if (entry)
 		entry->proc_fops = &ide_drivers_operations;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 4e59239..e82bfa5 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -4561,28 +4561,33 @@
 	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
+#ifdef CONFIG_IDE_PROC_FS
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
 /*
- *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
+ *			drive	setting name		read/write	data type	min			max			mul_factor			div_factor	data pointer				set function
  */
-	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
-	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
-	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
-	ide_add_setting(drive,	"stage",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1024,				&tape->stage_size,			NULL);
-	ide_add_setting(drive,	"tdsc",		SETTING_RW,	-1,	-1,		TYPE_INT,	IDETAPE_DSC_RW_MIN,	IDETAPE_DSC_RW_MAX,	1000,				HZ,				&tape->best_dsc_rw_frequency,		NULL);
-	ide_add_setting(drive,	"dsc_overlap",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,			1,			1,				1,				&drive->dsc_overlap,			NULL);
-	ide_add_setting(drive,	"pipeline_head_speed_c",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->controlled_pipeline_head_speed,	NULL);
-	ide_add_setting(drive,	"pipeline_head_speed_u",SETTING_READ,	-1,	-1,	TYPE_INT,	0,			0xffff,			1,				1,				&tape->uncontrolled_pipeline_head_speed,	NULL);
-	ide_add_setting(drive,	"avg_speed",	SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->avg_speed,		NULL);
-	ide_add_setting(drive,	"debug_level",SETTING_RW,	-1,	-1,		TYPE_INT,	0,			0xffff,			1,				1,				&tape->debug_level,		NULL);
+	ide_add_setting(drive,	"buffer",		SETTING_READ,	TYPE_SHORT,	0,			0xffff,			1,				2,		&tape->capabilities.buffer_size,	NULL);
+	ide_add_setting(drive,	"pipeline_min",		SETTING_RW,	TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,		&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",		SETTING_RW,	TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,		&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",		SETTING_RW,	TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,		&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_used",	SETTING_READ,	TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,		&tape->nr_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_pending",	SETTING_READ,	TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,		&tape->nr_pending_stages,		NULL);
+	ide_add_setting(drive,	"speed",		SETTING_READ,	TYPE_SHORT,	0,			0xffff,			1,				1,		&tape->capabilities.speed,		NULL);
+	ide_add_setting(drive,	"stage",		SETTING_READ,	TYPE_INT,	0,			0xffff,			1,				1024,		&tape->stage_size,			NULL);
+	ide_add_setting(drive,	"tdsc",			SETTING_RW,	TYPE_INT,	IDETAPE_DSC_RW_MIN,	IDETAPE_DSC_RW_MAX,	1000,				HZ,		&tape->best_dsc_rw_frequency,		NULL);
+	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW,	TYPE_BYTE,	0,			1,			1,				1,		&drive->dsc_overlap,			NULL);
+	ide_add_setting(drive,	"pipeline_head_speed_c",SETTING_READ,	TYPE_INT,	0,			0xffff,			1,				1,		&tape->controlled_pipeline_head_speed,	NULL);
+	ide_add_setting(drive,	"pipeline_head_speed_u",SETTING_READ,	TYPE_INT,	0,			0xffff,			1,				1,		&tape->uncontrolled_pipeline_head_speed,NULL);
+	ide_add_setting(drive,	"avg_speed",		SETTING_READ,	TYPE_INT,	0,			0xffff,			1,				1,		&tape->avg_speed,			NULL);
+	ide_add_setting(drive,	"debug_level",		SETTING_RW,	TYPE_INT,	0,			0xffff,			1,				1,		&tape->debug_level,			NULL);
 }
+#else
+static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *	ide_setup is called to:
@@ -4703,7 +4708,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	ide_unregister_subdriver(drive, tape->driver);
+	ide_proc_unregister_driver(drive, tape->driver);
 
 	ide_unregister_region(tape->disk);
 
@@ -4730,8 +4735,7 @@
 	kfree(tape);
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idetape_read_name
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -4749,11 +4753,6 @@
 	{ "name",	S_IFREG|S_IRUGO,	proc_idetape_read_name,	NULL },
 	{ NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define	idetape_proc	NULL
-
 #endif
 
 static int ide_tape_probe(ide_drive_t *);
@@ -4773,7 +4772,9 @@
 	.end_request		= idetape_end_request,
 	.error			= __ide_error,
 	.abort			= __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
 	.proc			= idetape_proc,
+#endif
 };
 
 /*
@@ -4864,7 +4865,7 @@
 
 	ide_init_disk(g, drive);
 
-	ide_register_subdriver(drive, &idetape_driver);
+	ide_proc_register_driver(drive, &idetape_driver);
 
 	kref_init(&tape->kref);
 
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index ae5bf2b..f2b547f 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -168,12 +168,11 @@
 
 static int idebus_parameter;	/* holds the "idebus=" parameter */
 static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
-static int initializing;	/* set while initializing built-in drivers */
 
 DECLARE_MUTEX(ide_cfg_sem);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
@@ -216,9 +215,6 @@
 	hwif->bus_state	= BUSSTATE_ON;
 
 	hwif->atapi_dma = 0;		/* disable all atapi dma */ 
-	hwif->ultra_mask = 0x80;	/* disable all ultra */
-	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
-	hwif->swdma_mask = 0x80;	/* disable all swdma */
 
 	init_completion(&hwif->gendev_rel_comp);
 
@@ -305,9 +301,7 @@
 #endif
 	}
 #ifdef CONFIG_IDE_ARM
-	initializing = 1;
 	ide_arm_init();
-	initializing = 0;
 #endif
 }
 
@@ -353,10 +347,6 @@
 	return system_bus_speed;
 }
 
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ide_root;
-#endif
-
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
 					    unsigned long addr, int num)
 {
@@ -480,6 +470,7 @@
 
 	hwif->tuneproc			= tmp_hwif->tuneproc;
 	hwif->speedproc			= tmp_hwif->speedproc;
+	hwif->udma_filter		= tmp_hwif->udma_filter;
 	hwif->selectproc		= tmp_hwif->selectproc;
 	hwif->reset_poll		= tmp_hwif->reset_poll;
 	hwif->pre_reset			= tmp_hwif->pre_reset;
@@ -599,7 +590,7 @@
 
 	spin_unlock_irq(&ide_lock);
 
-	destroy_proc_ide_interface(hwif);
+	ide_proc_unregister_port(hwif);
 
 	hwgroup = hwif->hwgroup;
 	/*
@@ -751,6 +742,7 @@
 /**
  *	ide_register_hw_with_fixup	-	register IDE interface
  *	@hw: hardware registers
+ *	@initializing: set while initializing built-in drivers
  *	@hwifp: pointer to returned hwif
  *	@fixup: fixup function
  *
@@ -760,7 +752,9 @@
  *	Returns -1 on error.
  */
 
-int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
+int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
+			       ide_hwif_t **hwifp,
+			       void(*fixup)(ide_hwif_t *hwif))
 {
 	int index, retry = 1;
 	ide_hwif_t *hwif;
@@ -801,7 +795,7 @@
 
 	if (!initializing) {
 		probe_hwif_init_with_fixup(hwif, fixup);
-		create_proc_ide_interfaces();
+		ide_proc_register_port(hwif);
 	}
 
 	if (hwifp)
@@ -812,9 +806,9 @@
 
 EXPORT_SYMBOL(ide_register_hw_with_fixup);
 
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, int initializing, ide_hwif_t **hwifp)
 {
-	return ide_register_hw_with_fixup(hw, hwifp, NULL);
+	return ide_register_hw_with_fixup(hw, initializing, hwifp, NULL);
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -825,205 +819,7 @@
 
 DECLARE_MUTEX(ide_setting_sem);
 
-/**
- *	__ide_add_setting	-	add an ide setting option
- *	@drive: drive to use
- *	@name: setting name
- *	@rw: true if the function is read write
- *	@read_ioctl: function to call on read
- *	@write_ioctl: function to call on write
- *	@data_type: type of data
- *	@min: range minimum
- *	@max: range maximum
- *	@mul_factor: multiplication scale
- *	@div_factor: divison scale
- *	@data: private data field
- *	@set: setting
- *	@auto_remove: setting auto removal flag
- *
- *	Removes the setting named from the device if it is present.
- *	The function takes the settings_lock to protect against 
- *	parallel changes. This function must not be called from IRQ
- *	context. Returns 0 on success or -1 on failure.
- *
- *	BUGS: This code is seriously over-engineered. There is also
- *	magic about how the driver specific features are setup. If
- *	a driver is attached we assume the driver settings are auto
- *	remove.
- */
-
-static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-{
-	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-
-	down(&ide_setting_sem);
-	while ((*p) && strcmp((*p)->name, name) < 0)
-		p = &((*p)->next);
-	if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-		goto abort;
-	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-		goto abort;
-	strcpy(setting->name, name);
-	setting->rw = rw;
-	setting->read_ioctl = read_ioctl;
-	setting->write_ioctl = write_ioctl;
-	setting->data_type = data_type;
-	setting->min = min;
-	setting->max = max;
-	setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;
-	setting->data = data;
-	setting->set = set;
-	
-	setting->next = *p;
-	if (auto_remove)
-		setting->auto_remove = 1;
-	*p = setting;
-	up(&ide_setting_sem);
-	return 0;
-abort:
-	up(&ide_setting_sem);
-	kfree(setting);
-	return -1;
-}
-
-int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-{
-	return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
-}
-
-EXPORT_SYMBOL(ide_add_setting);
-
-/**
- *	__ide_remove_setting	-	remove an ide setting option
- *	@drive: drive to use
- *	@name: setting name
- *
- *	Removes the setting named from the device if it is present.
- *	The caller must hold the setting semaphore.
- */
- 
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
-{
-	ide_settings_t **p, *setting;
-
-	p = (ide_settings_t **) &drive->settings;
-
-	while ((*p) && strcmp((*p)->name, name))
-		p = &((*p)->next);
-	if ((setting = (*p)) == NULL)
-		return;
-
-	(*p) = setting->next;
-	
-	kfree(setting->name);
-	kfree(setting);
-}
-
-/**
- *	ide_find_setting_by_ioctl	-	find a drive specific ioctl
- *	@drive: drive to scan
- *	@cmd: ioctl command to handle
- *
- *	Scan's the device setting table for a matching entry and returns
- *	this or NULL if no entry is found. The caller must hold the
- *	setting semaphore
- */
- 
-static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
-{
-	ide_settings_t *setting = drive->settings;
-
-	while (setting) {
-		if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
-			break;
-		setting = setting->next;
-	}
-	
-	return setting;
-}
-
-/**
- *	ide_find_setting_by_name	-	find a drive specific setting
- *	@drive: drive to scan
- *	@name: setting name
- *
- *	Scan's the device setting table for a matching entry and returns
- *	this or NULL if no entry is found. The caller must hold the
- *	setting semaphore
- */
- 
-ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
-{
-	ide_settings_t *setting = drive->settings;
-
-	while (setting) {
-		if (strcmp(setting->name, name) == 0)
-			break;
-		setting = setting->next;
-	}
-	return setting;
-}
-
-/**
- *	auto_remove_settings	-	remove driver specific settings
- *	@drive: drive
- *
- *	Automatically remove all the driver specific settings for this
- *	drive. This function may not be called from IRQ context. The
- *	caller must hold ide_setting_sem.
- */
- 
-static void auto_remove_settings (ide_drive_t *drive)
-{
-	ide_settings_t *setting;
-repeat:
-	setting = drive->settings;
-	while (setting) {
-		if (setting->auto_remove) {
-			__ide_remove_setting(drive, setting->name);
-			goto repeat;
-		}
-		setting = setting->next;
-	}
-}
-
-/**
- *	ide_read_setting	-	read an IDE setting
- *	@drive: drive to read from
- *	@setting: drive setting
- *
- *	Read a drive setting and return the value. The caller
- *	must hold the ide_setting_sem when making this call.
- *
- *	BUGS: the data return and error are the same return value
- *	so an error -EINVAL and true return of the same value cannot
- *	be told apart
- */
- 
-int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
-{
-	int		val = -EINVAL;
-	unsigned long	flags;
-
-	if ((setting->rw & SETTING_READ)) {
-		spin_lock_irqsave(&ide_lock, flags);
-		switch(setting->data_type) {
-			case TYPE_BYTE:
-				val = *((u8 *) setting->data);
-				break;
-			case TYPE_SHORT:
-				val = *((u16 *) setting->data);
-				break;
-			case TYPE_INT:
-			case TYPE_INTA:
-				val = *((u32 *) setting->data);
-				break;
-		}
-		spin_unlock_irqrestore(&ide_lock, flags);
-	}
-	return val;
-}
+EXPORT_SYMBOL_GPL(ide_setting_sem);
 
 /**
  *	ide_spin_wait_hwgroup	-	wait for group
@@ -1058,61 +854,14 @@
 
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
-/**
- *	ide_write_setting	-	read an IDE setting
- *	@drive: drive to read from
- *	@setting: drive setting
- *	@val: value
- *
- *	Write a drive setting if it is possible. The caller
- *	must hold the ide_setting_sem when making this call.
- *
- *	BUGS: the data return and error are the same return value
- *	so an error -EINVAL and true return of the same value cannot
- *	be told apart
- *
- *	FIXME:  This should be changed to enqueue a special request
- *	to the driver to change settings, and then wait on a sema for completion.
- *	The current scheme of polling is kludgy, though safe enough.
- */
-
-int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
+int set_io_32bit(ide_drive_t *drive, int arg)
 {
-	int i;
-	u32 *p;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if (!(setting->rw & SETTING_WRITE))
+	if (drive->no_io_32bit)
 		return -EPERM;
-	if (val < setting->min || val > setting->max)
-		return -EINVAL;
-	if (setting->set)
-		return setting->set(drive, val);
-	if (ide_spin_wait_hwgroup(drive))
-		return -EBUSY;
-	switch (setting->data_type) {
-		case TYPE_BYTE:
-			*((u8 *) setting->data) = val;
-			break;
-		case TYPE_SHORT:
-			*((u16 *) setting->data) = val;
-			break;
-		case TYPE_INT:
-			*((u32 *) setting->data) = val;
-			break;
-		case TYPE_INTA:
-			p = (u32 *) setting->data;
-			for (i = 0; i < 1 << PARTN_BITS; i++, p++)
-				*p = val;
-			break;
-	}
-	spin_unlock_irq(&ide_lock);
-	return 0;
-}
 
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
+	if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
+		return -EINVAL;
+
 	drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
 	if (HWIF(drive)->chipset == ide_dtc2278)
@@ -1121,12 +870,28 @@
 	return 0;
 }
 
-static int set_using_dma (ide_drive_t *drive, int arg)
+static int set_ksettings(ide_drive_t *drive, int arg)
+{
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
+
+	if (ide_spin_wait_hwgroup(drive))
+		return -EBUSY;
+	drive->keep_settings = arg;
+	spin_unlock_irq(&ide_lock);
+
+	return 0;
+}
+
+int set_using_dma(ide_drive_t *drive, int arg)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	ide_hwif_t *hwif = drive->hwif;
 	int err = -EPERM;
 
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
+
 	if (!drive->id || !(drive->id->capability & 1))
 		goto out;
 
@@ -1159,14 +924,20 @@
 out:
 	return err;
 #else
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
+
 	return -EPERM;
 #endif
 }
 
-static int set_pio_mode (ide_drive_t *drive, int arg)
+int set_pio_mode(ide_drive_t *drive, int arg)
 {
 	struct request rq;
 
+	if (arg < 0 || arg > 255)
+		return -EINVAL;
+
 	if (!HWIF(drive)->tuneproc)
 		return -ENOSYS;
 	if (drive->special.b.set_tune)
@@ -1178,42 +949,20 @@
 	return 0;
 }
 
-static int set_xfer_rate (ide_drive_t *drive, int arg)
+static int set_unmaskirq(ide_drive_t *drive, int arg)
 {
-	int err = ide_wait_cmd(drive,
-			WIN_SETFEATURES, (u8) arg,
-			SETFEATURES_XFER, 0, NULL);
+	if (drive->no_unmask)
+		return -EPERM;
 
-	if (!err && arg) {
-		ide_set_xfer_rate(drive, (u8) arg);
-		ide_driveid_update(drive);
-	}
-	return err;
-}
+	if (arg < 0 || arg > 1)
+		return -EINVAL;
 
-/**
- *	ide_add_generic_settings	-	generic ide settings
- *	@drive: drive being configured
- *
- *	Add the generic parts of the system settings to the /proc files and
- *	ioctls for this IDE device. The caller must not be holding the
- *	ide_setting_sem.
- */
+	if (ide_spin_wait_hwgroup(drive))
+		return -EBUSY;
+	drive->unmask = arg;
+	spin_unlock_irq(&ide_lock);
 
-void ide_add_generic_settings (ide_drive_t *drive)
-{
-/*
- *			  drive		setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
- */
-	__ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit,	0);
-	__ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL,		0);
-	__ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL,		0);
-	__ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode,	0);
-	__ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL,		0);
-	__ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma,	0);
-	__ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL,		0);
-	__ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate,	0);
-	__ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL,		0);
+	return 0;
 }
 
 /**
@@ -1285,27 +1034,23 @@
 int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
 			unsigned int cmd, unsigned long arg)
 {
-	ide_settings_t *setting;
+	unsigned long flags;
 	ide_driver_t *drv;
-	int err = 0;
 	void __user *p = (void __user *)arg;
+	int err = 0, (*setfunc)(ide_drive_t *, int);
+	u8 *val;
 
-	down(&ide_setting_sem);
-	if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
-		if (cmd == setting->read_ioctl) {
-			err = ide_read_setting(drive, setting);
-			up(&ide_setting_sem);
-			return err >= 0 ? put_user(err, (long __user *)arg) : err;
-		} else {
-			if (bdev != bdev->bd_contains)
-				err = -EINVAL;
-			else
-				err = ide_write_setting(drive, setting, arg);
-			up(&ide_setting_sem);
-			return err;
-		}
+	switch (cmd) {
+	case HDIO_GET_32BIT:	    val = &drive->io_32bit;	 goto read_val;
+	case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
+	case HDIO_GET_UNMASKINTR:   val = &drive->unmask;	 goto read_val;
+	case HDIO_GET_DMA:	    val = &drive->using_dma;	 goto read_val;
+	case HDIO_SET_32BIT:	    setfunc = set_io_32bit;	 goto set_val;
+	case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings;	 goto set_val;
+	case HDIO_SET_PIO_MODE:	    setfunc = set_pio_mode;	 goto set_val;
+	case HDIO_SET_UNMASKINTR:   setfunc = set_unmaskirq;	 goto set_val;
+	case HDIO_SET_DMA:	    setfunc = set_using_dma;	 goto set_val;
 	}
-	up(&ide_setting_sem);
 
 	switch (cmd) {
 		case HDIO_OBSOLETE_IDENTITY:
@@ -1359,7 +1104,7 @@
 			ide_init_hwif_ports(&hw, (unsigned long) args[0],
 					    (unsigned long) args[1], NULL);
 			hw.irq = args[2];
-			if (ide_register_hw(&hw, NULL) == -1)
+			if (ide_register_hw(&hw, 0, NULL) == -1)
 				return -EIO;
 			return 0;
 		}
@@ -1434,6 +1179,28 @@
 		default:
 			return -EINVAL;
 	}
+
+read_val:
+	down(&ide_setting_sem);
+	spin_lock_irqsave(&ide_lock, flags);
+	err = *val;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	up(&ide_setting_sem);
+	return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+	if (bdev != bdev->bd_contains)
+		err = -EINVAL;
+	else {
+		if (!capable(CAP_SYS_ADMIN))
+			err = -EACCES;
+		else {
+			down(&ide_setting_sem);
+			err = setfunc(drive, arg);
+			up(&ide_setting_sem);
+		}
+	}
+	return err;
 }
 
 EXPORT_SYMBOL(generic_ide_ioctl);
@@ -1566,13 +1333,13 @@
 		return 1;
 	}
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 	if (!strcmp(s, "ide=reverse")) {
 		ide_scan_direction = 1;
 		printk(" : Enabled support for IDE inverse scan order.\n");
 		return 1;
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
 	if (!strcmp(s, "ide=noacpi")) {
@@ -1832,9 +1599,9 @@
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 	ide_scan_pcibus(ide_scan_direction);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -1892,54 +1659,6 @@
 #endif
 }
 
-void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-#ifdef CONFIG_PROC_FS
-	ide_add_proc_entries(drive->proc, driver->proc, drive);
-#endif
-}
-
-EXPORT_SYMBOL(ide_register_subdriver);
-
-/**
- *	ide_unregister_subdriver	-	disconnect drive from driver
- *	@drive: drive to unplug
- *	@driver: driver
- *
- *	Disconnect a drive from the driver it was attached to and then
- *	clean up the various proc files and other objects attached to it.
- *
- *	Takes ide_setting_sem and ide_lock.
- *	Caller must hold none of the locks.
- */
-
-void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-	unsigned long flags;
-	
-#ifdef CONFIG_PROC_FS
-	ide_remove_proc_entries(drive->proc, driver->proc);
-#endif
-	down(&ide_setting_sem);
-	spin_lock_irqsave(&ide_lock, flags);
-	/*
-	 * ide_setting_sem protects the settings list
-	 * ide_lock protects the use of settings
-	 *
-	 * so we need to hold both, ide_settings_sem because we want to
-	 * modify the settings list, and ide_lock because we cannot take
-	 * a setting out that is being used.
-	 *
-	 * OTOH both ide_{read,write}_setting are only ever used under
-	 * ide_setting_sem.
-	 */
-	auto_remove_settings(drive);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	up(&ide_setting_sem);
-}
-
-EXPORT_SYMBOL(ide_unregister_subdriver);
-
 /*
  * Probe module
  */
@@ -2071,9 +1790,7 @@
 
 	init_ide_data();
 
-#ifdef CONFIG_PROC_FS
-	proc_ide_root = proc_mkdir("ide", NULL);
-#endif
+	proc_ide_create();
 
 #ifdef CONFIG_BLK_DEV_ALI14XX
 	if (probe_ali14xx)
@@ -2096,14 +1813,9 @@
 		(void)qd65xx_init();
 #endif
 
-	initializing = 1;
 	/* Probe for special PCI and other "known" interface chipsets. */
 	probe_for_hwifs();
-	initializing = 0;
 
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
 	return 0;
 }
 
@@ -2143,9 +1855,7 @@
 	pnpide_exit();
 #endif
 
-#ifdef CONFIG_PROC_FS
 	proc_ide_destroy();
-#endif
 
 	bus_unregister(&ide_bus_type);
 }
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 91961aa..df17ed6 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -223,7 +223,8 @@
 	probe_hwif_init(hwif);
 	probe_hwif_init(mate);
 
-	create_proc_ide_interfaces();
+	ide_proc_register_port(hwif);
+	ide_proc_register_port(mate);
 
 	return 0;
 }
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 1ed224a..101aee1 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -213,7 +213,7 @@
 						IRQ_AMIGA_PORTS);
 			}	
 			
-			index = ide_register_hw(&hw, &hwif);
+			index = ide_register_hw(&hw, 1, &hwif);
 			if (index != -1) {
 				hwif->mmio = 1;
 				printk("ide%d: ", index);
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 0219ffa..36a3f0a 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -138,7 +138,8 @@
 	probe_hwif_init(hwif);
 	probe_hwif_init(mate);
 
-	create_proc_ide_interfaces();
+	ide_proc_register_port(hwif);
+	ide_proc_register_port(mate);
 
 	return 0;
 }
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index a9f2cd5..e1e9d9d 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -70,7 +70,7 @@
 			0, 0, NULL,
 //			falconide_iops,
 			IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw, 1, NULL);
 
 	if (index != -1)
 	    printk("ide%d: Falcon IDE interface\n", index);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index dcfadbb..0830a02 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -165,7 +165,7 @@
 //			&gayle_iops,
 			IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw, &hwif);
+	index = ide_register_hw(&hw, 1, &hwif);
 	if (index != -1) {
 	    hwif->mmio = 1;
 	    switch (i) {
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index a283264..c8f353b 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -357,7 +357,8 @@
 	probe_hwif_init(hwif);
 	probe_hwif_init(mate);
 
-	create_proc_ide_interfaces();
+	ide_proc_register_port(hwif);
+	ide_proc_register_port(mate);
 
 	return 0;
 
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index c6522a6..2f3977f 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -153,7 +153,7 @@
     hw.irq = irq;
     hw.chipset = ide_pci;
     hw.dev = &handle->dev;
-    return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
+    return ide_register_hw_with_fixup(&hw, 0, NULL, ide_undecoded_slave);
 }
 
 /*======================================================================
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 4c0079a..c211fc7 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -102,21 +102,21 @@
 				0, 0, macide_ack_intr,
 //				quadra_ide_iops,
 				IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, &hwif);
+		index = ide_register_hw(&hw, 1, &hwif);
 		break;
 	case MAC_IDE_PB:
 		ide_setup_ports(&hw, IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr,
 //				macide_pb_iops,
 				IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, &hwif);
+		index = ide_register_hw(&hw, 1, &hwif);
 		break;
 	case MAC_IDE_BABOON:
 		ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
 				0, 0, NULL,
 //				macide_baboon_iops,
 				IRQ_BABOON_1);
-		index = ide_register_hw(&hw, &hwif);
+		index = ide_register_hw(&hw, 1, &hwif);
 		if (index == -1) break;
 		if (macintosh_config->ident == MAC_MODEL_PB190) {
 
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 74f0812..e628a98 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -142,7 +142,7 @@
 			0, NULL,
 //			m68kide_iops,
 			q40ide_default_irq(pcide_bases[i]));
-	index = ide_register_hw(&hw, &hwif);
+	index = ide_register_hw(&hw, 1, &hwif);
 	// **FIXME**
 	if (index != -1)
 		hwif->mmio = 1;
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 2fb8f50..d1414a7 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -427,7 +427,7 @@
 		qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
 			 &qd6500_tune_drive);
 
-		create_proc_ide_interfaces();
+		ide_proc_register_port(hwif);
 
 		return 1;
 	}
@@ -459,7 +459,7 @@
 				 &qd6580_tune_drive);
 			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
-			create_proc_ide_interfaces();
+			ide_proc_register_port(hwif);
 
 			return 1;
 		} else {
@@ -479,7 +479,8 @@
 				 &qd6580_tune_drive);
 			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
-			create_proc_ide_interfaces();
+			ide_proc_register_port(hwif);
+			ide_proc_register_port(mate);
 
 			return 0; /* no other qd65xx possible */
 		}
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index ca79744..ddc403a 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -160,7 +160,8 @@
 	probe_hwif_init(hwif);
 	probe_hwif_init(mate);
 
-	create_proc_ide_interfaces();
+	ide_proc_register_port(hwif);
+	ide_proc_register_port(mate);
 
 	return 0;
 }
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index d54d9fe..ca95e99 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -760,6 +760,9 @@
 #endif
 
 	probe_hwif_init(hwif);
+
+	ide_proc_register_port(hwif);
+
 	dev_set_drvdata(dev, hwif);
 
 	printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 81fa068..6e935d7 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -129,6 +129,9 @@
 	hwif->irq = hwif->hw.irq;
 
 	probe_hwif_init(hwif);
+
+	ide_proc_register_port(hwif);
+
 	dev_set_drvdata(dev, hwif);
 
 	return 0;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 73bdf64..b173bc6 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -87,38 +87,12 @@
 	return chipset_table->ultra_settings;
 }
 
-static u8 aec62xx_ratemask (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 mode;
-
-	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-			mode = (inb(hwif->channel ?
-				    hwif->mate->dma_status :
-				    hwif->dma_status) & 0x10) ? 4 : 3;
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			mode = 2;
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		default:
-			return 1;
-	}
-
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
 static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u16 d_conf		= 0;
-	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	u8 ultra = 0, ultra_conf = 0;
 	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
 	unsigned long flags;
@@ -145,7 +119,7 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 speed	= ide_rate_filter(drive, xferspeed);
 	u8 unit		= (drive->select.b.unit & 0x01);
 	u8 tmp1 = 0, tmp2 = 0;
 	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -181,17 +155,6 @@
 	}
 }
 
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));	
-
-	if (!(speed))
-		return 0;
-
-	(void) aec62xx_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 {
 	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -200,7 +163,7 @@
 
 static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
 {
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
@@ -261,11 +224,13 @@
 
 static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
 {
+	struct pci_dev *dev = hwif->pci_dev;
+
 	hwif->autodma = 0;
 	hwif->tuneproc = &aec62xx_tune_drive;
 	hwif->speedproc = &aec62xx_tune_chipset;
 
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
 		hwif->serialized = hwif->channel;
 
 	if (hwif->mate)
@@ -277,7 +242,15 @@
 		return;
 	}
 
-	hwif->ultra_mask = 0x7f;
+	hwif->ultra_mask = hwif->cds->udma_mask;
+
+	/* atp865 and atp865r */
+	if (hwif->ultra_mask == 0x3f) {
+		/* check bit 0x10 of DMA status register */
+		if (inb(pci_resource_start(dev, 4) + 2) & 0x10)
+ 			hwif->ultra_mask = 0x7f; /* udma0-6 */
+	}
+
 	hwif->mwdma_mask = 0x07;
 
 	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
@@ -344,6 +317,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 1 */
 		.name		= "AEC6260",
 		.init_setup	= init_setup_aec62xx,
@@ -353,6 +327,7 @@
 		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 2 */
 		.name		= "AEC6260R",
 		.init_setup	= init_setup_aec62xx,
@@ -363,6 +338,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= NEVER_BOARD,
+		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "AEC6X80",
 		.init_setup	= init_setup_aec6x80,
@@ -372,6 +348,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 4 */
 		.name		= "AEC6X80R",
 		.init_setup	= init_setup_aec6x80,
@@ -382,6 +359,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
 
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 946a127..428efda 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -50,7 +50,7 @@
 static u8 chip_is_1543c_e;
 static struct pci_dev *isa_dev;
 
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -278,7 +278,7 @@
 
 	return p-buffer; /* => must be less than 4k! */
 }
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /**
  *	ali15x3_tune_pio	-	set up chipset for PIO mode
@@ -378,74 +378,31 @@
 }
 
 /**
- *	ali15x3_can_ultra	-	check for ultra DMA support
- *	@drive: drive to do the check
+ *	ali_udma_filter		-	compute UDMA mask
+ *	@drive: IDE device
  *
- *	Check the drive and controller revisions. Return 0 if UDMA is
- *	not available, or 1 if UDMA can be used. The actual rules for
- *	the ALi are
+ *	Return available UDMA modes.
+ *
+ *	The actual rules for the ALi are:
  *		No UDMA on revisions <= 0x20
  *		Disk only for revisions < 0xC2
  *		Not WDC drives for revisions < 0xC2
  *
  *	FIXME: WDC ifdef needs to die
  */
- 
-static u8 ali15x3_can_ultra (ide_drive_t *drive)
+
+static u8 ali_udma_filter(ide_drive_t *drive)
 {
+	if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
+		if (drive->media != ide_disk)
+			return 0;
 #ifndef CONFIG_WDC_ALI15X3
-	struct hd_driveid *id	= drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
-
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-/**
- *	ali15x3_ratemask	-	generate DMA mode list
- *	@drive: drive to compute against
- *
- *	Generate a list of the available DMA modes for the drive. 
- *	FIXME: this function contains lots of bogus masking we can dump
- *
- *	Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
- */
- 
-static u8 ali15x3_ratemask (ide_drive_t *drive)
-{
-	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
-
-	if (m5229_revision > 0xC4 && can_ultra) {
-		mode = 4;
-	} else if (m5229_revision == 0xC4 && can_ultra) {
-		mode = 3;
-	} else if (m5229_revision >= 0xC2 && can_ultra) {
-		mode = 2;
-	} else if (can_ultra) {
-		return 1;
-	} else {
-		return 0;
+		if (chip_is_1543c_e && strstr(drive->id->model, "WDC "))
+			return 0;
+#endif
 	}
 
-	/*
-	 *	If the drive sees no suitable cable then UDMA 33
-	 *	is the highest permitted mode
-	 */
-	 
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
+	return drive->hwif->ultra_mask;
 }
 
 /**
@@ -461,7 +418,7 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed		= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	u8 speed1		= speed;
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 tmpbyte		= 0x00;
@@ -511,7 +468,7 @@
  
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!(speed))
 		return 0;
@@ -609,13 +566,13 @@
 
 	isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
 
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 	if (!ali_proc) {
 		ali_proc = 1;
 		bmide_dev = dev;
 		ide_pci_create_host_proc("ali", ali_get_info);
 	}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 	local_irq_save(flags);
 
@@ -771,6 +728,7 @@
 	hwif->autodma = 0;
 	hwif->tuneproc = &ali15x3_tune_drive;
 	hwif->speedproc = &ali15x3_tune_chipset;
+	hwif->udma_filter = &ali_udma_filter;
 
 	/* don't use LBA48 DMA on ALi devices before rev 0xC5 */
 	hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0;
@@ -783,8 +741,17 @@
 
 	hwif->atapi_dma = 1;
 
-	if (m5229_revision > 0x20)
-		hwif->ultra_mask = 0x7f;
+	if (m5229_revision <= 0x20)
+		hwif->ultra_mask = 0x00; /* no udma */
+	else if (m5229_revision < 0xC2)
+		hwif->ultra_mask = 0x07; /* udma0-2 */
+	else if (m5229_revision == 0xC2 || m5229_revision == 0xC3)
+		hwif->ultra_mask = 0x1f; /* udma0-4 */
+	else if (m5229_revision == 0xC4)
+		hwif->ultra_mask = 0x3f; /* udma0-5 */
+	else
+		hwif->ultra_mask = 0x7f; /* udma0-6 */
+
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 7989bdd8..becb1a5 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -92,7 +92,7 @@
  * AMD /proc entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -402,14 +402,14 @@
  * Register /proc/ide/amd74xx entry
  */
 
-#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
         if (!amd74xx_proc) {
                 amd_base = pci_resource_start(dev, 4);
                 bmide_dev = dev;
 		ide_pci_create_host_proc("amd74xx", amd74xx_get_info);
                 amd74xx_proc = 1;
         }
-#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
+#endif /* DISPLAY_AMD_TIMINGS && CONFIG_IDE_PROC_FS */
 
 	return dev->irq;
 }
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 2d48af3..0e52ad7 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -49,22 +49,6 @@
 static DEFINE_SPINLOCK(atiixp_lock);
 
 /**
- *	atiixp_ratemask		-	compute rate mask for ATIIXP IDE
- *	@drive: IDE drive to compute for
- *
- *	Returns the available modes for the ATIIXP IDE controller.
- */
-
-static u8 atiixp_ratemask(ide_drive_t *drive)
-{
-	u8 mode = 3;
-
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
-/**
  *	atiixp_dma_2_pio		-	return the PIO mode matching DMA
  *	@xfer_rate: transfer speed
  *
@@ -189,7 +173,7 @@
 	u16 tmp16;
 	u8 speed, pio;
 
-	speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed);
+	speed = ide_rate_filter(drive, xferspeed);
 
 	spin_lock_irqsave(&atiixp_lock, flags);
 
@@ -223,26 +207,6 @@
 }
 
 /**
- *	atiixp_config_drive_for_dma	-	configure drive for DMA
- *	@drive: IDE drive to configure
- *
- *	Set up a ATIIXP interface channel for the best available speed.
- *	We prefer UDMA if it is available and then MWDMA. If DMA is
- *	not available we switch to PIO and return 0.
- */
-
-static int atiixp_config_drive_for_dma(ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	(void) atiixp_speedproc(drive, speed);
-	return ide_dma_enable(drive);
-}
-
-/**
  *	atiixp_dma_check	-	set up an IDE device
  *	@drive: IDE drive to configure
  *
@@ -256,7 +220,7 @@
 
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && atiixp_config_drive_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive)) {
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 77f51ab..61ea96b 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -74,7 +74,7 @@
 #define UDIDETCR1	0x7B
 #define DTPR1		0x7C
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -165,7 +165,7 @@
 	return p-buffer;	/* => must be less than 4k! */
 }
 
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 static u8 quantize_timing(int timing, int quant)
 {
@@ -292,55 +292,6 @@
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static u8 cmd64x_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 mode = 0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_649:
-			mode = 3;
-			break;
-		case PCI_DEVICE_ID_CMD_648:
-			mode = 2;
-			break;
-		case PCI_DEVICE_ID_CMD_643:
-			return 0;
-
-		case PCI_DEVICE_ID_CMD_646:
-		{
-			unsigned int class_rev	= 0;
-			pci_read_config_dword(dev,
-				PCI_CLASS_REVISION, &class_rev);
-			class_rev &= 0xff;
-		/*
-		 * UltraDMA only supported on PCI646U and PCI646U2, which
-		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
-		 * Actually, although the CMD tech support people won't
-		 * tell me the details, the 0x03 revision cannot support
-		 * UDMA correctly without hardware modifications, and even
-		 * then it only works with Quantum disks due to some
-		 * hold time assumptions in the 646U part which are fixed
-		 * in the 646U2.
-		 *
-		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-		 */
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:
-					return 1;
-				case 0x03:
-				case 0x01:
-				default:
-					return 0;
-			}
-		}
-	}
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
 static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -348,7 +299,7 @@
 	u8 unit			= drive->dn & 0x01;
 	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
 
-	speed = ide_rate_filter(cmd64x_ratemask(drive), speed);
+	speed = ide_rate_filter(drive, speed);
 
 	if (speed >= XFER_SW_DMA_0) {
 		(void) pci_read_config_byte(dev, pciU, &regU);
@@ -403,7 +354,7 @@
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u8 speed	= ide_dma_speed(drive, cmd64x_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!speed)
 		return 0;
@@ -597,7 +548,7 @@
 	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
 #endif /* CONFIG_PPC */
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 
 	cmd_devs[n_cmd_devs++] = dev;
 
@@ -605,7 +556,7 @@
 		cmd64x_proc = 1;
 		ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
 	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
 
 	return 0;
 }
@@ -644,15 +595,24 @@
 
 	hwif->atapi_dma = 1;
 
-	hwif->ultra_mask = 0x3f;
-	hwif->mwdma_mask = 0x07;
+	hwif->ultra_mask = hwif->cds->udma_mask;
 
-	if (dev->device == PCI_DEVICE_ID_CMD_643)
-		hwif->ultra_mask = 0x80;
-	if (dev->device == PCI_DEVICE_ID_CMD_646)
-		hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
-	if (dev->device == PCI_DEVICE_ID_CMD_648)
-		hwif->ultra_mask = 0x1f;
+	/*
+	 * UltraDMA only supported on PCI646U and PCI646U2, which
+	 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+	 * Actually, although the CMD tech support people won't
+	 * tell me the details, the 0x03 revision cannot support
+	 * UDMA correctly without hardware modifications, and even
+	 * then it only works with Quantum disks due to some
+	 * hold time assumptions in the 646U part which are fixed
+	 * in the 646U2.
+	 *
+	 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+	 */
+	if (dev->device == PCI_DEVICE_ID_CMD_646 && class_rev < 5)
+		hwif->ultra_mask = 0x00;
+
+	hwif->mwdma_mask = 0x07;
 
 	hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
 	if (!(hwif->udma_four))
@@ -716,6 +676,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.udma_mask	= 0x00, /* no udma */
 	},{	/* 1 */
 		.name		= "CMD646",
 		.init_setup	= init_setup_cmd646,
@@ -725,6 +686,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 2 */
 		.name		= "CMD648",
 		.init_setup	= init_setup_cmd64x,
@@ -734,6 +696,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "CMD649",
 		.init_setup	= init_setup_cmd64x,
@@ -743,6 +706,7 @@
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
 
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 400859a..3b88a3a 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -213,6 +213,7 @@
  
 static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
+	ide_hwif_t *hwif = NULL, *mate = NULL;
 	ata_index_t index;
 	ide_pci_device_t *d = &cyrix_chipsets[id->driver_data];
 
@@ -239,10 +240,21 @@
 
 	ide_pci_setup_ports(dev, d, 14, &index);
 
-	if((index.b.low & 0xf0) != 0xf0)
-		probe_hwif_init(&ide_hwifs[index.b.low]);
-	if((index.b.high & 0xf0) != 0xf0)
-		probe_hwif_init(&ide_hwifs[index.b.high]);
+	if ((index.b.low & 0xf0) != 0xf0)
+		hwif = &ide_hwifs[index.b.low];
+	if ((index.b.high & 0xf0) != 0xf0)
+		mate = &ide_hwifs[index.b.high];
+
+	if (hwif)
+		probe_hwif_init(hwif);
+	if (mate)
+		probe_hwif_init(mate);
+
+	if (hwif)
+		ide_proc_register_port(hwif);
+	if (mate)
+		ide_proc_register_port(mate);
+
 	return 0;
 }
 
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 45f43ef..41925c4 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -127,20 +127,6 @@
 	}
 }
 
-static u8 cs5535_ratemask(ide_drive_t *drive)
-{
-	/* eighty93 will return 1 if it's 80core and capable of
-	exceeding udma2, 0 otherwise. we need ratemask to set
-	the max speed and if we can > udma2 then we return 2
-	which selects speed_max as udma4 which is the 5535's max
-	speed, and 1 selects udma2 which is the max for 40c */
-	if (!eighty_ninty_three(drive))
-		return 1;
-
-	return 2;
-}
-
-
 /****
  *	cs5535_set_drive         -     Configure the drive to the new speed
  *	@drive: Drive to set up
@@ -151,7 +137,7 @@
  */
 static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
 {
-	speed = ide_rate_filter(cs5535_ratemask(drive), speed);
+	speed = ide_rate_filter(drive, speed);
 	ide_config_drive_speed(drive, speed);
 	cs5535_set_speed(drive, speed);
 
@@ -178,28 +164,13 @@
 	cs5535_set_speed(drive, xferspeed);
 }
 
-static int cs5535_config_drive_for_dma(ide_drive_t *drive)
-{
-	u8 speed;
-
-	speed = ide_dma_speed(drive, cs5535_ratemask(drive));
-
-	/* If no DMA speed was available then let dma_check hit pio */
-	if (!speed) {
-		return 0;
-	}
-
-	cs5535_set_drive(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int cs5535_dma_check(ide_drive_t *drive)
 {
 	u8 speed;
 
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && cs5535_config_drive_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive)) {
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index dd7ec37..46f4a88 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -80,7 +80,7 @@
 	hw.irq = dev->irq;
 	hw.chipset = ide_pci;		/* this enables IRQ sharing */
 
-	rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+	rc = ide_register_hw_with_fixup(&hw, 0, &hwif, ide_undecoded_slave);
 	if (rc < 0) {
 		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
 		pci_disable_device(dev);
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 924eaa3..2c24c3d 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -43,15 +43,10 @@
 
 #define HPT343_DEBUG_DRIVE_INFO		0
 
-static u8 hpt34x_ratemask (ide_drive_t *drive)
-{
-	return 1;
-}
-
 static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+	u8 speed = ide_rate_filter(drive, xferspeed);
 	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
 	u8			hi_speed, lo_speed;
 
@@ -89,29 +84,11 @@
 	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
 }
 
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
-
-	if (!(speed))
-		return 0;
-
-	(void) hpt34x_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
 {
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 #ifndef CONFIG_HPT34X_AUTODMA
 		return -1;
 #else
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index cf9d344..fcbc560 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -514,43 +514,31 @@
 	return 0;
 }
 
-static u8 hpt3xx_ratemask(ide_drive_t *drive)
-{
-	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
-	u8 mode			= info->max_mode;
-
-	if (!eighty_ninty_three(drive) && mode)
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
 /*
  *	Note for the future; the SATA hpt37x we must set
  *	either PIO or UDMA modes 0,4,5
  */
- 
-static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
+
+static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 {
 	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
 	u8 chip_type		= info->chip_type;
-	u8 mode			= hpt3xx_ratemask(drive);
-
-	if (drive->media != ide_disk)
-		return min(speed, (u8)XFER_PIO_4);
+	u8 mode			= info->max_mode;
+	u8 mask;
 
 	switch (mode) {
 		case 0x04:
-			speed = min_t(u8, speed, XFER_UDMA_6);
+			mask = 0x7f;
 			break;
 		case 0x03:
-			speed = min_t(u8, speed, XFER_UDMA_5);
+			mask = 0x3f;
 			if (chip_type >= HPT374)
 				break;
 			if (!check_in_drive_list(drive, bad_ata100_5))
 				goto check_bad_ata33;
 			/* fall thru */
 		case 0x02:
-			speed = min_t(u8, speed, XFER_UDMA_4);
+			mask = 0x1f;
 
 			/*
 			 * CHECK ME, Does this need to be changed to HPT374 ??
@@ -561,13 +549,13 @@
 			    !check_in_drive_list(drive, bad_ata66_4))
 				goto check_bad_ata33;
 
-			speed = min_t(u8, speed, XFER_UDMA_3);
+			mask = 0x0f;
 			if (HPT366_ALLOW_ATA66_3 &&
 			    !check_in_drive_list(drive, bad_ata66_3))
 				goto check_bad_ata33;
 			/* fall thru */
 		case 0x01:
-			speed = min_t(u8, speed, XFER_UDMA_2);
+			mask = 0x07;
 
 		check_bad_ata33:
 			if (chip_type >= HPT370A)
@@ -577,10 +565,10 @@
 			/* fall thru */
 		case 0x00:
 		default:
-			speed = min_t(u8, speed, XFER_MW_DMA_2);
+			mask = 0x00;
 			break;
 	}
-	return speed;
+	return mask;
 }
 
 static u32 get_speed_setting(u8 speed, struct hpt_info *info)
@@ -608,12 +596,19 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev  *dev	= hwif->pci_dev;
 	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  speed		= ide_rate_filter(drive, xferspeed);
 	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
-	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x30070000 :
-				 (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
-	u32 new_itr		= get_speed_setting(speed, info);
 	u32 old_itr		= 0;
+	u32 itr_mask, new_itr;
+
+	/* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
+	if (drive->media != ide_disk)
+		speed = min_t(u8, speed, XFER_PIO_4);
+
+	itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+		  (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+
+	new_itr = get_speed_setting(speed, info);
 
 	/*
 	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
@@ -633,12 +628,19 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev  *dev	= hwif->pci_dev;
 	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  speed		= ide_rate_filter(drive, xferspeed);
 	u8  itr_addr		= 0x40 + (drive->dn * 4);
-	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x303c0000 :
-				 (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
-	u32 new_itr		= get_speed_setting(speed, info);
 	u32 old_itr		= 0;
+	u32 itr_mask, new_itr;
+
+	/* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
+	if (drive->media != ide_disk)
+		speed = min_t(u8, speed, XFER_PIO_4);
+
+	itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+		  (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+
+	new_itr = get_speed_setting(speed, info);
 
 	pci_read_config_dword(dev, itr_addr, &old_itr);
 	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
@@ -667,24 +669,6 @@
 	(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- */
-static int config_chipset_for_dma(ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int hpt3xx_quirkproc(ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
@@ -739,7 +723,7 @@
 {
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
@@ -1271,6 +1255,7 @@
 	hwif->intrproc			= &hpt3xx_intrproc;
 	hwif->maskproc			= &hpt3xx_maskproc;
 	hwif->busproc			= &hpt3xx_busproc;
+	hwif->udma_filter		= &hpt3xx_udma_filter;
 
 	/*
 	 * HPT3xxN chips have some complications:
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 424f00b..c04a026 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -17,22 +17,6 @@
 
 #include <asm/io.h>
 
-/*
- *	it8213_ratemask	-	Compute available modes
- *	@drive: IDE drive
- *
- *	Compute the available speeds for the devices on the interface. This
- *	is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 it8213_ratemask (ide_drive_t *drive)
-{
-	u8 mode	= 4;
-	if (!eighty_ninty_three(drive))
-		mode = min_t(u8, mode, 1);
-	return mode;
-}
-
 /**
  *	it8213_dma_2_pio		-	return the PIO mode matching DMA
  *	@xfer_rate: transfer speed
@@ -145,7 +129,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= 0x40;
-	u8 speed		= ide_rate_filter(it8213_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int a_speed		= 3 << (drive->dn * 4);
 	int u_flag		= 1 << drive->dn;
 	int v_flag		= 0x01 << drive->dn;
@@ -213,25 +197,6 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
-/*
- *	config_chipset_for_dma	-	configure for DMA
- *	@drive: drive to configure
- *
- *	Called by the IDE layer when it wants the timings set up.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	it8213_tune_chipset(drive, speed);
-
-	return ide_dma_enable(drive);
-}
-
 /**
  *	it8213_configure_drive_for_dma	-	set up for DMA transfers
  *	@drive: drive we are going to set up
@@ -246,7 +211,7 @@
 {
 	u8 pio;
 
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 4e12548..442f658 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -229,22 +229,6 @@
 }
 
 /**
- *	it821x_ratemask	-	Compute available modes
- *	@drive: IDE drive
- *
- *	Compute the available speeds for the devices on the interface. This
- *	is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 it821x_ratemask (ide_drive_t *drive)
-{
-	u8 mode	= 4;
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
-/**
  *	it821x_tunepio	-	tune a drive
  *	@drive: drive to tune
  *	@pio: the desired PIO mode
@@ -438,7 +422,7 @@
 
 	ide_hwif_t *hwif	= drive->hwif;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	u8 speed		= ide_rate_filter(it821x_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 
 	switch (speed) {
 	case XFER_PIO_4:
@@ -488,7 +472,7 @@
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u8 speed	= ide_dma_speed(drive, it821x_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (speed == 0)
 		return 0;
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index be4fc96..76ed251 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -22,22 +22,6 @@
 } port_type;
 
 /**
- *	jmicron_ratemask	-	Compute available modes
- *	@drive: IDE drive
- *
- *	Compute the available speeds for the devices on the interface. This
- *	is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 jmicron_ratemask(ide_drive_t *drive)
-{
-	u8 mode	= 4;
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
-/**
  *	ata66_jmicron		-	Cable check
  *	@hwif: IDE port
  *
@@ -129,32 +113,12 @@
 
 static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-
-	u8 speed		= ide_rate_filter(jmicron_ratemask(drive), xferspeed);
+	u8 speed = ide_rate_filter(drive, xferspeed);
 
 	return ide_config_drive_speed(drive, speed);
 }
 
 /**
- *	config_chipset_for_dma	-	configure for DMA
- *	@drive: drive to configure
- *
- *	As the JMicron snoops for timings all we actually need to do is
- *	make sure we don't set an invalid mode.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	u8 speed	= ide_dma_speed(drive, jmicron_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	jmicron_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
-/**
  *	jmicron_configure_drive_for_dma	-	set up for DMA transfers
  *	@drive: drive we are going to set up
  *
@@ -164,7 +128,7 @@
 
 static int jmicron_config_drive_for_dma (ide_drive_t *drive)
 {
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	config_jmicron_chipset_for_pio(drive, 1);
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 2cdd629..65b1e12 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -37,8 +37,6 @@
 #include <asm/pci-bridge.h>
 #endif
 
-#define PDC202_DEBUG_CABLE	0
-
 #undef DEBUG
 
 #ifdef DEBUG
@@ -82,16 +80,6 @@
 	return mode;
 }
 
-static u8 pdcnew_ratemask(ide_drive_t *drive)
-{
-	u8 mode = max_dma_rate(HWIF(drive)->pci_dev);
-
-	if (!eighty_ninty_three(drive))
-		mode = min_t(u8, mode, 1);
-
-	return	mode;
-}
-
 /**
  * get_indexed_reg - Get indexed register
  * @hwif: for the port address
@@ -164,7 +152,7 @@
 	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
 	int			err;
 
-	speed = ide_rate_filter(pdcnew_ratemask(drive), speed);
+	speed = ide_rate_filter(drive, speed);
 
 	/*
 	 * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
@@ -244,17 +232,8 @@
 {
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
-	u8 ultra_66		= (id->dma_ultra & 0x0078) ? 1 : 0;
-	u8 cable		= pdcnew_cable_detect(hwif);
 	u8 speed;
 
-	if (ultra_66 && cable) {
-		printk(KERN_WARNING "Warning: %s channel "
-		       "requires an 80-pin cable for operation.\n",
-		       hwif->channel ? "Secondary" : "Primary");
-		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
-	}
-
 	if (id->capability & 4) {
 		/*
 		 * Set IORDY_EN & PREFETCH_EN (this seems to have
@@ -267,7 +246,7 @@
 		set_indexed_reg(hwif, 0x13 + adj, tmp | 0x03);
 	}
 
-	speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+	speed = ide_max_dma_mode(drive);
 
 	if (!speed)
 		return 0;
@@ -543,7 +522,8 @@
 	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
 	hwif->atapi_dma  = 1;
-	hwif->ultra_mask = 0x7f;
+
+	hwif->ultra_mask = hwif->cds->udma_mask;
 	hwif->mwdma_mask = 0x07;
 
 	hwif->err_stops_fifo = 1;
@@ -556,11 +536,6 @@
 	if (!noautodma)
 		hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-
-#if PDC202_DEBUG_CABLE
-	printk(KERN_DEBUG "%s: %s-pin cable\n",
-		hwif->name, hwif->udma_four ? "80" : "40");
-#endif /* PDC202_DEBUG_CABLE */
 }
 
 static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d)
@@ -619,6 +594,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 1 */
 		.name		= "PDC20269",
 		.init_setup	= init_setup_pdcnew,
@@ -627,6 +603,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 2 */
 		.name		= "PDC20270",
 		.init_setup	= init_setup_pdc20270,
@@ -635,6 +612,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 3 */
 		.name		= "PDC20271",
 		.init_setup	= init_setup_pdcnew,
@@ -643,6 +621,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 4 */
 		.name		= "PDC20275",
 		.init_setup	= init_setup_pdcnew,
@@ -651,6 +630,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 5 */
 		.name		= "PDC20276",
 		.init_setup	= init_setup_pdc20276,
@@ -659,6 +639,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 6 */
 		.name		= "PDC20277",
 		.init_setup	= init_setup_pdcnew,
@@ -667,6 +648,7 @@
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.udma_mask	= 0x7f, /* udma0-6*/
 	}
 };
 
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index a7a639f..7146fe3 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -46,7 +46,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define PDC202_DEBUG_CABLE		0
 #define PDC202XX_DEBUG_DRIVE_INFO	0
 
 static const char *pdc_quirk_drives[] = {
@@ -101,35 +100,12 @@
 #define	MC1		0x02	/* DMA"C" timing */
 #define	MC0		0x01	/* DMA"C" timing */
 
-static u8 pdc202xx_ratemask (ide_drive_t *drive)
-{
-	u8 mode;
-
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			mode = 3;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			mode = 2;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			return 1;
-		default:
-			return 0;
-	}
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
 static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 drive_pci		= 0x60 + (drive->dn << 2);
-	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 
 	u32			drive_conf;
 	u8			AP, BP, CP, DP;
@@ -261,20 +237,7 @@
 	u32 drive_conf		= 0;
 	u8 drive_pci		= 0x60 + (drive->dn << 2);
 	u8 test1 = 0, test2 = 0, speed = -1;
-	u8 AP = 0, cable = 0;
-
-	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-	if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
-		cable = pdc202xx_old_cable_detect(hwif);
-	else
-		ultra_66 = 0;
-
-	if (ultra_66 && cable) {
-		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
-		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
-	}
+	u8 AP = 0;
 
 	if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
 		pdc_old_disable_66MHz_clock(drive->hwif);
@@ -308,7 +271,7 @@
 	if (drive->media == ide_disk)	/* PREFETCH_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+	speed = ide_max_dma_mode(drive);
 
 	if (!(speed)) {
 		/* restore original pci-config space */
@@ -478,7 +441,7 @@
 
 	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
-	hwif->ultra_mask = 0x3f;
+	hwif->ultra_mask = hwif->cds->udma_mask;
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 	hwif->atapi_dma = 1;
@@ -500,10 +463,6 @@
 	if (!noautodma)
 		hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-#if PDC202_DEBUG_CABLE
-	printk(KERN_DEBUG "%s: %s-pin cable\n",
-		hwif->name, hwif->udma_four ? "80" : "40");
-#endif /* PDC202_DEBUG_CABLE */	
 }
 
 static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
@@ -587,6 +546,7 @@
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 16,
+		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 1 */
 		.name		= "PDC20262",
 		.init_setup	= init_setup_pdc202ata4,
@@ -597,6 +557,7 @@
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 2 */
 		.name		= "PDC20263",
 		.init_setup	= init_setup_pdc202ata4,
@@ -607,6 +568,7 @@
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "PDC20265",
 		.init_setup	= init_setup_pdc20265,
@@ -617,6 +579,7 @@
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 4 */
 		.name		= "PDC20267",
 		.init_setup	= init_setup_pdc202xx,
@@ -627,6 +590,7 @@
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
 
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 061d300..8b219dd 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -106,68 +106,6 @@
 static int no_piix_dma;
 
 /**
- *	piix_ratemask		-	compute rate mask for PIIX IDE
- *	@drive: IDE drive to compute for
- *
- *	Returns the available modes for the PIIX IDE controller.
- */
- 
-static u8 piix_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 mode;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801EB_1:
-			mode = 3;
-			break;
-		/* UDMA 100 capable */
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-		case PCI_DEVICE_ID_INTEL_82801CA_10:
-		case PCI_DEVICE_ID_INTEL_82801CA_11:
-		case PCI_DEVICE_ID_INTEL_82801E_11:
-		case PCI_DEVICE_ID_INTEL_82801DB_1:
-		case PCI_DEVICE_ID_INTEL_82801DB_10:
-		case PCI_DEVICE_ID_INTEL_82801DB_11:
-		case PCI_DEVICE_ID_INTEL_82801EB_11:
-		case PCI_DEVICE_ID_INTEL_ESB_2:
-		case PCI_DEVICE_ID_INTEL_ICH6_19:
-		case PCI_DEVICE_ID_INTEL_ICH7_21:
-		case PCI_DEVICE_ID_INTEL_ESB2_18:
-		case PCI_DEVICE_ID_INTEL_ICH8_6:
-			mode = 3;
-			break;
-		/* UDMA 66 capable */
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-			mode = 2;
-			break;
-		/* UDMA 33 capable */
-		case PCI_DEVICE_ID_INTEL_82371AB:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-			return 1;
-		/* Non UDMA capable (MWDMA2) */
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		case PCI_DEVICE_ID_INTEL_82371MX:
-		default:
-			return 0;
-	}
-	
-	/*
-	 *	If we are UDMA66 capable fall back to UDMA33 
-	 *	if the drive cannot see an 80pin cable.
-	 */
-	if (!eighty_ninty_three(drive))
-		mode = min_t(u8, mode, 1);
-	return mode;
-}
-
-/**
  *	piix_dma_2_pio		-	return the PIO mode matching DMA
  *	@xfer_rate: transfer speed
  *
@@ -301,7 +239,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
-	u8 speed		= ide_rate_filter(piix_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int a_speed		= 3 << (drive->dn * 4);
 	int u_flag		= 1 << drive->dn;
 	int v_flag		= 0x01 << drive->dn;
@@ -366,30 +304,6 @@
 }
 
 /**
- *	piix_config_drive_for_dma	-	configure drive for DMA
- *	@drive: IDE drive to configure
- *
- *	Set up a PIIX interface channel for the best available speed.
- *	We prefer UDMA if it is available and then MWDMA.  If DMA is
- *	not available we switch to PIO and return 0.
- */
- 
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
-
-	/*
-	 * If no DMA speed was available or the chipset has DMA bugs
-	 * then disable DMA and use PIO
-	 */
-	if (!speed)
-		return 0;
-
-	(void) piix_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
-/**
  *	piix_config_drive_xfer_rate	-	set up an IDE device
  *	@drive: IDE drive to configure
  *
@@ -401,7 +315,7 @@
 {
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && piix_config_drive_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
@@ -524,26 +438,14 @@
 		hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
 
 	hwif->atapi_dma = 1;
-	hwif->ultra_mask = 0x3f;
+
+	hwif->ultra_mask = hwif->cds->udma_mask;
 	hwif->mwdma_mask = 0x06;
 	hwif->swdma_mask = 0x04;
 
-	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			hwif->ultra_mask = 0x80;
-			break;
-		case PCI_DEVICE_ID_INTEL_82371AB:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-			hwif->ultra_mask = 0x07;
-			break;
-		default:
-			if (!hwif->udma_four)
-				hwif->udma_four = piix_cable_detect(hwif);
-			break;
+	if (hwif->ultra_mask & 0x78) {
+		if (!hwif->udma_four)
+			hwif->udma_four = piix_cable_detect(hwif);
 	}
 
 	if (no_piix_dma)
@@ -557,7 +459,7 @@
 	hwif->drives[0].autodma = hwif->autodma;
 }
 
-#define DECLARE_PIIX_DEV(name_str) \
+#define DECLARE_PIIX_DEV(name_str, udma) \
 	{						\
 		.name		= name_str,		\
 		.init_chipset	= init_chipset_piix,	\
@@ -566,11 +468,12 @@
 		.autodma	= AUTODMA,		\
 		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
 		.bootable	= ON_BOARD,		\
+		.udma_mask	= udma,			\
 	}
 
 static ide_pci_device_t piix_pci_info[] __devinitdata = {
-	/*  0 */ DECLARE_PIIX_DEV("PIIXa"),
-	/*  1 */ DECLARE_PIIX_DEV("PIIXb"),
+	/*  0 */ DECLARE_PIIX_DEV("PIIXa", 0x00),	/* no udma */
+	/*  1 */ DECLARE_PIIX_DEV("PIIXb", 0x00),	/* no udma */
 
 	/*  2 */
 	{	/*
@@ -587,28 +490,28 @@
 		.flags		= IDEPCI_FLAG_ISA_PORTS
 	},
 
-	/*  3 */ DECLARE_PIIX_DEV("PIIX3"),
-	/*  4 */ DECLARE_PIIX_DEV("PIIX4"),
-	/*  5 */ DECLARE_PIIX_DEV("ICH0"),
-	/*  6 */ DECLARE_PIIX_DEV("PIIX4"),
-	/*  7 */ DECLARE_PIIX_DEV("ICH"),
-	/*  8 */ DECLARE_PIIX_DEV("PIIX4"),
-	/*  9 */ DECLARE_PIIX_DEV("PIIX4"),
-	/* 10 */ DECLARE_PIIX_DEV("ICH2"),
-	/* 11 */ DECLARE_PIIX_DEV("ICH2M"),
-	/* 12 */ DECLARE_PIIX_DEV("ICH3M"),
-	/* 13 */ DECLARE_PIIX_DEV("ICH3"),
-	/* 14 */ DECLARE_PIIX_DEV("ICH4"),
-	/* 15 */ DECLARE_PIIX_DEV("ICH5"),
-	/* 16 */ DECLARE_PIIX_DEV("C-ICH"),
-	/* 17 */ DECLARE_PIIX_DEV("ICH4"),
-	/* 18 */ DECLARE_PIIX_DEV("ICH5-SATA"),
-	/* 19 */ DECLARE_PIIX_DEV("ICH5"),
-	/* 20 */ DECLARE_PIIX_DEV("ICH6"),
-	/* 21 */ DECLARE_PIIX_DEV("ICH7"),
-	/* 22 */ DECLARE_PIIX_DEV("ICH4"),
-	/* 23 */ DECLARE_PIIX_DEV("ESB2"),
-	/* 24 */ DECLARE_PIIX_DEV("ICH8M"),
+	/*  3 */ DECLARE_PIIX_DEV("PIIX3", 0x00),	/* no udma */
+	/*  4 */ DECLARE_PIIX_DEV("PIIX4", 0x07),	/* udma0-2 */
+	/*  5 */ DECLARE_PIIX_DEV("ICH0",  0x07),	/* udma0-2 */
+	/*  6 */ DECLARE_PIIX_DEV("PIIX4", 0x07),	/* udma0-2 */
+	/*  7 */ DECLARE_PIIX_DEV("ICH",   0x1f),	/* udma0-4 */
+	/*  8 */ DECLARE_PIIX_DEV("PIIX4", 0x1f),	/* udma0-4 */
+	/*  9 */ DECLARE_PIIX_DEV("PIIX4", 0x07),	/* udma0-2 */
+	/* 10 */ DECLARE_PIIX_DEV("ICH2",  0x3f),	/* udma0-5 */
+	/* 11 */ DECLARE_PIIX_DEV("ICH2M", 0x3f),	/* udma0-5 */
+	/* 12 */ DECLARE_PIIX_DEV("ICH3M", 0x3f),	/* udma0-5 */
+	/* 13 */ DECLARE_PIIX_DEV("ICH3",  0x3f),	/* udma0-5 */
+	/* 14 */ DECLARE_PIIX_DEV("ICH4",  0x3f),	/* udma0-5 */
+	/* 15 */ DECLARE_PIIX_DEV("ICH5",  0x3f),	/* udma0-5 */
+	/* 16 */ DECLARE_PIIX_DEV("C-ICH", 0x3f),	/* udma0-5 */
+	/* 17 */ DECLARE_PIIX_DEV("ICH4",  0x3f),	/* udma0-5 */
+	/* 18 */ DECLARE_PIIX_DEV("ICH5-SATA", 0x3f),	/* udma0-5 */
+	/* 19 */ DECLARE_PIIX_DEV("ICH5",  0x3f),	/* udma0-5 */
+	/* 20 */ DECLARE_PIIX_DEV("ICH6",  0x3f),	/* udma0-5 */
+	/* 21 */ DECLARE_PIIX_DEV("ICH7",  0x3f),	/* udma0-5 */
+	/* 22 */ DECLARE_PIIX_DEV("ICH4",  0x3f),	/* udma0-5 */
+	/* 23 */ DECLARE_PIIX_DEV("ESB2",  0x3f),	/* udma0-5 */
+	/* 24 */ DECLARE_PIIX_DEV("ICH8M", 0x3f),	/* udma0-5 */
 };
 
 /**
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index f84bf79..cbf9363 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -190,23 +190,6 @@
 }
 
 /**
- *	scc_ratemask	-	Compute available modes
- *	@drive: IDE drive
- *
- *	Compute the available speeds for the devices on the interface.
- *	Enforce UDMA33 as a limit if there is no 80pin cable present.
- */
-
-static u8 scc_ratemask(ide_drive_t *drive)
-{
-	u8 mode = 4;
-
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
-
-/**
  *	scc_tuneproc	-	tune a drive PIO mode
  *	@drive: drive to tune
  *	@mode_wanted: the target operating mode
@@ -273,7 +256,7 @@
 static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	u8 speed = ide_rate_filter(scc_ratemask(drive), xferspeed);
+	u8 speed = ide_rate_filter(drive, xferspeed);
 	struct scc_ports *ports = ide_get_hwifdata(hwif);
 	unsigned long ctl_base = ports->ctl;
 	unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -347,7 +330,7 @@
 
 static int scc_config_chipset_for_dma(ide_drive_t *drive)
 {
-	u8 speed = ide_dma_speed(drive, scc_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!speed)
 		return 0;
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index dbcd37a..2fa6d92 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -65,16 +65,16 @@
 	return 0;
 }
 
-static u8 svwks_ratemask (ide_drive_t *drive)
+static u8 svwks_udma_filter(ide_drive_t *drive)
 {
 	struct pci_dev *dev     = HWIF(drive)->pci_dev;
-	u8 mode = 0;
+	u8 mask = 0;
 
 	if (!svwks_revision)
 		pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
 	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
-		return 2;
+		return 0x1f;
 	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
 		u32 reg = 0;
 		if (isa_dev)
@@ -86,25 +86,31 @@
 		if(drive->media == ide_disk)
 			return 0;
 		/* Check the OSB4 DMA33 enable bit */
-		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+		return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0;
 	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
-		return 1;
+		return 0x07;
 	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
-		u8 btr = 0;
+		u8 btr = 0, mode;
 		pci_read_config_byte(dev, 0x5A, &btr);
 		mode = btr & 0x3;
-		if (!eighty_ninty_three(drive))
-			mode = min(mode, (u8)1);
+
 		/* If someone decides to do UDMA133 on CSB5 the same
 		   issue will bite so be inclusive */
 		if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
 			mode = 2;
+
+		switch(mode) {
+		case 2:	 mask = 0x1f; break;
+		case 1:	 mask = 0x07; break;
+		default: mask = 0x00; break;
+		}
 	}
 	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
 	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
 	    (!(PCI_FUNC(dev->devfn) & 1)))
-		mode = 2;
-	return mode;
+		mask = 0x1f;
+
+	return mask;
 }
 
 static u8 svwks_csb_check (struct pci_dev *dev)
@@ -141,7 +147,7 @@
 	if (xferspeed == 255)	/* PIO auto-tuning */
 		speed = XFER_PIO_0 + pio;
 	else
-		speed = ide_rate_filter(svwks_ratemask(drive), xferspeed);
+		speed = ide_rate_filter(drive, xferspeed);
 
 	/* If we are about to put a disk into UDMA mode we screwed up.
 	   Our code assumes we never _ever_ do this on an OSB4 */
@@ -304,7 +310,7 @@
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!(speed))
 		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
@@ -500,6 +506,7 @@
 
 	hwif->tuneproc = &svwks_tune_drive;
 	hwif->speedproc = &svwks_tune_chipset;
+	hwif->udma_filter = &svwks_udma_filter;
 
 	hwif->atapi_dma = 1;
 
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index fd09b29..d3185e2 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -692,7 +692,7 @@
 		return -EIO;
 
 	/* Create /proc/ide entries */
-	create_proc_ide_interfaces();
+	ide_proc_register_port(hwif);
 
 	return 0;
 }
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index c0188de..d09e74c 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -122,45 +122,41 @@
 }
 
 /**
- *	siimage_ratemask	-	Compute available modes
- *	@drive: IDE drive
+ *	sil_udma_filter		-	compute UDMA mask
+ *	@drive: IDE device
  *
- *	Compute the available speeds for the devices on the interface.
+ *	Compute the available UDMA speeds for the device on the interface.
+ *
  *	For the CMD680 this depends on the clocking mode (scsc), for the
- *	SI3312 SATA controller life is a bit simpler. Enforce UDMA33
- *	as a limit if there is no 80pin cable present.
+ *	SI3112 SATA controller life is a bit simpler.
  */
- 
-static byte siimage_ratemask (ide_drive_t *drive)
+
+static u8 sil_udma_filter(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 mode	= 0, scsc = 0;
+	ide_hwif_t *hwif = drive->hwif;
 	unsigned long base = (unsigned long) hwif->hwif_data;
+	u8 mask = 0, scsc = 0;
 
 	if (hwif->mmio)
 		scsc = hwif->INB(base + 0x4A);
 	else
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-	if(is_sata(hwif))
-	{
-		if(strstr(drive->id->model, "Maxtor"))
-			return 3;
-		return 4;
+	if (is_sata(hwif)) {
+		mask = strstr(drive->id->model, "Maxtor") ? 0x3f : 0x7f;
+		goto out;
 	}
-	
+
 	if ((scsc & 0x30) == 0x10)	/* 133 */
-		mode = 4;
+		mask = 0x7f;
 	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
-		mode = 4;
+		mask = 0x7f;
 	else if ((scsc & 0x30) == 0x00)	/* 100 */
-		mode = 3;
+		mask = 0x3f;
 	else 	/* Disabled ? */
 		BUG();
-
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
+out:
+	return mask;
 }
 
 /**
@@ -306,7 +302,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	u16 ultra = 0, multi	= 0;
 	u8 mode = 0, unit	= drive->select.b.unit;
-	u8 speed		= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	unsigned long base	= (unsigned long)hwif->hwif_data;
 	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
 				    ((hwif->mmio) ? 0xF4 : 0x84) :
@@ -389,7 +385,7 @@
  
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
+	u8 speed = ide_max_dma_mode(drive);
 
 	if (!speed)
 		return 0;
@@ -831,7 +827,7 @@
 
 	/*
 	 *	Now set up the hw. We have to do this ourselves as
-	 *	the MMIO layout isnt the same as the the standard port
+	 *	the MMIO layout isnt the same as the standard port
 	 *	based I/O
 	 */
 
@@ -989,6 +985,7 @@
 	hwif->tuneproc	= &siimage_tuneproc;
 	hwif->reset_poll = &siimage_reset_poll;
 	hwif->pre_reset = &siimage_pre_reset;
+	hwif->udma_filter = &sil_udma_filter;
 
 	if(is_sata(hwif)) {
 		static int first = 1;
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 2ba0669..2bde1b9 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -191,7 +191,7 @@
 	"ATA 133 (1st gen)", "ATA 133 (2nd gen)"
 };
 
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -426,17 +426,7 @@
 
 	return len > count ? count : len;
 }
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static u8 sis5513_ratemask (ide_drive_t *drive)
-{
-	u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
-	u8 mode = rates[chipset_family];
-
-	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
-	return mode;
-}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /*
  * Configuration functions
@@ -563,7 +553,7 @@
 	u8 drive_pci, reg, speed;
 	u32 regdw;
 
-	speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+	speed = ide_rate_filter(drive, xferspeed);
 
 	/* See config_art_rwp_pio for drive pci config registers */
 	drive_pci = 0x40;
@@ -648,32 +638,13 @@
 	(void) config_chipset_for_pio(drive, pio);
 }
 
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
-	       drive->dn, drive->id->dma_ultra);
-#endif
-
-	if (!(speed))
-		return 0;
-
-	sis5513_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int sis5513_config_xfer_rate(ide_drive_t *drive)
 {
 	config_art_rwp_pio(drive, 5);
 
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
@@ -826,7 +797,7 @@
 				break;
 		}
 
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 		if (!sis_proc) {
 			sis_proc = 1;
 			bmide_dev = dev;
@@ -858,6 +829,8 @@
 
 static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
 {
+	u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
+
 	hwif->autodma = 0;
 
 	if (!hwif->irq)
@@ -873,7 +846,8 @@
 	}
 
 	hwif->atapi_dma = 1;
-	hwif->ultra_mask = 0x7f;
+
+	hwif->ultra_mask = udma_rates[chipset_family];
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 852ccb3..c40f291 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -21,15 +21,6 @@
 
 #include <asm/io.h>
 
-static u8 slc90e66_ratemask (ide_drive_t *drive)
-{
-	u8 mode	= 2;
-
-	if (!eighty_ninty_three(drive))
-		mode = min_t(u8, mode, 1);
-	return mode;
-}
-
 static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
 	switch(xfer_rate) {
 		case XFER_UDMA_4:
@@ -122,7 +113,7 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
-	u8 speed	= ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
 	int u_speed = 0, u_flag = 1 << drive->dn;
 	u16			reg4042, reg44, reg48, reg4a;
@@ -169,22 +160,11 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	(void) slc90e66_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
 {
 	drive->init_speed = 0;
 
-	if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 0b6d81d..cee619b 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -13,18 +13,13 @@
 #include <linux/pci.h>
 #include <linux/ide.h>
 
-static inline u8 tc86c001_ratemask(ide_drive_t *drive)
-{
-	return eighty_ninty_three(drive) ? 2 : 1;
-}
-
 static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	unsigned long scr_port	= hwif->config_data + (drive->dn ? 0x02 : 0x00);
 	u16 mode, scr		= hwif->INW(scr_port);
 
-	speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+	speed = ide_rate_filter(drive, speed);
 
 	switch (speed) {
 		case XFER_UDMA_4:	mode = 0x00c0; break;
@@ -172,20 +167,9 @@
 	return 0;
 }
 
-static int config_chipset_for_dma(ide_drive_t *drive)
-{
-	u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
-
-	if (!speed)
-		return 0;
-
-	(void) tc86c001_tune_chipset(drive, speed);
-	return ide_dma_enable(drive);
-}
-
 static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
 {
-	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	if (ide_use_fast_pio(drive))
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 5e06179..35e8c61 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -48,7 +48,7 @@
 	u16 timing = 0;
 	u32 triflex_timings = 0;
 	u8 unit = (drive->select.b.unit & 0x01);
-	u8 speed = ide_rate_filter(0, xferspeed);
+	u8 speed = ide_rate_filter(drive, xferspeed);
 	
 	pci_read_config_dword(dev, channel_offset, &triflex_timings);
 	
@@ -100,20 +100,9 @@
 	(void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
 }
 
-static int triflex_config_drive_for_dma(ide_drive_t *drive)
-{
-	int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
-
-	if (!speed)
-		return 0;
-
-	(void) triflex_tune_chipset(drive, speed);
-	 return ide_dma_enable(drive);
-}
-
 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
 {
-	if (ide_use_dma(drive) && triflex_config_drive_for_dma(drive))
+	if (ide_tune_dma(drive))
 		return 0;
 
 	triflex_tune_drive(drive, 255);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index a49ebe4..45fc36f 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1276,6 +1276,8 @@
 	/* We probe the hwif now */
 	probe_hwif_init(hwif);
 
+	ide_proc_register_port(hwif);
+
 	return 0;
 }
 
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 118fb32..67035ba 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -702,6 +702,7 @@
 
 int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
 {
+	ide_hwif_t *hwif = NULL, *mate = NULL;
 	ata_index_t index_list;
 	int ret;
 
@@ -710,11 +711,19 @@
 		goto out;
 
 	if ((index_list.b.low & 0xf0) != 0xf0)
-		probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.low], d->fixup);
+		hwif = &ide_hwifs[index_list.b.low];
 	if ((index_list.b.high & 0xf0) != 0xf0)
-		probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.high], d->fixup);
+		mate = &ide_hwifs[index_list.b.high];
 
-	create_proc_ide_interfaces();
+	if (hwif)
+		probe_hwif_init_with_fixup(hwif, d->fixup);
+	if (mate)
+		probe_hwif_init_with_fixup(mate, d->fixup);
+
+	if (hwif)
+		ide_proc_register_port(hwif);
+	if (mate)
+		ide_proc_register_port(mate);
 out:
 	return ret;
 }
@@ -748,13 +757,22 @@
 		}
 	}
 
-	create_proc_ide_interfaces();
+	for (i = 0; i < 2; i++) {
+		u8 idx[2] = { index_list[i].b.low, index_list[i].b.high };
+		int j;
+
+		for (j = 0; j < 2; j++) {
+			if ((idx[j] & 0xf0) != 0xf0)
+				ide_proc_register_port(ide_hwifs + idx[j]);
+		}
+	}
 out:
 	return ret;
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
 
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 /*
  *	Module interfaces
  */
@@ -861,3 +879,4 @@
 		__pci_register_driver(d, d->driver.owner, d->driver.mod_name);
 	}
 }
+#endif
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 6a1a057..835937e 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -1702,7 +1702,7 @@
 			generation = get_hpsb_generation(host);
 
 			/* If we get a reset before we are done waiting, then
-			 * start the the waiting over again */
+			 * start the waiting over again */
 			if (generation != g)
 				g = generation, i = 0;
 		}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index f284be1..82dda2f 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -745,6 +745,7 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
 		if(!create_comp_task(pool, cpu)) {
 			ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
@@ -752,24 +753,29 @@
 		}
 		break;
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
 		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
 		kthread_bind(cct->task, any_online_cpu(cpu_online_map));
 		destroy_comp_task(pool, cpu);
 		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
 		cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
 		kthread_bind(cct->task, cpu);
 		wake_up_process(cct->task);
 		break;
 	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
 		break;
 	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
 		destroy_comp_task(pool, cpu);
 		take_over_work(pool, cpu);
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index c921d6c..c92f9d7 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -17,7 +17,7 @@
 	help
 	  If you say Y here, the kernelcapi driver can make verbose traces
 	  of CAPI messages. This feature can be enabled/disabled via IOCTL for
-	  every controler (default disabled).
+	  every controller (default disabled).
 	  This will increase the size of the kernelcapi module by 20 KB.
 	  If unsure, say Y.
 
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index c8e1c35..a126301 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -138,8 +138,6 @@
 	char			bchars[6];		/* for request 0x19 */
 };
 
-struct usb_bc_state {};
-
 static inline unsigned tiocm_to_gigaset(unsigned state)
 {
 	return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
@@ -579,25 +577,21 @@
 
 static int gigaset_freebcshw(struct bc_state *bcs)
 {
-	if (!bcs->hw.usb)
-		return 0;
-	//FIXME
-	kfree(bcs->hw.usb);
+	/* unused */
 	return 1;
 }
 
 /* Initialize the b-channel structure */
 static int gigaset_initbcshw(struct bc_state *bcs)
 {
-	bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL);
-	if (!bcs->hw.usb)
-		return 0;
-
+	/* unused */
+	bcs->hw.usb = NULL;
 	return 1;
 }
 
 static void gigaset_reinitbcshw(struct bc_state *bcs)
 {
+	/* nothing to do for M10x */
 }
 
 static void gigaset_freecshw(struct cardstate *cs)
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
index af3eb9e..85784a7 100644
--- a/drivers/isdn/hardware/eicon/divasync.h
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -216,7 +216,7 @@
 #define SERIAL_HOOK_RING 0x85
 #define SERIAL_HOOK_DETACH 0x8f
  unsigned char Flags;           /* function refinements   */
- /* parameters passed by the the ATTACH request      */
+ /* parameters passed by the ATTACH request      */
  SERIAL_INT_CB InterruptHandler; /* called on each interrupt  */
  SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
  void   *HandlerContext; /* context for both handlers */
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 99e70d4..1f18f19 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1217,11 +1217,11 @@
 	/* aux = output, reset off */
 	write_usb(hfc, HFCUSB_CIRM, 0x10);
 
-	/* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+	/* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
 	write_usb(hfc, HFCUSB_USB_SIZE,
 		  (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
 
-	/* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+	/* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
 	write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
 
 	/* enable PCM/GCI master mode */
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index c8b8cfa..0d89260 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -2889,7 +2889,9 @@
 
 	switch (val) {
 	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
 		       cpu);
 		decache_vcpus_on_cpu(cpu);
@@ -2897,6 +2899,7 @@
 					 NULL, 0, 1);
 		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
 		       cpu);
 		smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 1d49d2a..677c993 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -1,5 +1,5 @@
 /*
- * drivers/leds/h1940-leds.c
+ * drivers/leds/leds-h1940.c
  * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a32c91e..58926da 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -237,7 +237,7 @@
 	tristate "Support for Apple XServe front panel LEDs"
 	depends on PPC_PMAC
 	help
-	  This driver procides some support to control the front panel
+	  This driver provides some support to control the front panel
           blue LEDs "vu-meter" of the XServer macs.
 
 endif # MACINTOSH_DRIVERS
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 0acf2f7..c803d2b 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -563,7 +563,7 @@
 				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
 				hw.irq = bay->cd_irq;
 				hw.chipset = ide_pmac;
-				bay->cd_index = ide_register_hw(&hw, NULL);
+				bay->cd_index = ide_register_hw(&hw, 0, NULL);
 				pmu_resume();
 			}
 			if (bay->cd_index == -1) {
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
index da862e4..67b8e94 100644
--- a/drivers/mca/mca-bus.c
+++ b/drivers/mca/mca-bus.c
@@ -47,19 +47,25 @@
 {
 	struct mca_device *mca_dev = to_mca_device (dev);
 	struct mca_driver *mca_drv = to_mca_driver (drv);
-	const short *mca_ids = mca_drv->id_table;
-	int i;
+	const unsigned short *mca_ids = mca_drv->id_table;
+	int i = 0;
 
-	if (!mca_ids)
-		return 0;
-
-	for(i = 0; mca_ids[i]; i++) {
-		if (mca_ids[i] == mca_dev->pos_id) {
-			mca_dev->index = i;
-			return 1;
+	if (mca_ids) {
+		for(i = 0; mca_ids[i]; i++) {
+			if (mca_ids[i] == mca_dev->pos_id) {
+				mca_dev->index = i;
+				return 1;
+			}
 		}
 	}
-
+	/* If the integrated id is present, treat it as though it were an
+	 * additional id in the id_table (it can't be because by definition,
+	 * integrated id's overflow a short */
+	if (mca_drv->integrated_id && mca_dev->pos_id ==
+	    mca_drv->integrated_id) {
+		mca_dev->index = i;
+		return 1;
+	}
 	return 0;
 }
 
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
index 2223466..32cd39b 100644
--- a/drivers/mca/mca-driver.c
+++ b/drivers/mca/mca-driver.c
@@ -36,12 +36,25 @@
 		mca_drv->driver.bus = &mca_bus_type;
 		if ((r = driver_register(&mca_drv->driver)) < 0)
 			return r;
+		mca_drv->integrated_id = 0;
 	}
 
 	return 0;
 }
 EXPORT_SYMBOL(mca_register_driver);
 
+int mca_register_driver_integrated(struct mca_driver *mca_driver,
+				   int integrated_id)
+{
+	int r = mca_register_driver(mca_driver);
+
+	if (!r)
+		mca_driver->integrated_id = integrated_id;
+
+	return r;
+}
+EXPORT_SYMBOL(mca_register_driver_integrated);
+
 void mca_unregister_driver(struct mca_driver *mca_drv)
 {
 	if (MCA_bus)
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 4540ade..7df934d 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -262,6 +262,15 @@
 	---help---
 	  Multipath support for EMC CX/AX series hardware.
 
+config DM_DELAY
+	tristate "I/O delaying target (EXPERIMENTAL)"
+	depends on BLK_DEV_DM && EXPERIMENTAL
+	---help---
+	A target that delays reads and/or writes and can send
+	them to different devices.  Useful for testing.
+
+	If unsure, say N.
+
 endmenu
 
 endif
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 34957a6..3875408 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_BLK_DEV_MD)	+= md-mod.o
 obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
+obj-$(CONFIG_DM_DELAY)		+= dm-delay.o
 obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o
 obj-$(CONFIG_DM_MULTIPATH_EMC)	+= dm-emc.o
 obj-$(CONFIG_DM_SNAPSHOT)	+= dm-snapshot.o
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index da43496..c6be888 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -8,17 +8,43 @@
 #define DM_BIO_LIST_H
 
 #include <linux/bio.h>
+#include <linux/prefetch.h>
 
 struct bio_list {
 	struct bio *head;
 	struct bio *tail;
 };
 
+static inline int bio_list_empty(const struct bio_list *bl)
+{
+	return bl->head == NULL;
+}
+
+#define BIO_LIST_INIT { .head = NULL, .tail = NULL }
+
+#define BIO_LIST(bl) \
+	struct bio_list bl = BIO_LIST_INIT
+
 static inline void bio_list_init(struct bio_list *bl)
 {
 	bl->head = bl->tail = NULL;
 }
 
+#define bio_list_for_each(bio, bl) \
+	for (bio = (bl)->head; bio && ({ prefetch(bio->bi_next); 1; }); \
+	     bio = bio->bi_next)
+
+static inline unsigned bio_list_size(const struct bio_list *bl)
+{
+	unsigned sz = 0;
+	struct bio *bio;
+
+	bio_list_for_each(bio, bl)
+		sz++;
+
+	return sz;
+}
+
 static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
 {
 	bio->bi_next = NULL;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index d812123..7b0fcfc 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -33,7 +33,6 @@
 struct crypt_io {
 	struct dm_target *target;
 	struct bio *base_bio;
-	struct bio *first_clone;
 	struct work_struct work;
 	atomic_t pending;
 	int error;
@@ -107,6 +106,8 @@
 
 static struct kmem_cache *_crypt_io_pool;
 
+static void clone_init(struct crypt_io *, struct bio *);
+
 /*
  * Different IV generation algorithms:
  *
@@ -120,6 +121,9 @@
  * benbi: the 64-bit "big-endian 'narrow block'-count", starting at 1
  *        (needed for LRW-32-AES and possible other narrow block modes)
  *
+ * null: the initial vector is always zero.  Provides compatibility with
+ *       obsolete loop_fish2 devices.  Do not use for new devices.
+ *
  * plumb: unimplemented, see:
  * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
  */
@@ -256,6 +260,13 @@
 	return 0;
 }
 
+static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+	memset(iv, 0, cc->iv_size);
+
+	return 0;
+}
+
 static struct crypt_iv_operations crypt_iv_plain_ops = {
 	.generator = crypt_iv_plain_gen
 };
@@ -272,6 +283,10 @@
 	.generator = crypt_iv_benbi_gen
 };
 
+static struct crypt_iv_operations crypt_iv_null_ops = {
+	.generator = crypt_iv_null_gen
+};
+
 static int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
@@ -378,36 +393,21 @@
  * This should never violate the device limitations
  * May return a smaller bio when running out of pages
  */
-static struct bio *
-crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
-                   struct bio *base_bio, unsigned int *bio_vec_idx)
+static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int size)
 {
+	struct crypt_config *cc = io->target->private;
 	struct bio *clone;
 	unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
 	unsigned int i;
 
-	if (base_bio) {
-		clone = bio_alloc_bioset(GFP_NOIO, base_bio->bi_max_vecs, cc->bs);
-		__bio_clone(clone, base_bio);
-	} else
-		clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
-
+	clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
 	if (!clone)
 		return NULL;
 
-	clone->bi_destructor = dm_crypt_bio_destructor;
+	clone_init(io, clone);
 
-	/* if the last bio was not complete, continue where that one ended */
-	clone->bi_idx = *bio_vec_idx;
-	clone->bi_vcnt = *bio_vec_idx;
-	clone->bi_size = 0;
-	clone->bi_flags &= ~(1 << BIO_SEG_VALID);
-
-	/* clone->bi_idx pages have already been allocated */
-	size -= clone->bi_idx * PAGE_SIZE;
-
-	for (i = clone->bi_idx; i < nr_iovecs; i++) {
+	for (i = 0; i < nr_iovecs; i++) {
 		struct bio_vec *bv = bio_iovec_idx(clone, i);
 
 		bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
@@ -419,7 +419,7 @@
 		 * return a partially allocated bio, the caller will then try
 		 * to allocate additional bios while submitting this partial bio
 		 */
-		if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
+		if (i == (MIN_BIO_PAGES - 1))
 			gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
 
 		bv->bv_offset = 0;
@@ -438,12 +438,6 @@
 		return NULL;
 	}
 
-	/*
-	 * Remember the last bio_vec allocated to be able
-	 * to correctly continue after the splitting.
-	 */
-	*bio_vec_idx = clone->bi_vcnt;
-
 	return clone;
 }
 
@@ -495,9 +489,6 @@
 	if (!atomic_dec_and_test(&io->pending))
 		return;
 
-	if (io->first_clone)
-		bio_put(io->first_clone);
-
 	bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
 
 	mempool_free(io, cc->io_pool);
@@ -562,6 +553,7 @@
 	clone->bi_end_io  = crypt_endio;
 	clone->bi_bdev    = cc->dev->bdev;
 	clone->bi_rw      = io->base_bio->bi_rw;
+	clone->bi_destructor = dm_crypt_bio_destructor;
 }
 
 static void process_read(struct crypt_io *io)
@@ -585,7 +577,6 @@
 	}
 
 	clone_init(io, clone);
-	clone->bi_destructor = dm_crypt_bio_destructor;
 	clone->bi_idx = 0;
 	clone->bi_vcnt = bio_segments(base_bio);
 	clone->bi_size = base_bio->bi_size;
@@ -604,7 +595,6 @@
 	struct convert_context ctx;
 	unsigned remaining = base_bio->bi_size;
 	sector_t sector = base_bio->bi_sector - io->target->begin;
-	unsigned bvec_idx = 0;
 
 	atomic_inc(&io->pending);
 
@@ -615,14 +605,14 @@
 	 * so repeat the whole process until all the data can be handled.
 	 */
 	while (remaining) {
-		clone = crypt_alloc_buffer(cc, base_bio->bi_size,
-					   io->first_clone, &bvec_idx);
+		clone = crypt_alloc_buffer(io, remaining);
 		if (unlikely(!clone)) {
 			dec_pending(io, -ENOMEM);
 			return;
 		}
 
 		ctx.bio_out = clone;
+		ctx.idx_out = 0;
 
 		if (unlikely(crypt_convert(cc, &ctx) < 0)) {
 			crypt_free_buffer_pages(cc, clone, clone->bi_size);
@@ -631,31 +621,26 @@
 			return;
 		}
 
-		clone_init(io, clone);
+		/* crypt_convert should have filled the clone bio */
+		BUG_ON(ctx.idx_out < clone->bi_vcnt);
+
 		clone->bi_sector = cc->start + sector;
-
-		if (!io->first_clone) {
-			/*
-			 * hold a reference to the first clone, because it
-			 * holds the bio_vec array and that can't be freed
-			 * before all other clones are released
-			 */
-			bio_get(clone);
-			io->first_clone = clone;
-		}
-
 		remaining -= clone->bi_size;
 		sector += bio_sectors(clone);
 
-		/* prevent bio_put of first_clone */
+		/* Grab another reference to the io struct
+		 * before we kick off the request */
 		if (remaining)
 			atomic_inc(&io->pending);
 
 		generic_make_request(clone);
 
+		/* Do not reference clone after this - it
+		 * may be gone already. */
+
 		/* out of memory -> run queues */
 		if (remaining)
-			congestion_wait(bio_data_dir(clone), HZ/100);
+			congestion_wait(WRITE, HZ/100);
 	}
 }
 
@@ -832,6 +817,8 @@
 		cc->iv_gen_ops = &crypt_iv_essiv_ops;
 	else if (strcmp(ivmode, "benbi") == 0)
 		cc->iv_gen_ops = &crypt_iv_benbi_ops;
+	else if (strcmp(ivmode, "null") == 0)
+		cc->iv_gen_ops = &crypt_iv_null_ops;
 	else {
 		ti->error = "Invalid IV mode";
 		goto bad2;
@@ -954,10 +941,12 @@
 	struct crypt_config *cc = ti->private;
 	struct crypt_io *io;
 
+	if (bio_barrier(bio))
+		return -EOPNOTSUPP;
+
 	io = mempool_alloc(cc->io_pool, GFP_NOIO);
 	io->target = ti;
 	io->base_bio = bio;
-	io->first_clone = NULL;
 	io->error = io->post_process = 0;
 	atomic_set(&io->pending, 0);
 	kcryptd_queue_io(io);
@@ -1057,7 +1046,7 @@
 
 static struct target_type crypt_target = {
 	.name   = "crypt",
-	.version= {1, 3, 0},
+	.version= {1, 5, 0},
 	.module = THIS_MODULE,
 	.ctr    = crypt_ctr,
 	.dtr    = crypt_dtr,
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
new file mode 100644
index 0000000..52c7cf9
--- /dev/null
+++ b/drivers/md/dm-delay.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2005-2007 Red Hat GmbH
+ *
+ * A target that delays reads and/or writes and can send
+ * them to different devices.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+
+#include "dm.h"
+#include "dm-bio-list.h"
+
+#define DM_MSG_PREFIX "delay"
+
+struct delay_c {
+	struct timer_list delay_timer;
+	struct semaphore timer_lock;
+	struct work_struct flush_expired_bios;
+	struct list_head delayed_bios;
+	atomic_t may_delay;
+	mempool_t *delayed_pool;
+
+	struct dm_dev *dev_read;
+	sector_t start_read;
+	unsigned read_delay;
+	unsigned reads;
+
+	struct dm_dev *dev_write;
+	sector_t start_write;
+	unsigned write_delay;
+	unsigned writes;
+};
+
+struct delay_info {
+	struct delay_c *context;
+	struct list_head list;
+	struct bio *bio;
+	unsigned long expires;
+};
+
+static DEFINE_MUTEX(delayed_bios_lock);
+
+static struct workqueue_struct *kdelayd_wq;
+static struct kmem_cache *delayed_cache;
+
+static void handle_delayed_timer(unsigned long data)
+{
+	struct delay_c *dc = (struct delay_c *)data;
+
+	queue_work(kdelayd_wq, &dc->flush_expired_bios);
+}
+
+static void queue_timeout(struct delay_c *dc, unsigned long expires)
+{
+	down(&dc->timer_lock);
+
+	if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
+		mod_timer(&dc->delay_timer, expires);
+
+	up(&dc->timer_lock);
+}
+
+static void flush_bios(struct bio *bio)
+{
+	struct bio *n;
+
+	while (bio) {
+		n = bio->bi_next;
+		bio->bi_next = NULL;
+		generic_make_request(bio);
+		bio = n;
+	}
+}
+
+static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
+{
+	struct delay_info *delayed, *next;
+	unsigned long next_expires = 0;
+	int start_timer = 0;
+	BIO_LIST(flush_bios);
+
+	mutex_lock(&delayed_bios_lock);
+	list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
+		if (flush_all || time_after_eq(jiffies, delayed->expires)) {
+			list_del(&delayed->list);
+			bio_list_add(&flush_bios, delayed->bio);
+			if ((bio_data_dir(delayed->bio) == WRITE))
+				delayed->context->writes--;
+			else
+				delayed->context->reads--;
+			mempool_free(delayed, dc->delayed_pool);
+			continue;
+		}
+
+		if (!start_timer) {
+			start_timer = 1;
+			next_expires = delayed->expires;
+		} else
+			next_expires = min(next_expires, delayed->expires);
+	}
+
+	mutex_unlock(&delayed_bios_lock);
+
+	if (start_timer)
+		queue_timeout(dc, next_expires);
+
+	return bio_list_get(&flush_bios);
+}
+
+static void flush_expired_bios(struct work_struct *work)
+{
+	struct delay_c *dc;
+
+	dc = container_of(work, struct delay_c, flush_expired_bios);
+	flush_bios(flush_delayed_bios(dc, 0));
+}
+
+/*
+ * Mapping parameters:
+ *    <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+ *
+ * With separate write parameters, the first set is only used for reads.
+ * Delays are specified in milliseconds.
+ */
+static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	struct delay_c *dc;
+	unsigned long long tmpll;
+
+	if (argc != 3 && argc != 6) {
+		ti->error = "requires exactly 3 or 6 arguments";
+		return -EINVAL;
+	}
+
+	dc = kmalloc(sizeof(*dc), GFP_KERNEL);
+	if (!dc) {
+		ti->error = "Cannot allocate context";
+		return -ENOMEM;
+	}
+
+	dc->reads = dc->writes = 0;
+
+	if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+		ti->error = "Invalid device sector";
+		goto bad;
+	}
+	dc->start_read = tmpll;
+
+	if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+		ti->error = "Invalid delay";
+		goto bad;
+	}
+
+	if (dm_get_device(ti, argv[0], dc->start_read, ti->len,
+			  dm_table_get_mode(ti->table), &dc->dev_read)) {
+		ti->error = "Device lookup failed";
+		goto bad;
+	}
+
+	if (argc == 3) {
+		dc->dev_write = NULL;
+		goto out;
+	}
+
+	if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+		ti->error = "Invalid write device sector";
+		goto bad;
+	}
+	dc->start_write = tmpll;
+
+	if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+		ti->error = "Invalid write delay";
+		goto bad;
+	}
+
+	if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
+			  dm_table_get_mode(ti->table), &dc->dev_write)) {
+		ti->error = "Write device lookup failed";
+		dm_put_device(ti, dc->dev_read);
+		goto bad;
+	}
+
+out:
+	dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
+	if (!dc->delayed_pool) {
+		DMERR("Couldn't create delayed bio pool.");
+		goto bad;
+	}
+
+	init_timer(&dc->delay_timer);
+	dc->delay_timer.function = handle_delayed_timer;
+	dc->delay_timer.data = (unsigned long)dc;
+
+	INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
+	INIT_LIST_HEAD(&dc->delayed_bios);
+	init_MUTEX(&dc->timer_lock);
+	atomic_set(&dc->may_delay, 1);
+
+	ti->private = dc;
+	return 0;
+
+bad:
+	kfree(dc);
+	return -EINVAL;
+}
+
+static void delay_dtr(struct dm_target *ti)
+{
+	struct delay_c *dc = ti->private;
+
+	flush_workqueue(kdelayd_wq);
+
+	dm_put_device(ti, dc->dev_read);
+
+	if (dc->dev_write)
+		dm_put_device(ti, dc->dev_write);
+
+	mempool_destroy(dc->delayed_pool);
+	kfree(dc);
+}
+
+static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
+{
+	struct delay_info *delayed;
+	unsigned long expires = 0;
+
+	if (!delay || !atomic_read(&dc->may_delay))
+		return 1;
+
+	delayed = mempool_alloc(dc->delayed_pool, GFP_NOIO);
+
+	delayed->context = dc;
+	delayed->bio = bio;
+	delayed->expires = expires = jiffies + (delay * HZ / 1000);
+
+	mutex_lock(&delayed_bios_lock);
+
+	if (bio_data_dir(bio) == WRITE)
+		dc->writes++;
+	else
+		dc->reads++;
+
+	list_add_tail(&delayed->list, &dc->delayed_bios);
+
+	mutex_unlock(&delayed_bios_lock);
+
+	queue_timeout(dc, expires);
+
+	return 0;
+}
+
+static void delay_presuspend(struct dm_target *ti)
+{
+	struct delay_c *dc = ti->private;
+
+	atomic_set(&dc->may_delay, 0);
+	del_timer_sync(&dc->delay_timer);
+	flush_bios(flush_delayed_bios(dc, 1));
+}
+
+static void delay_resume(struct dm_target *ti)
+{
+	struct delay_c *dc = ti->private;
+
+	atomic_set(&dc->may_delay, 1);
+}
+
+static int delay_map(struct dm_target *ti, struct bio *bio,
+		     union map_info *map_context)
+{
+	struct delay_c *dc = ti->private;
+
+	if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
+		bio->bi_bdev = dc->dev_write->bdev;
+		bio->bi_sector = dc->start_write +
+				 (bio->bi_sector - ti->begin);
+
+		return delay_bio(dc, dc->write_delay, bio);
+	}
+
+	bio->bi_bdev = dc->dev_read->bdev;
+	bio->bi_sector = dc->start_read +
+			 (bio->bi_sector - ti->begin);
+
+	return delay_bio(dc, dc->read_delay, bio);
+}
+
+static int delay_status(struct dm_target *ti, status_type_t type,
+			char *result, unsigned maxlen)
+{
+	struct delay_c *dc = ti->private;
+	int sz = 0;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		DMEMIT("%u %u", dc->reads, dc->writes);
+		break;
+
+	case STATUSTYPE_TABLE:
+		DMEMIT("%s %llu %u", dc->dev_read->name,
+		       (unsigned long long) dc->start_read,
+		       dc->read_delay);
+		if (dc->dev_write)
+			DMEMIT("%s %llu %u", dc->dev_write->name,
+			       (unsigned long long) dc->start_write,
+			       dc->write_delay);
+		break;
+	}
+
+	return 0;
+}
+
+static struct target_type delay_target = {
+	.name	     = "delay",
+	.version     = {1, 0, 2},
+	.module      = THIS_MODULE,
+	.ctr	     = delay_ctr,
+	.dtr	     = delay_dtr,
+	.map	     = delay_map,
+	.presuspend  = delay_presuspend,
+	.resume	     = delay_resume,
+	.status	     = delay_status,
+};
+
+static int __init dm_delay_init(void)
+{
+	int r = -ENOMEM;
+
+	kdelayd_wq = create_workqueue("kdelayd");
+	if (!kdelayd_wq) {
+		DMERR("Couldn't start kdelayd");
+		goto bad_queue;
+	}
+
+	delayed_cache = kmem_cache_create("dm-delay",
+					  sizeof(struct delay_info),
+					  __alignof__(struct delay_info),
+					  0, NULL, NULL);
+	if (!delayed_cache) {
+		DMERR("Couldn't create delayed bio cache.");
+		goto bad_memcache;
+	}
+
+	r = dm_register_target(&delay_target);
+	if (r < 0) {
+		DMERR("register failed %d", r);
+		goto bad_register;
+	}
+
+	return 0;
+
+bad_register:
+	kmem_cache_destroy(delayed_cache);
+bad_memcache:
+	destroy_workqueue(kdelayd_wq);
+bad_queue:
+	return r;
+}
+
+static void __exit dm_delay_exit(void)
+{
+	int r = dm_unregister_target(&delay_target);
+
+	if (r < 0)
+		DMERR("unregister failed %d", r);
+
+	kmem_cache_destroy(delayed_cache);
+	destroy_workqueue(kdelayd_wq);
+}
+
+/* Module hooks */
+module_init(dm_delay_init);
+module_exit(dm_delay_exit);
+
+MODULE_DESCRIPTION(DM_NAME " delay target");
+MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 99cdffa..07e0a0c 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -1,7 +1,8 @@
 /*
- * dm-snapshot.c
+ * dm-exception-store.c
  *
  * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  */
@@ -123,6 +124,7 @@
 	atomic_t pending_count;
 	uint32_t callback_count;
 	struct commit_callback *callbacks;
+	struct dm_io_client *io_client;
 };
 
 static inline unsigned int sectors_to_pages(unsigned int sectors)
@@ -159,14 +161,20 @@
  */
 static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
 {
-	struct io_region where;
-	unsigned long bits;
+	struct io_region where = {
+		.bdev = ps->snap->cow->bdev,
+		.sector = ps->snap->chunk_size * chunk,
+		.count = ps->snap->chunk_size,
+	};
+	struct dm_io_request io_req = {
+		.bi_rw = rw,
+		.mem.type = DM_IO_VMA,
+		.mem.ptr.vma = ps->area,
+		.client = ps->io_client,
+		.notify.fn = NULL,
+	};
 
-	where.bdev = ps->snap->cow->bdev;
-	where.sector = ps->snap->chunk_size * chunk;
-	where.count = ps->snap->chunk_size;
-
-	return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
+	return dm_io(&io_req, 1, &where, NULL);
 }
 
 /*
@@ -213,17 +221,18 @@
 		chunk_size_supplied = 0;
 	}
 
-	r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
-	if (r)
-		return r;
+	ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+							     chunk_size));
+	if (IS_ERR(ps->io_client))
+		return PTR_ERR(ps->io_client);
 
 	r = alloc_area(ps);
 	if (r)
-		goto bad1;
+		return r;
 
 	r = chunk_io(ps, 0, READ);
 	if (r)
-		goto bad2;
+		goto bad;
 
 	dh = (struct disk_header *) ps->area;
 
@@ -235,7 +244,7 @@
 	if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
 		DMWARN("Invalid or corrupt snapshot");
 		r = -ENXIO;
-		goto bad2;
+		goto bad;
 	}
 
 	*new_snapshot = 0;
@@ -252,27 +261,22 @@
 	       (unsigned long long)ps->snap->chunk_size);
 
 	/* We had a bogus chunk_size. Fix stuff up. */
-	dm_io_put(sectors_to_pages(ps->snap->chunk_size));
 	free_area(ps);
 
 	ps->snap->chunk_size = chunk_size;
 	ps->snap->chunk_mask = chunk_size - 1;
 	ps->snap->chunk_shift = ffs(chunk_size) - 1;
 
-	r = dm_io_get(sectors_to_pages(chunk_size));
+	r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+				ps->io_client);
 	if (r)
 		return r;
 
 	r = alloc_area(ps);
-	if (r)
-		goto bad1;
+	return r;
 
-	return 0;
-
-bad2:
+bad:
 	free_area(ps);
-bad1:
-	dm_io_put(sectors_to_pages(ps->snap->chunk_size));
 	return r;
 }
 
@@ -405,7 +409,7 @@
 {
 	struct pstore *ps = get_info(store);
 
-	dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+	dm_io_client_destroy(ps->io_client);
 	vfree(ps->callbacks);
 	free_area(ps);
 	kfree(ps);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index 32eff28..e0832e6 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -16,6 +16,7 @@
 struct hw_handler_type;
 struct hw_handler {
 	struct hw_handler_type *type;
+	struct mapped_device *md;
 	void *context;
 };
 
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 8bdc8a8..352c6fb 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  */
@@ -12,13 +13,17 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-static struct bio_set *_bios;
+struct dm_io_client {
+	mempool_t *pool;
+	struct bio_set *bios;
+};
 
 /* FIXME: can we shrink this ? */
 struct io {
 	unsigned long error;
 	atomic_t count;
 	struct task_struct *sleeper;
+	struct dm_io_client *client;
 	io_notify_fn callback;
 	void *context;
 };
@@ -26,63 +31,58 @@
 /*
  * io contexts are only dynamically allocated for asynchronous
  * io.  Since async io is likely to be the majority of io we'll
- * have the same number of io contexts as buffer heads ! (FIXME:
- * must reduce this).
+ * have the same number of io contexts as bios! (FIXME: must reduce this).
  */
-static unsigned _num_ios;
-static mempool_t *_io_pool;
 
 static unsigned int pages_to_ios(unsigned int pages)
 {
 	return 4 * pages;	/* too many ? */
 }
 
-static int resize_pool(unsigned int new_ios)
+/*
+ * Create a client with mempool and bioset.
+ */
+struct dm_io_client *dm_io_client_create(unsigned num_pages)
 {
-	int r = 0;
+	unsigned ios = pages_to_ios(num_pages);
+	struct dm_io_client *client;
 
-	if (_io_pool) {
-		if (new_ios == 0) {
-			/* free off the pool */
-			mempool_destroy(_io_pool);
-			_io_pool = NULL;
-			bioset_free(_bios);
+	client = kmalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return ERR_PTR(-ENOMEM);
 
-		} else {
-			/* resize the pool */
-			r = mempool_resize(_io_pool, new_ios, GFP_KERNEL);
-		}
+	client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io));
+	if (!client->pool)
+		goto bad;
 
-	} else {
-		/* create new pool */
-		_io_pool = mempool_create_kmalloc_pool(new_ios,
-						       sizeof(struct io));
-		if (!_io_pool)
-			return -ENOMEM;
+	client->bios = bioset_create(16, 16);
+	if (!client->bios)
+		goto bad;
 
-		_bios = bioset_create(16, 16);
-		if (!_bios) {
-			mempool_destroy(_io_pool);
-			_io_pool = NULL;
-			return -ENOMEM;
-		}
-	}
+	return client;
 
-	if (!r)
-		_num_ios = new_ios;
-
-	return r;
+   bad:
+	if (client->pool)
+		mempool_destroy(client->pool);
+	kfree(client);
+	return ERR_PTR(-ENOMEM);
 }
+EXPORT_SYMBOL(dm_io_client_create);
 
-int dm_io_get(unsigned int num_pages)
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client)
 {
-	return resize_pool(_num_ios + pages_to_ios(num_pages));
+	return mempool_resize(client->pool, pages_to_ios(num_pages),
+			      GFP_KERNEL);
 }
+EXPORT_SYMBOL(dm_io_client_resize);
 
-void dm_io_put(unsigned int num_pages)
+void dm_io_client_destroy(struct dm_io_client *client)
 {
-	resize_pool(_num_ios - pages_to_ios(num_pages));
+	mempool_destroy(client->pool);
+	bioset_free(client->bios);
+	kfree(client);
 }
+EXPORT_SYMBOL(dm_io_client_destroy);
 
 /*-----------------------------------------------------------------
  * We need to keep track of which region a bio is doing io for.
@@ -118,7 +118,7 @@
 			io_notify_fn fn = io->callback;
 			void *context = io->context;
 
-			mempool_free(io, _io_pool);
+			mempool_free(io, io->client->pool);
 			fn(r, context);
 		}
 	}
@@ -126,7 +126,8 @@
 
 static int endio(struct bio *bio, unsigned int done, int error)
 {
-	struct io *io = (struct io *) bio->bi_private;
+	struct io *io;
+	unsigned region;
 
 	/* keep going until we've finished */
 	if (bio->bi_size)
@@ -135,10 +136,17 @@
 	if (error && bio_data_dir(bio) == READ)
 		zero_fill_bio(bio);
 
-	dec_count(io, bio_get_region(bio), error);
+	/*
+	 * The bio destructor in bio_put() may use the io object.
+	 */
+	io = bio->bi_private;
+	region = bio_get_region(bio);
+
 	bio->bi_max_vecs++;
 	bio_put(bio);
 
+	dec_count(io, region, error);
+
 	return 0;
 }
 
@@ -209,6 +217,9 @@
 	dp->context_ptr = bvec;
 }
 
+/*
+ * Functions for getting the pages from a VMA.
+ */
 static void vm_get_page(struct dpages *dp,
 		 struct page **p, unsigned long *len, unsigned *offset)
 {
@@ -233,7 +244,34 @@
 
 static void dm_bio_destructor(struct bio *bio)
 {
-	bio_free(bio, _bios);
+	struct io *io = bio->bi_private;
+
+	bio_free(bio, io->client->bios);
+}
+
+/*
+ * Functions for getting the pages from kernel memory.
+ */
+static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len,
+			unsigned *offset)
+{
+	*p = virt_to_page(dp->context_ptr);
+	*offset = dp->context_u;
+	*len = PAGE_SIZE - dp->context_u;
+}
+
+static void km_next_page(struct dpages *dp)
+{
+	dp->context_ptr += PAGE_SIZE - dp->context_u;
+	dp->context_u = 0;
+}
+
+static void km_dp_init(struct dpages *dp, void *data)
+{
+	dp->get_page = km_get_page;
+	dp->next_page = km_next_page;
+	dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+	dp->context_ptr = data;
 }
 
 /*-----------------------------------------------------------------
@@ -256,7 +294,7 @@
 		 * to hide it from bio_add_page().
 		 */
 		num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
-		bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
+		bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
 		bio->bi_sector = where->sector + (where->count - remaining);
 		bio->bi_bdev = where->bdev;
 		bio->bi_end_io = endio;
@@ -311,8 +349,9 @@
 	dec_count(io, 0, 0);
 }
 
-static int sync_io(unsigned int num_regions, struct io_region *where,
-	    int rw, struct dpages *dp, unsigned long *error_bits)
+static int sync_io(struct dm_io_client *client, unsigned int num_regions,
+		   struct io_region *where, int rw, struct dpages *dp,
+		   unsigned long *error_bits)
 {
 	struct io io;
 
@@ -324,6 +363,7 @@
 	io.error = 0;
 	atomic_set(&io.count, 1); /* see dispatch_io() */
 	io.sleeper = current;
+	io.client = client;
 
 	dispatch_io(rw, num_regions, where, dp, &io, 1);
 
@@ -340,12 +380,15 @@
 	if (atomic_read(&io.count))
 		return -EINTR;
 
-	*error_bits = io.error;
+	if (error_bits)
+		*error_bits = io.error;
+
 	return io.error ? -EIO : 0;
 }
 
-static int async_io(unsigned int num_regions, struct io_region *where, int rw,
-	     struct dpages *dp, io_notify_fn fn, void *context)
+static int async_io(struct dm_io_client *client, unsigned int num_regions,
+		    struct io_region *where, int rw, struct dpages *dp,
+		    io_notify_fn fn, void *context)
 {
 	struct io *io;
 
@@ -355,10 +398,11 @@
 		return -EIO;
 	}
 
-	io = mempool_alloc(_io_pool, GFP_NOIO);
+	io = mempool_alloc(client->pool, GFP_NOIO);
 	io->error = 0;
 	atomic_set(&io->count, 1); /* see dispatch_io() */
 	io->sleeper = NULL;
+	io->client = client;
 	io->callback = fn;
 	io->context = context;
 
@@ -366,61 +410,51 @@
 	return 0;
 }
 
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
-	       struct page_list *pl, unsigned int offset,
-	       unsigned long *error_bits)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
 {
-	struct dpages dp;
-	list_dp_init(&dp, pl, offset);
-	return sync_io(num_regions, where, rw, &dp, error_bits);
+	/* Set up dpages based on memory type */
+	switch (io_req->mem.type) {
+	case DM_IO_PAGE_LIST:
+		list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
+		break;
+
+	case DM_IO_BVEC:
+		bvec_dp_init(dp, io_req->mem.ptr.bvec);
+		break;
+
+	case DM_IO_VMA:
+		vm_dp_init(dp, io_req->mem.ptr.vma);
+		break;
+
+	case DM_IO_KMEM:
+		km_dp_init(dp, io_req->mem.ptr.addr);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
-		    struct bio_vec *bvec, unsigned long *error_bits)
+/*
+ * New collapsed (a)synchronous interface
+ */
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+	  struct io_region *where, unsigned long *sync_error_bits)
 {
+	int r;
 	struct dpages dp;
-	bvec_dp_init(&dp, bvec);
-	return sync_io(num_regions, where, rw, &dp, error_bits);
-}
 
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
-		  void *data, unsigned long *error_bits)
-{
-	struct dpages dp;
-	vm_dp_init(&dp, data);
-	return sync_io(num_regions, where, rw, &dp, error_bits);
-}
+	r = dp_init(io_req, &dp);
+	if (r)
+		return r;
 
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
-		struct page_list *pl, unsigned int offset,
-		io_notify_fn fn, void *context)
-{
-	struct dpages dp;
-	list_dp_init(&dp, pl, offset);
-	return async_io(num_regions, where, rw, &dp, fn, context);
-}
+	if (!io_req->notify.fn)
+		return sync_io(io_req->client, num_regions, where,
+			       io_req->bi_rw, &dp, sync_error_bits);
 
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
-		     struct bio_vec *bvec, io_notify_fn fn, void *context)
-{
-	struct dpages dp;
-	bvec_dp_init(&dp, bvec);
-	return async_io(num_regions, where, rw, &dp, fn, context);
+	return async_io(io_req->client, num_regions, where, io_req->bi_rw,
+			&dp, io_req->notify.fn, io_req->notify.context);
 }
-
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
-		   void *data, io_notify_fn fn, void *context)
-{
-	struct dpages dp;
-	vm_dp_init(&dp, data);
-	return async_io(num_regions, where, rw, &dp, fn, context);
-}
-
-EXPORT_SYMBOL(dm_io_get);
-EXPORT_SYMBOL(dm_io_put);
-EXPORT_SYMBOL(dm_io_sync);
-EXPORT_SYMBOL(dm_io_async);
-EXPORT_SYMBOL(dm_io_sync_bvec);
-EXPORT_SYMBOL(dm_io_async_bvec);
-EXPORT_SYMBOL(dm_io_sync_vm);
-EXPORT_SYMBOL(dm_io_async_vm);
+EXPORT_SYMBOL(dm_io);
diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h
index f9035bf..f647e2c 100644
--- a/drivers/md/dm-io.h
+++ b/drivers/md/dm-io.h
@@ -12,7 +12,7 @@
 struct io_region {
 	struct block_device *bdev;
 	sector_t sector;
-	sector_t count;
+	sector_t count;		/* If this is zero the region is ignored. */
 };
 
 struct page_list {
@@ -20,55 +20,60 @@
 	struct page *page;
 };
 
-
-/*
- * 'error' is a bitset, with each bit indicating whether an error
- * occurred doing io to the corresponding region.
- */
 typedef void (*io_notify_fn)(unsigned long error, void *context);
 
+enum dm_io_mem_type {
+	DM_IO_PAGE_LIST,/* Page list */
+	DM_IO_BVEC,	/* Bio vector */
+	DM_IO_VMA,	/* Virtual memory area */
+	DM_IO_KMEM,	/* Kernel memory */
+};
+
+struct dm_io_memory {
+	enum dm_io_mem_type type;
+
+	union {
+		struct page_list *pl;
+		struct bio_vec *bvec;
+		void *vma;
+		void *addr;
+	} ptr;
+
+	unsigned offset;
+};
+
+struct dm_io_notify {
+	io_notify_fn fn;	/* Callback for asynchronous requests */
+	void *context;		/* Passed to callback */
+};
 
 /*
- * Before anyone uses the IO interface they should call
- * dm_io_get(), specifying roughly how many pages they are
- * expecting to perform io on concurrently.
- *
- * This function may block.
+ * IO request structure
  */
-int dm_io_get(unsigned int num_pages);
-void dm_io_put(unsigned int num_pages);
+struct dm_io_client;
+struct dm_io_request {
+	int bi_rw;			/* READ|WRITE - not READA */
+	struct dm_io_memory mem;	/* Memory to use for io */
+	struct dm_io_notify notify;	/* Synchronous if notify.fn is NULL */
+	struct dm_io_client *client;	/* Client memory handler */
+};
 
 /*
- * Synchronous IO.
+ * For async io calls, users can alternatively use the dm_io() function below
+ * and dm_io_client_create() to create private mempools for the client.
  *
- * Please ensure that the rw flag in the next two functions is
- * either READ or WRITE, ie. we don't take READA.  Any
- * regions with a zero count field will be ignored.
+ * Create/destroy may block.
  */
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
-	       struct page_list *pl, unsigned int offset,
-	       unsigned long *error_bits);
-
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
-		    struct bio_vec *bvec, unsigned long *error_bits);
-
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
-		  void *data, unsigned long *error_bits);
+struct dm_io_client *dm_io_client_create(unsigned num_pages);
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client);
+void dm_io_client_destroy(struct dm_io_client *client);
 
 /*
- * Aynchronous IO.
- *
- * The 'where' array may be safely allocated on the stack since
- * the function takes a copy.
+ * IO interface using private per-client pools.
+ * Each bit in the optional 'sync_error_bits' bitset indicates whether an
+ * error occurred doing io to the corresponding region.
  */
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
-		struct page_list *pl, unsigned int offset,
-		io_notify_fn fn, void *context);
-
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
-		     struct bio_vec *bvec, io_notify_fn fn, void *context);
-
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
-		   void *data, io_notify_fn fn, void *context);
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+	  struct io_region *region, unsigned long *sync_error_bits);
 
 #endif
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 6a92613..a66428d8 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -149,9 +149,12 @@
 		FORCESYNC,	/* Force a sync to happen */
 	} sync;
 
+	struct dm_io_request io_req;
+
 	/*
 	 * Disk log fields
 	 */
+	int log_dev_failed;
 	struct dm_dev *log_dev;
 	struct log_header header;
 
@@ -199,13 +202,20 @@
 	core->nr_regions = le64_to_cpu(disk->nr_regions);
 }
 
+static int rw_header(struct log_c *lc, int rw)
+{
+	lc->io_req.bi_rw = rw;
+	lc->io_req.mem.ptr.vma = lc->disk_header;
+	lc->io_req.notify.fn = NULL;
+
+	return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
+}
+
 static int read_header(struct log_c *log)
 {
 	int r;
-	unsigned long ebits;
 
-	r = dm_io_sync_vm(1, &log->header_location, READ,
-			  log->disk_header, &ebits);
+	r = rw_header(log, READ);
 	if (r)
 		return r;
 
@@ -233,11 +243,8 @@
 
 static inline int write_header(struct log_c *log)
 {
-	unsigned long ebits;
-
 	header_to_disk(&log->header, log->disk_header);
-	return dm_io_sync_vm(1, &log->header_location, WRITE,
-			     log->disk_header, &ebits);
+	return rw_header(log, WRITE);
 }
 
 /*----------------------------------------------------------------
@@ -256,6 +263,7 @@
 	uint32_t region_size;
 	unsigned int region_count;
 	size_t bitset_size, buf_size;
+	int r;
 
 	if (argc < 1 || argc > 2) {
 		DMWARN("wrong number of arguments to mirror log");
@@ -315,6 +323,7 @@
 		lc->disk_header = NULL;
 	} else {
 		lc->log_dev = dev;
+		lc->log_dev_failed = 0;
 		lc->header_location.bdev = lc->log_dev->bdev;
 		lc->header_location.sector = 0;
 
@@ -324,6 +333,15 @@
 		buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
 				       bitset_size, ti->limits.hardsect_size);
 		lc->header_location.count = buf_size >> SECTOR_SHIFT;
+		lc->io_req.mem.type = DM_IO_VMA;
+		lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
+								   PAGE_SIZE));
+		if (IS_ERR(lc->io_req.client)) {
+			r = PTR_ERR(lc->io_req.client);
+			DMWARN("couldn't allocate disk io client");
+			kfree(lc);
+			return -ENOMEM;
+		}
 
 		lc->disk_header = vmalloc(buf_size);
 		if (!lc->disk_header) {
@@ -424,6 +442,7 @@
 
 	dm_put_device(lc->ti, lc->log_dev);
 	vfree(lc->disk_header);
+	dm_io_client_destroy(lc->io_req.client);
 	destroy_log_context(lc);
 }
 
@@ -437,6 +456,15 @@
 	return count;
 }
 
+static void fail_log_device(struct log_c *lc)
+{
+	if (lc->log_dev_failed)
+		return;
+
+	lc->log_dev_failed = 1;
+	dm_table_event(lc->ti->table);
+}
+
 static int disk_resume(struct dirty_log *log)
 {
 	int r;
@@ -446,8 +474,19 @@
 
 	/* read the disk header */
 	r = read_header(lc);
-	if (r)
-		return r;
+	if (r) {
+		DMWARN("%s: Failed to read header on mirror log device",
+		       lc->log_dev->name);
+		fail_log_device(lc);
+		/*
+		 * If the log device cannot be read, we must assume
+		 * all regions are out-of-sync.  If we simply return
+		 * here, the state will be uninitialized and could
+		 * lead us to return 'in-sync' status for regions
+		 * that are actually 'out-of-sync'.
+		 */
+		lc->header.nr_regions = 0;
+	}
 
 	/* set or clear any new bits -- device has grown */
 	if (lc->sync == NOSYNC)
@@ -472,7 +511,14 @@
 	lc->header.nr_regions = lc->region_count;
 
 	/* write the new header */
-	return write_header(lc);
+	r = write_header(lc);
+	if (r) {
+		DMWARN("%s: Failed to write header on mirror log device",
+		       lc->log_dev->name);
+		fail_log_device(lc);
+	}
+
+	return r;
 }
 
 static uint32_t core_get_region_size(struct dirty_log *log)
@@ -516,7 +562,9 @@
 		return 0;
 
 	r = write_header(lc);
-	if (!r)
+	if (r)
+		fail_log_device(lc);
+	else
 		lc->touched = 0;
 
 	return r;
@@ -591,6 +639,7 @@
 
 	switch(status) {
 	case STATUSTYPE_INFO:
+		DMEMIT("1 %s", log->type->name);
 		break;
 
 	case STATUSTYPE_TABLE:
@@ -606,17 +655,17 @@
 		       char *result, unsigned int maxlen)
 {
 	int sz = 0;
-	char buffer[16];
 	struct log_c *lc = log->context;
 
 	switch(status) {
 	case STATUSTYPE_INFO:
+		DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
+		       lc->log_dev_failed ? 'D' : 'A');
 		break;
 
 	case STATUSTYPE_TABLE:
-		format_dev_t(buffer, lc->log_dev->bdev->bd_dev);
 		DMEMIT("%s %u %s %u ", log->type->name,
-		       lc->sync == DEFAULTSYNC ? 2 : 3, buffer,
+		       lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
 		       lc->region_size);
 		DMEMIT_SYNC;
 	}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 3aa0135..de54b39 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -668,6 +668,9 @@
 		return -EINVAL;
 	}
 
+	m->hw_handler.md = dm_table_get_md(ti->table);
+	dm_put(m->hw_handler.md);
+
 	r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
 	if (r) {
 		dm_put_hw_handler(hwht);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 23a6426..ef124b7 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -21,16 +21,12 @@
 #include <linux/workqueue.h>
 
 #define DM_MSG_PREFIX "raid1"
+#define DM_IO_PAGES 64
 
-static struct workqueue_struct *_kmirrord_wq;
-static struct work_struct _kmirrord_work;
+#define DM_RAID1_HANDLE_ERRORS 0x01
+
 static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
 
-static inline void wake(void)
-{
-	queue_work(_kmirrord_wq, &_kmirrord_work);
-}
-
 /*-----------------------------------------------------------------
  * Region hash
  *
@@ -125,17 +121,23 @@
 	struct list_head list;
 	struct region_hash rh;
 	struct kcopyd_client *kcopyd_client;
+	uint64_t features;
 
 	spinlock_t lock;	/* protects the next two lists */
 	struct bio_list reads;
 	struct bio_list writes;
 
+	struct dm_io_client *io_client;
+
 	/* recovery */
 	region_t nr_regions;
 	int in_sync;
 
 	struct mirror *default_mirror;	/* Default mirror */
 
+	struct workqueue_struct *kmirrord_wq;
+	struct work_struct kmirrord_work;
+
 	unsigned int nr_mirrors;
 	struct mirror mirror[0];
 };
@@ -153,6 +155,11 @@
 	return region << rh->region_shift;
 }
 
+static void wake(struct mirror_set *ms)
+{
+	queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
+}
+
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
@@ -398,8 +405,7 @@
 		mempool_free(reg, rh->region_pool);
 	}
 
-	if (!list_empty(&recovered))
-		rh->log->type->flush(rh->log);
+	rh->log->type->flush(rh->log);
 
 	list_for_each_entry_safe (reg, next, &clean, list)
 		mempool_free(reg, rh->region_pool);
@@ -471,7 +477,7 @@
 	spin_unlock_irqrestore(&rh->region_lock, flags);
 
 	if (should_wake)
-		wake();
+		wake(rh->ms);
 }
 
 /*
@@ -558,7 +564,7 @@
 	list_add(&reg->list, &reg->rh->recovered_regions);
 	spin_unlock_irq(&rh->region_lock);
 
-	wake();
+	wake(rh->ms);
 }
 
 static void rh_flush(struct region_hash *rh)
@@ -592,7 +598,7 @@
 	for (i = 0; i < MAX_RECOVERY; i++)
 		up(&rh->recovery_count);
 
-	wake();
+	wake(rh->ms);
 }
 
 /*
@@ -735,7 +741,7 @@
 		/*
 		 * We can only read balance if the region is in sync.
 		 */
-		if (rh_in_sync(&ms->rh, region, 0))
+		if (rh_in_sync(&ms->rh, region, 1))
 			m = choose_mirror(ms, bio->bi_sector);
 		else
 			m = ms->default_mirror;
@@ -792,6 +798,14 @@
 	unsigned int i;
 	struct io_region io[KCOPYD_MAX_REGIONS+1];
 	struct mirror *m;
+	struct dm_io_request io_req = {
+		.bi_rw = WRITE,
+		.mem.type = DM_IO_BVEC,
+		.mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+		.notify.fn = write_callback,
+		.notify.context = bio,
+		.client = ms->io_client,
+	};
 
 	for (i = 0; i < ms->nr_mirrors; i++) {
 		m = ms->mirror + i;
@@ -802,9 +816,8 @@
 	}
 
 	bio_set_ms(bio, ms);
-	dm_io_async_bvec(ms->nr_mirrors, io, WRITE,
-			 bio->bi_io_vec + bio->bi_idx,
-			 write_callback, bio);
+
+	(void) dm_io(&io_req, ms->nr_mirrors, io, NULL);
 }
 
 static void do_writes(struct mirror_set *ms, struct bio_list *writes)
@@ -870,11 +883,10 @@
 /*-----------------------------------------------------------------
  * kmirrord
  *---------------------------------------------------------------*/
-static LIST_HEAD(_mirror_sets);
-static DECLARE_RWSEM(_mirror_sets_lock);
-
-static void do_mirror(struct mirror_set *ms)
+static void do_mirror(struct work_struct *work)
 {
+	struct mirror_set *ms =container_of(work, struct mirror_set,
+					    kmirrord_work);
 	struct bio_list reads, writes;
 
 	spin_lock(&ms->lock);
@@ -890,16 +902,6 @@
 	do_writes(ms, &writes);
 }
 
-static void do_work(struct work_struct *ignored)
-{
-	struct mirror_set *ms;
-
-	down_read(&_mirror_sets_lock);
-	list_for_each_entry (ms, &_mirror_sets, list)
-		do_mirror(ms);
-	up_read(&_mirror_sets_lock);
-}
-
 /*-----------------------------------------------------------------
  * Target functions
  *---------------------------------------------------------------*/
@@ -931,6 +933,13 @@
 	ms->in_sync = 0;
 	ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
 
+	ms->io_client = dm_io_client_create(DM_IO_PAGES);
+	if (IS_ERR(ms->io_client)) {
+		ti->error = "Error creating dm_io client";
+		kfree(ms);
+ 		return NULL;
+	}
+
 	if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
 		ti->error = "Error creating dirty region hash";
 		kfree(ms);
@@ -946,6 +955,7 @@
 	while (m--)
 		dm_put_device(ti, ms->mirror[m].dev);
 
+	dm_io_client_destroy(ms->io_client);
 	rh_exit(&ms->rh);
 	kfree(ms);
 }
@@ -978,23 +988,6 @@
 	return 0;
 }
 
-static int add_mirror_set(struct mirror_set *ms)
-{
-	down_write(&_mirror_sets_lock);
-	list_add_tail(&ms->list, &_mirror_sets);
-	up_write(&_mirror_sets_lock);
-	wake();
-
-	return 0;
-}
-
-static void del_mirror_set(struct mirror_set *ms)
-{
-	down_write(&_mirror_sets_lock);
-	list_del(&ms->list);
-	up_write(&_mirror_sets_lock);
-}
-
 /*
  * Create dirty log: log_type #log_params <log_params>
  */
@@ -1037,16 +1030,55 @@
 	return dl;
 }
 
+static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
+			  unsigned *args_used)
+{
+	unsigned num_features;
+	struct dm_target *ti = ms->ti;
+
+	*args_used = 0;
+
+	if (!argc)
+		return 0;
+
+	if (sscanf(argv[0], "%u", &num_features) != 1) {
+		ti->error = "Invalid number of features";
+		return -EINVAL;
+	}
+
+	argc--;
+	argv++;
+	(*args_used)++;
+
+	if (num_features > argc) {
+		ti->error = "Not enough arguments to support feature count";
+		return -EINVAL;
+	}
+
+	if (!strcmp("handle_errors", argv[0]))
+		ms->features |= DM_RAID1_HANDLE_ERRORS;
+	else {
+		ti->error = "Unrecognised feature requested";
+		return -EINVAL;
+	}
+
+	(*args_used)++;
+
+	return 0;
+}
+
 /*
  * Construct a mirror mapping:
  *
  * log_type #log_params <log_params>
  * #mirrors [mirror_path offset]{2,}
+ * [#features <features>]
  *
  * log_type is "core" or "disk"
  * #log_params is between 1 and 3
+ *
+ * If present, features must be "handle_errors".
  */
-#define DM_IO_PAGES 64
 static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
 	int r;
@@ -1070,8 +1102,8 @@
 
 	argv++, argc--;
 
-	if (argc != nr_mirrors * 2) {
-		ti->error = "Wrong number of mirror arguments";
+	if (argc < nr_mirrors * 2) {
+		ti->error = "Too few mirror arguments";
 		dm_destroy_dirty_log(dl);
 		return -EINVAL;
 	}
@@ -1096,13 +1128,37 @@
 	ti->private = ms;
  	ti->split_io = ms->rh.region_size;
 
-	r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+	ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
+	if (!ms->kmirrord_wq) {
+		DMERR("couldn't start kmirrord");
+		free_context(ms, ti, m);
+		return -ENOMEM;
+	}
+	INIT_WORK(&ms->kmirrord_work, do_mirror);
+
+	r = parse_features(ms, argc, argv, &args_used);
 	if (r) {
 		free_context(ms, ti, ms->nr_mirrors);
 		return r;
 	}
 
-	add_mirror_set(ms);
+	argv += args_used;
+	argc -= args_used;
+
+	if (argc) {
+		ti->error = "Too many mirror arguments";
+		free_context(ms, ti, ms->nr_mirrors);
+		return -EINVAL;
+	}
+
+	r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+	if (r) {
+		destroy_workqueue(ms->kmirrord_wq);
+		free_context(ms, ti, ms->nr_mirrors);
+		return r;
+	}
+
+	wake(ms);
 	return 0;
 }
 
@@ -1110,8 +1166,9 @@
 {
 	struct mirror_set *ms = (struct mirror_set *) ti->private;
 
-	del_mirror_set(ms);
+	flush_workqueue(ms->kmirrord_wq);
 	kcopyd_client_destroy(ms->kcopyd_client);
+	destroy_workqueue(ms->kmirrord_wq);
 	free_context(ms, ti, ms->nr_mirrors);
 }
 
@@ -1127,7 +1184,7 @@
 	spin_unlock(&ms->lock);
 
 	if (should_wake)
-		wake();
+		wake(ms);
 }
 
 /*
@@ -1222,11 +1279,9 @@
 static int mirror_status(struct dm_target *ti, status_type_t type,
 			 char *result, unsigned int maxlen)
 {
-	unsigned int m, sz;
+	unsigned int m, sz = 0;
 	struct mirror_set *ms = (struct mirror_set *) ti->private;
 
-	sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
-
 	switch (type) {
 	case STATUSTYPE_INFO:
 		DMEMIT("%d ", ms->nr_mirrors);
@@ -1237,13 +1292,21 @@
 			(unsigned long long)ms->rh.log->type->
 				get_sync_count(ms->rh.log),
 			(unsigned long long)ms->nr_regions);
+
+		sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
 		break;
 
 	case STATUSTYPE_TABLE:
+		sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
 		DMEMIT("%d", ms->nr_mirrors);
 		for (m = 0; m < ms->nr_mirrors; m++)
 			DMEMIT(" %s %llu", ms->mirror[m].dev->name,
 				(unsigned long long)ms->mirror[m].offset);
+
+		if (ms->features & DM_RAID1_HANDLE_ERRORS)
+			DMEMIT(" 1 handle_errors");
 	}
 
 	return 0;
@@ -1251,7 +1314,7 @@
 
 static struct target_type mirror_target = {
 	.name	 = "mirror",
-	.version = {1, 0, 2},
+	.version = {1, 0, 3},
 	.module	 = THIS_MODULE,
 	.ctr	 = mirror_ctr,
 	.dtr	 = mirror_dtr,
@@ -1270,20 +1333,11 @@
 	if (r)
 		return r;
 
-	_kmirrord_wq = create_singlethread_workqueue("kmirrord");
-	if (!_kmirrord_wq) {
-		DMERR("couldn't start kmirrord");
-		dm_dirty_log_exit();
-		return r;
-	}
-	INIT_WORK(&_kmirrord_work, do_work);
-
 	r = dm_register_target(&mirror_target);
 	if (r < 0) {
 		DMERR("%s: Failed to register mirror target",
 		      mirror_target.name);
 		dm_dirty_log_exit();
-		destroy_workqueue(_kmirrord_wq);
 	}
 
 	return r;
@@ -1297,7 +1351,6 @@
 	if (r < 0)
 		DMERR("%s: unregister failed %d", mirror_target.name, r);
 
-	destroy_workqueue(_kmirrord_wq);
 	dm_dirty_log_exit();
 }
 
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 05befa9..2fc199b 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -425,13 +425,15 @@
 }
 
 /*
- * If possible (ie. blk_size[major] is set), this checks an area
- * of a destination device is valid.
+ * If possible, this checks an area of a destination device is valid.
  */
 static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
 {
-	sector_t dev_size;
-	dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+	sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+
+	if (!dev_size)
+		return 1;
+
 	return ((start < dev_size) && (len <= (dev_size - start)));
 }
 
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 11a98df..2717a35 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1236,6 +1236,7 @@
 		free_dev(md);
 	}
 }
+EXPORT_SYMBOL_GPL(dm_put);
 
 /*
  * Process the deferred bios
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index b46f6c5..dbc234e 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  *
@@ -45,6 +46,8 @@
 	unsigned int nr_pages;
 	unsigned int nr_free_pages;
 
+	struct dm_io_client *io_client;
+
 	wait_queue_head_t destroyq;
 	atomic_t nr_jobs;
 };
@@ -342,16 +345,20 @@
 static int run_io_job(struct kcopyd_job *job)
 {
 	int r;
+	struct dm_io_request io_req = {
+		.bi_rw = job->rw,
+		.mem.type = DM_IO_PAGE_LIST,
+		.mem.ptr.pl = job->pages,
+		.mem.offset = job->offset,
+		.notify.fn = complete_io,
+		.notify.context = job,
+		.client = job->kc->io_client,
+	};
 
 	if (job->rw == READ)
-		r = dm_io_async(1, &job->source, job->rw,
-				job->pages,
-				job->offset, complete_io, job);
-
+		r = dm_io(&io_req, 1, &job->source, NULL);
 	else
-		r = dm_io_async(job->num_dests, job->dests, job->rw,
-				job->pages,
-				job->offset, complete_io, job);
+		r = dm_io(&io_req, job->num_dests, job->dests, NULL);
 
 	return r;
 }
@@ -670,8 +677,9 @@
 		return r;
 	}
 
-	r = dm_io_get(nr_pages);
-	if (r) {
+	kc->io_client = dm_io_client_create(nr_pages);
+	if (IS_ERR(kc->io_client)) {
+		r = PTR_ERR(kc->io_client);
 		client_free_pages(kc);
 		kfree(kc);
 		kcopyd_exit();
@@ -691,7 +699,7 @@
 	/* Wait for completion of all jobs submitted by this client. */
 	wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
 
-	dm_io_put(kc->nr_pages);
+	dm_io_client_destroy(kc->io_client);
 	client_free_pages(kc);
 	client_del(kc);
 	kfree(kc);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 2b4315d..65814b0 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -33,6 +33,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/linkage.h>
 #include <linux/raid/md.h>
@@ -273,6 +274,7 @@
 	atomic_set(&new->active, 1);
 	spin_lock_init(&new->write_lock);
 	init_waitqueue_head(&new->sb_wait);
+	new->reshape_position = MaxSector;
 
 	new->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!new->queue) {
@@ -589,14 +591,41 @@
 	return ret;
 }
 
+
+static u32 md_csum_fold(u32 csum)
+{
+	csum = (csum & 0xffff) + (csum >> 16);
+	return (csum & 0xffff) + (csum >> 16);
+}
+
 static unsigned int calc_sb_csum(mdp_super_t * sb)
 {
+	u64 newcsum = 0;
+	u32 *sb32 = (u32*)sb;
+	int i;
 	unsigned int disk_csum, csum;
 
 	disk_csum = sb->sb_csum;
 	sb->sb_csum = 0;
-	csum = csum_partial((void *)sb, MD_SB_BYTES, 0);
+
+	for (i = 0; i < MD_SB_BYTES/4 ; i++)
+		newcsum += sb32[i];
+	csum = (newcsum & 0xffffffff) + (newcsum>>32);
+
+
+#ifdef CONFIG_ALPHA
+	/* This used to use csum_partial, which was wrong for several
+	 * reasons including that different results are returned on
+	 * different architectures.  It isn't critical that we get exactly
+	 * the same return value as before (we always csum_fold before
+	 * testing, and that removes any differences).  However as we
+	 * know that csum_partial always returned a 16bit value on
+	 * alphas, do a fold to maximise conformity to previous behaviour.
+	 */
+	sb->sb_csum = md_csum_fold(disk_csum);
+#else
 	sb->sb_csum = disk_csum;
+#endif
 	return csum;
 }
 
@@ -684,7 +713,7 @@
 	if (sb->raid_disks <= 0)
 		goto abort;
 
-	if (csum_fold(calc_sb_csum(sb)) != csum_fold(sb->sb_csum)) {
+	if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
 		printk(KERN_WARNING "md: invalid superblock checksum on %s\n",
 			b);
 		goto abort;
@@ -694,6 +723,17 @@
 	rdev->data_offset = 0;
 	rdev->sb_size = MD_SB_BYTES;
 
+	if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+		if (sb->level != 1 && sb->level != 4
+		    && sb->level != 5 && sb->level != 6
+		    && sb->level != 10) {
+			/* FIXME use a better test */
+			printk(KERN_WARNING
+			       "md: bitmaps not supported for this level.\n");
+			goto abort;
+		}
+	}
+
 	if (sb->level == LEVEL_MULTIPATH)
 		rdev->desc_nr = -1;
 	else
@@ -792,16 +832,8 @@
 		mddev->max_disks = MD_SB_DISKS;
 
 		if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
-		    mddev->bitmap_file == NULL) {
-			if (mddev->level != 1 && mddev->level != 4
-			    && mddev->level != 5 && mddev->level != 6
-			    && mddev->level != 10) {
-				/* FIXME use a better test */
-				printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
-				return -EINVAL;
-			}
+		    mddev->bitmap_file == NULL)
 			mddev->bitmap_offset = mddev->default_bitmap_offset;
-		}
 
 	} else if (mddev->pers == NULL) {
 		/* Insist on good event counter while assembling */
@@ -1058,6 +1090,18 @@
 		       bdevname(rdev->bdev,b));
 		return -EINVAL;
 	}
+	if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) {
+		if (sb->level != cpu_to_le32(1) &&
+		    sb->level != cpu_to_le32(4) &&
+		    sb->level != cpu_to_le32(5) &&
+		    sb->level != cpu_to_le32(6) &&
+		    sb->level != cpu_to_le32(10)) {
+			printk(KERN_WARNING
+			       "md: bitmaps not supported for this level.\n");
+			return -EINVAL;
+		}
+	}
+
 	rdev->preferred_minor = 0xffff;
 	rdev->data_offset = le64_to_cpu(sb->data_offset);
 	atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
@@ -1141,14 +1185,9 @@
 		mddev->max_disks =  (4096-256)/2;
 
 		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
-		    mddev->bitmap_file == NULL ) {
-			if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
-			    && mddev->level != 10) {
-				printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
-				return -EINVAL;
-			}
+		    mddev->bitmap_file == NULL )
 			mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
-		}
+
 		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
 			mddev->reshape_position = le64_to_cpu(sb->reshape_position);
 			mddev->delta_disks = le32_to_cpu(sb->delta_disks);
@@ -2204,6 +2243,10 @@
 layout_show(mddev_t *mddev, char *page)
 {
 	/* just a number, not meaningful for all levels */
+	if (mddev->reshape_position != MaxSector &&
+	    mddev->layout != mddev->new_layout)
+		return sprintf(page, "%d (%d)\n",
+			       mddev->new_layout, mddev->layout);
 	return sprintf(page, "%d\n", mddev->layout);
 }
 
@@ -2212,13 +2255,16 @@
 {
 	char *e;
 	unsigned long n = simple_strtoul(buf, &e, 10);
-	if (mddev->pers)
-		return -EBUSY;
 
 	if (!*buf || (*e && *e != '\n'))
 		return -EINVAL;
 
-	mddev->layout = n;
+	if (mddev->pers)
+		return -EBUSY;
+	if (mddev->reshape_position != MaxSector)
+		mddev->new_layout = n;
+	else
+		mddev->layout = n;
 	return len;
 }
 static struct md_sysfs_entry md_layout =
@@ -2230,6 +2276,10 @@
 {
 	if (mddev->raid_disks == 0)
 		return 0;
+	if (mddev->reshape_position != MaxSector &&
+	    mddev->delta_disks != 0)
+		return sprintf(page, "%d (%d)\n", mddev->raid_disks,
+			       mddev->raid_disks - mddev->delta_disks);
 	return sprintf(page, "%d\n", mddev->raid_disks);
 }
 
@@ -2247,7 +2297,11 @@
 
 	if (mddev->pers)
 		rv = update_raid_disks(mddev, n);
-	else
+	else if (mddev->reshape_position != MaxSector) {
+		int olddisks = mddev->raid_disks - mddev->delta_disks;
+		mddev->delta_disks = n - olddisks;
+		mddev->raid_disks = n;
+	} else
 		mddev->raid_disks = n;
 	return rv ? rv : len;
 }
@@ -2257,6 +2311,10 @@
 static ssize_t
 chunk_size_show(mddev_t *mddev, char *page)
 {
+	if (mddev->reshape_position != MaxSector &&
+	    mddev->chunk_size != mddev->new_chunk)
+		return sprintf(page, "%d (%d)\n", mddev->new_chunk,
+			       mddev->chunk_size);
 	return sprintf(page, "%d\n", mddev->chunk_size);
 }
 
@@ -2267,12 +2325,15 @@
 	char *e;
 	unsigned long n = simple_strtoul(buf, &e, 10);
 
-	if (mddev->pers)
-		return -EBUSY;
 	if (!*buf || (*e && *e != '\n'))
 		return -EINVAL;
 
-	mddev->chunk_size = n;
+	if (mddev->pers)
+		return -EBUSY;
+	else if (mddev->reshape_position != MaxSector)
+		mddev->new_chunk = n;
+	else
+		mddev->chunk_size = n;
 	return len;
 }
 static struct md_sysfs_entry md_chunk_size =
@@ -2637,8 +2698,7 @@
 	minor = simple_strtoul(buf, &e, 10);
 	if (e==buf || (*e && *e != '\n') )
 		return -EINVAL;
-	if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
-	    super_types[major].name == NULL)
+	if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
 		return -ENOENT;
 	mddev->major_version = major;
 	mddev->minor_version = minor;
@@ -2859,6 +2919,37 @@
 static struct md_sysfs_entry md_suspend_hi =
 __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
 
+static ssize_t
+reshape_position_show(mddev_t *mddev, char *page)
+{
+	if (mddev->reshape_position != MaxSector)
+		return sprintf(page, "%llu\n",
+			       (unsigned long long)mddev->reshape_position);
+	strcpy(page, "none\n");
+	return 5;
+}
+
+static ssize_t
+reshape_position_store(mddev_t *mddev, const char *buf, size_t len)
+{
+	char *e;
+	unsigned long long new = simple_strtoull(buf, &e, 10);
+	if (mddev->pers)
+		return -EBUSY;
+	if (buf == e || (*e && *e != '\n'))
+		return -EINVAL;
+	mddev->reshape_position = new;
+	mddev->delta_disks = 0;
+	mddev->new_level = mddev->level;
+	mddev->new_layout = mddev->layout;
+	mddev->new_chunk = mddev->chunk_size;
+	return len;
+}
+
+static struct md_sysfs_entry md_reshape_position =
+__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
+       reshape_position_store);
+
 
 static struct attribute *md_default_attrs[] = {
 	&md_level.attr,
@@ -2871,6 +2962,7 @@
 	&md_new_device.attr,
 	&md_safe_delay.attr,
 	&md_array_state.attr,
+	&md_reshape_position.attr,
 	NULL,
 };
 
@@ -3409,6 +3501,7 @@
 		mddev->size = 0;
 		mddev->raid_disks = 0;
 		mddev->recovery_cp = 0;
+		mddev->reshape_position = MaxSector;
 
 	} else if (mddev->pers)
 		printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4019,7 +4112,7 @@
 	if (info->raid_disks == 0) {
 		/* just setting version number for superblock loading */
 		if (info->major_version < 0 ||
-		    info->major_version >= sizeof(super_types)/sizeof(super_types[0]) ||
+		    info->major_version >= ARRAY_SIZE(super_types) ||
 		    super_types[info->major_version].name == NULL) {
 			/* maybe try to auto-load a module? */
 			printk(KERN_INFO 
@@ -4941,15 +5034,6 @@
 	return error;
 }
 
-static int md_seq_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *m = file->private_data;
-	struct mdstat_info *mi = m->private;
-	m->private = NULL;
-	kfree(mi);
-	return seq_release(inode, file);
-}
-
 static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
 {
 	struct seq_file *m = filp->private_data;
@@ -4971,7 +5055,7 @@
 	.open           = md_seq_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
-	.release	= md_seq_release,
+	.release	= seq_release_private,
 	.poll		= mdstat_poll,
 };
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8d59914..061375e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -353,8 +353,8 @@
 	struct kmem_cache *sc;
 	int devs = conf->raid_disks;
 
-	sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev));
-	sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev));
+	sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev));
+	sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev));
 	conf->active_name = 0;
 	sc = kmem_cache_create(conf->cache_name[conf->active_name],
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 68ed3a7..9200a30 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
  * see dvb-usb-init.c for copyright information.
  *
- * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
  */
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f5d40aa..f64546c 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -266,7 +266,7 @@
 {
 
 /* internal */
-//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
 	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
 	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
 
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 0349a4b..aece458 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -223,7 +223,7 @@
 static int dib7000p_sad_calib(struct dib7000p_state *state)
 {
 /* internal */
-//	dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+//	dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
 	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
 	dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
 
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 1105368..e725f61 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -1,6 +1,6 @@
 /*
     TDA10021  - Single Chip Cable Channel Receiver driver module
-	       used on the the Siemens DVB-C cards
+	       used on the Siemens DVB-C cards
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
     Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 54d7b07..23fd030 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -306,7 +306,7 @@
 	 * The ves1893 sometimes returns sync values that make no sense,
 	 * because, e.g., the SIGNAL bit is 0, while some of the higher
 	 * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
-	 * Tests showed that the the VITERBI and SYNC bits are returned
+	 * Tests showed that the VITERBI and SYNC bits are returned
 	 * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
 	 * If such a case occurs, we read the value again, until we get a
 	 * valid value.
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 563a831..54ccc6e 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -70,7 +70,7 @@
 
 	ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
 	if (ret != 2 + len) {
-		em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+		em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
 		return -EIO;
 	}
 	for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index bec6760..2c7b158 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1729,7 +1729,7 @@
 
 	endpoint = &interface->cur_altsetting->endpoint[1].desc;
 
-	/* check if the the device has the iso in endpoint at the correct place */
+	/* check if the device has the iso in endpoint at the correct place */
 	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
 	    USB_ENDPOINT_XFER_ISOC) {
 		em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
index f5e8484..f9f3584 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/video/pwc/philips.txt
@@ -54,9 +54,9 @@
    Specifies the desired framerate. Is an integer in the range of 4-30.
 
 fbufs
-   This paramter specifies the number of internal buffers to use for storing
+   This parameter specifies the number of internal buffers to use for storing
    frames from the cam. This will help if the process that reads images from
-   the cam is a bit slow or momentarely busy. However, on slow machines it
+   the cam is a bit slow or momentarily busy. However, on slow machines it
    only introduces lag, so choose carefully. The default is 3, which is
    reasonable. You can set it between 2 and 5.
 
@@ -209,7 +209,7 @@
 
      128   0x80   PWCX debugging                                      Off
 
-   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+   For example, to trace the open() & read() functions, sum 8 + 4 = 12,
    so you would supply trace=12 during insmod or modprobe. If
    you want to turn the initialization and probing tracing off, set trace=0.
    The default value for trace is 35 (0x23).
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 876fd27..982b115 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -28,7 +28,7 @@
  *
  * Portions of this code were also copied from usbvideo.c
  *
- * Special thanks to the the whole team at Sourceforge for help making
+ * Special thanks to the whole team at Sourceforge for help making
  * this driver become a reality.  Notably:
  * Andy Armstrong who reverse engineered the color encoding and
  * Pavel Machek and Chris Cheney who worked on reverse engineering the
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index d6b4c60..ddc7ae0 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -571,7 +571,7 @@
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  12-04-00  01.01.02  Added messages for Common Transport Send and
  *                      Primitive Send.
- *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *  01-09-01  01.01.03  Modified some of the new flags to have an MPI prefix
  *                      and modified the FcPrimitiveSend flags.
  *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
  *                      field.
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 97471af..5021d1a 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -3585,7 +3585,7 @@
 	 * index = chain_idx
 	 *
 	 * Calculate the number of chain buffers needed(plus 1) per I/O
-	 * then multiply the the maximum number of simultaneous cmds
+	 * then multiply the maximum number of simultaneous cmds
 	 *
 	 * num_sge = num sge in request frame + last chain buffer
 	 * scale = num sge per chain buffer if no chain element
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 1ba6c08..c08ad8f 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -105,7 +105,8 @@
 	    == TIFM_TYPE_XD)
 		msleep(40);
 
-	writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+	writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00,
+	       sock_addr + SOCK_CONTROL);
 	/* wait for power to stabilize */
 	msleep(20);
 	for (cnt = 16; cnt <= 256; cnt <<= 1) {
@@ -122,6 +123,12 @@
 	return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
 }
 
+inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr)
+{
+	writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL),
+	       sock_addr + SOCK_CONTROL);
+}
+
 inline static char __iomem *
 tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
 {
@@ -133,6 +140,7 @@
 	struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
 					       media_switcher);
 	struct tifm_dev *sock;
+	char __iomem *sock_addr;
 	unsigned long flags;
 	unsigned char media_id;
 	unsigned int socket_change_set, cnt;
@@ -158,11 +166,12 @@
 			       "%s : demand removing card from socket %u:%u\n",
 			       fm->cdev.class_id, fm->id, cnt);
 			fm->sockets[cnt] = NULL;
+			sock_addr = sock->addr;
 			spin_unlock_irqrestore(&fm->lock, flags);
 			device_unregister(&sock->dev);
 			spin_lock_irqsave(&fm->lock, flags);
-			writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
-			       + SOCK_CONTROL);
+			tifm_7xx1_sock_power_off(sock_addr);
+			writel(0x0e00, sock_addr + SOCK_CONTROL);
 		}
 
 		spin_unlock_irqrestore(&fm->lock, flags);
@@ -205,8 +214,16 @@
 
 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
 {
+	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	int cnt;
+
 	dev_dbg(&dev->dev, "suspending host\n");
 
+	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+		if (fm->sockets[cnt])
+			tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr);
+	}
+
 	pci_save_state(dev);
 	pci_enable_wake(dev, pci_choose_state(dev, state), 0);
 	pci_disable_device(dev);
@@ -357,6 +374,7 @@
 static void tifm_7xx1_remove(struct pci_dev *dev)
 {
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	int cnt;
 
 	fm->eject = tifm_7xx1_dummy_eject;
 	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
@@ -365,6 +383,9 @@
 
 	tifm_remove_adapter(fm);
 
+	for (cnt = 0; cnt < fm->num_sockets; cnt++)
+		tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt));
+
 	pci_set_drvdata(dev, NULL);
 
 	iounmap(fm->addr);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 6c97491..45b7d53 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -2,10 +2,8 @@
 # MMC subsystem configuration
 #
 
-menu "MMC/SD Card support"
-
-config MMC
-	tristate "MMC support"
+menuconfig MMC
+	tristate "MMC/SD card support"
 	help
 	  MMC is the "multi-media card" bus protocol.
 
@@ -19,10 +17,12 @@
 	  This is an option for use by developers; most people should
 	  say N here.  This enables MMC core and driver debugging.
 
+if MMC
+
 source "drivers/mmc/core/Kconfig"
 
 source "drivers/mmc/card/Kconfig"
 
 source "drivers/mmc/host/Kconfig"
 
-endmenu
+endif # MMC
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 01a9fd3..9320a8c 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -3,11 +3,10 @@
 #
 
 comment "MMC/SD Card Drivers"
-	depends MMC
 
 config MMC_BLOCK
 	tristate "MMC block device driver"
-	depends on MMC && BLOCK
+	depends on BLOCK
 	default y
 	help
 	  Say Y here to enable the MMC block device driver support.
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 94222b9..ab37a6d 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -4,7 +4,6 @@
 
 config MMC_UNSAFE_RESUME
 	bool "Allow unsafe resume (DANGEROUS)"
-	depends on MMC != n
 	help
 	  If you say Y here, the MMC layer will assume that all cards
 	  stayed in their respective slots during the suspend. The
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 72c7cf4..7385acf 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -500,9 +500,10 @@
 void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
 #ifdef CONFIG_MMC_DEBUG
-	mmc_claim_host(host);
+	unsigned long flags;
+	spin_lock_irqsave(&host->lock, flags);
 	BUG_ON(host->removed);
-	mmc_release_host(host);
+	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
 	mmc_schedule_delayed_work(&host->detect, delay);
@@ -625,9 +626,10 @@
 void mmc_remove_host(struct mmc_host *host)
 {
 #ifdef CONFIG_MMC_DEBUG
-	mmc_claim_host(host);
+	unsigned long flags;
+	spin_lock_irqsave(&host->lock, flags);
 	host->removed = 1;
-	mmc_release_host(host);
+	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
 	mmc_flush_scheduled_work();
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ed4deab..e23082f 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -3,11 +3,10 @@
 #
 
 comment "MMC/SD Host Controller Drivers"
-	depends on MMC
 
 config MMC_ARMMMCI
 	tristate "ARM AMBA Multimedia Card Interface support"
-	depends on ARM_AMBA && MMC
+	depends on ARM_AMBA
 	help
 	  This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
 	  Interface (PL180 and PL181) support.  If you have an ARM(R)
@@ -17,7 +16,7 @@
 
 config MMC_PXA
 	tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
-	depends on ARCH_PXA && MMC
+	depends on ARCH_PXA
 	help
 	  This selects the Intel(R) PXA(R) Multimedia card Interface.
 	  If you have a PXA(R) platform with a Multimedia Card slot,
@@ -27,7 +26,7 @@
 
 config MMC_SDHCI
 	tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
-	depends on PCI && MMC && EXPERIMENTAL
+	depends on PCI && EXPERIMENTAL
 	help
 	  This select the generic Secure Digital Host Controller Interface.
 	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
@@ -38,7 +37,7 @@
 
 config MMC_OMAP
 	tristate "TI OMAP Multimedia Card Interface support"
-	depends on ARCH_OMAP && MMC
+	depends on ARCH_OMAP
 	select TPS65010 if MACH_OMAP_H2
 	help
 	  This selects the TI OMAP Multimedia card Interface.
@@ -49,7 +48,7 @@
 
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
-	depends on MMC && ISA_DMA_API
+	depends on ISA_DMA_API
 	help
 	  This selects the Winbond(R) W83L51xD Secure digital and
           Multimedia card Interface.
@@ -60,7 +59,7 @@
 
 config MMC_AU1X
 	tristate "Alchemy AU1XX0 MMC Card Interface support"
-	depends on MMC && SOC_AU1200
+	depends on SOC_AU1200
 	help
 	  This selects the AMD Alchemy(R) Multimedia card interface.
 	  If you have a Alchemy platform with a MMC slot, say Y or M here.
@@ -69,7 +68,7 @@
 
 config MMC_AT91
 	tristate "AT91 SD/MMC Card Interface support"
-	depends on ARCH_AT91 && MMC
+	depends on ARCH_AT91
 	help
 	  This selects the AT91 MCI controller.
 
@@ -77,7 +76,7 @@
 
 config MMC_IMX
 	tristate "Motorola i.MX Multimedia Card Interface support"
-	depends on ARCH_IMX && MMC
+	depends on ARCH_IMX
 	help
 	  This selects the Motorola i.MX Multimedia card Interface.
 	  If you have a i.MX platform with a Multimedia Card slot,
@@ -87,7 +86,7 @@
 
 config MMC_TIFM_SD
 	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
-	depends on MMC && EXPERIMENTAL && PCI
+	depends on EXPERIMENTAL && PCI
 	select TIFM_CORE
 	help
 	  Say Y here if you want to be able to access MMC/SD cards with
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 7511f96..8b736e9 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -1021,10 +1021,6 @@
 	mmc_remove_host(mmc);
 	dev_dbg(&sock->dev, "after remove\n");
 
-	/* The meaning of the bit majority in this constant is unknown. */
-	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-
 	mmc_free_host(mmc);
 }
 
@@ -1032,14 +1028,7 @@
 
 static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	int rc;
-
-	rc = mmc_suspend_host(mmc, state);
-	/* The meaning of the bit majority in this constant is unknown. */
-	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-	return rc;
+	return mmc_suspend_host(tifm_get_drvdata(sock), state);
 }
 
 static int tifm_sd_resume(struct tifm_dev *sock)
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index d28e0fc..479d32b 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,4 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $
 
 menu "RAM/ROM/Flash chip drivers"
 	depends on MTD!=n
@@ -231,45 +230,6 @@
 	  the system regardless of media presence.  Device nodes created
 	  with this driver will return -ENODEV upon access.
 
-config MTD_OBSOLETE_CHIPS
-	bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
-	help
-	  This option does not enable any code directly, but will allow you to
-	  select some other chip drivers which are now considered obsolete,
-	  because the generic CONFIG_JEDECPROBE code above should now detect
-	  the chips which are supported by these drivers, and allow the generic
-	  CFI-compatible drivers to drive the chips. Say 'N' here unless you have
-	  already tried the CONFIG_JEDECPROBE method and reported its failure
-	  to the MTD mailing list at <linux-mtd@lists.infradead.org>
-
-config MTD_AMDSTD
-	tristate "AMD compatible flash chip support (non-CFI)"
-	depends on MTD_OBSOLETE_CHIPS && BROKEN
-	help
-	  This option enables support for flash chips using AMD-compatible
-	  commands, including some which are not CFI-compatible and hence
-	  cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
-	  It also works on AMD compatible chips that do conform to CFI.
-
-config MTD_SHARP
-	tristate "pre-CFI Sharp chip support"
-	depends on MTD_OBSOLETE_CHIPS
-	help
-	  This option enables support for flash chips using Sharp-compatible
-	  commands, including some which are not CFI-compatible and hence
-	  cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
-
-config MTD_JEDEC
-	tristate "JEDEC device support"
-	depends on MTD_OBSOLETE_CHIPS && BROKEN
-	help
-	  Enable older JEDEC flash interface devices for self
-	  programming flash.  It is commonly used in older AMD chips.  It is
-	  only called JEDEC because the JEDEC association
-	  <http://www.jedec.org/> distributes the identification codes for the
-	  chips.
-
 config MTD_XIP
 	bool "XIP aware MTD support"
 	depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
index 75bc1c2..3658241 100644
--- a/drivers/mtd/chips/Makefile
+++ b/drivers/mtd/chips/Makefile
@@ -1,19 +1,15 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
 
 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
 obj-$(CONFIG_MTD_GEN_PROBE)	+= gen_probe.o
-obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
 obj-$(CONFIG_MTD_JEDECPROBE)	+= jedec_probe.o
 obj-$(CONFIG_MTD_RAM)		+= map_ram.o
 obj-$(CONFIG_MTD_ROM)		+= map_rom.o
-obj-$(CONFIG_MTD_SHARP)		+= sharp.o
 obj-$(CONFIG_MTD_ABSENT)	+= map_absent.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
deleted file mode 100644
index e7999f1..0000000
--- a/drivers/mtd/chips/amd_flash.c
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- * MTD map driver for AMD compatible flash chips (non-CFI)
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
- * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
- *
- * Copyright (c) 2001 Axis Communications AB
- *
- * This file is under GPL.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/flashchip.h>
-
-/* There's no limit. It exists only to avoid realloc. */
-#define MAX_AMD_CHIPS 8
-
-#define DEVICE_TYPE_X8	(8 / 8)
-#define DEVICE_TYPE_X16	(16 / 8)
-#define DEVICE_TYPE_X32	(32 / 8)
-
-/* Addresses */
-#define ADDR_MANUFACTURER		0x0000
-#define ADDR_DEVICE_ID			0x0001
-#define ADDR_SECTOR_LOCK		0x0002
-#define ADDR_HANDSHAKE			0x0003
-#define ADDR_UNLOCK_1			0x0555
-#define ADDR_UNLOCK_2			0x02AA
-
-/* Commands */
-#define CMD_UNLOCK_DATA_1		0x00AA
-#define CMD_UNLOCK_DATA_2		0x0055
-#define CMD_MANUFACTURER_UNLOCK_DATA	0x0090
-#define CMD_UNLOCK_BYPASS_MODE		0x0020
-#define CMD_PROGRAM_UNLOCK_DATA		0x00A0
-#define CMD_RESET_DATA			0x00F0
-#define CMD_SECTOR_ERASE_UNLOCK_DATA	0x0080
-#define CMD_SECTOR_ERASE_UNLOCK_DATA_2	0x0030
-
-#define CMD_UNLOCK_SECTOR		0x0060
-
-/* Manufacturers */
-#define MANUFACTURER_AMD	0x0001
-#define MANUFACTURER_ATMEL	0x001F
-#define MANUFACTURER_FUJITSU	0x0004
-#define MANUFACTURER_ST		0x0020
-#define MANUFACTURER_SST	0x00BF
-#define MANUFACTURER_TOSHIBA	0x0098
-
-/* AMD */
-#define AM29F800BB	0x2258
-#define AM29F800BT	0x22D6
-#define AM29LV800BB	0x225B
-#define AM29LV800BT	0x22DA
-#define AM29LV160DT	0x22C4
-#define AM29LV160DB	0x2249
-#define AM29BDS323D     0x22D1
-
-/* Atmel */
-#define AT49xV16x	0x00C0
-#define AT49xV16xT	0x00C2
-
-/* Fujitsu */
-#define MBM29LV160TE	0x22C4
-#define MBM29LV160BE	0x2249
-#define MBM29LV800BB	0x225B
-
-/* ST - www.st.com */
-#define M29W800T	0x00D7
-#define M29W160DT	0x22C4
-#define M29W160DB	0x2249
-
-/* SST */
-#define SST39LF800	0x2781
-#define SST39LF160	0x2782
-
-/* Toshiba */
-#define TC58FVT160	0x00C2
-#define TC58FVB160	0x0043
-
-#define D6_MASK	0x40
-
-struct amd_flash_private {
-	int device_type;
-	int interleave;
-	int numchips;
-	unsigned long chipshift;
-	struct flchip chips[0];
-};
-
-struct amd_flash_info {
-	const __u16 mfr_id;
-	const __u16 dev_id;
-	const char *name;
-	const u_long size;
-	const int numeraseregions;
-	const struct mtd_erase_region_info regions[4];
-};
-
-
-
-static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
-			  u_char *);
-static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
-			   const u_char *);
-static int amd_flash_erase(struct mtd_info *, struct erase_info *);
-static void amd_flash_sync(struct mtd_info *);
-static int amd_flash_suspend(struct mtd_info *);
-static void amd_flash_resume(struct mtd_info *);
-static void amd_flash_destroy(struct mtd_info *);
-static struct mtd_info *amd_flash_probe(struct map_info *map);
-
-
-static struct mtd_chip_driver amd_flash_chipdrv = {
-	.probe = amd_flash_probe,
-	.destroy = amd_flash_destroy,
-	.name = "amd_flash",
-	.module = THIS_MODULE
-};
-
-static inline __u32 wide_read(struct map_info *map, __u32 addr)
-{
-	if (map->buswidth == 1) {
-		return map_read8(map, addr);
-	} else if (map->buswidth == 2) {
-		return map_read16(map, addr);
-	} else if (map->buswidth == 4) {
-		return map_read32(map, addr);
-        }
-
-	return 0;
-}
-
-static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
-{
-	if (map->buswidth == 1) {
-		map_write8(map, val, addr);
-	} else if (map->buswidth == 2) {
-		map_write16(map, val, addr);
-	} else if (map->buswidth == 4) {
-		map_write32(map, val, addr);
-	}
-}
-
-static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
-{
-	const struct amd_flash_private *private = map->fldrv_priv;
-	if ((private->interleave == 2) &&
-	    (private->device_type == DEVICE_TYPE_X16)) {
-		cmd |= (cmd << 16);
-	}
-
-	return cmd;
-}
-
-static inline void send_unlock(struct map_info *map, unsigned long base)
-{
-	wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
-		   base + (map->buswidth * ADDR_UNLOCK_1));
-	wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
-		   base + (map->buswidth * ADDR_UNLOCK_2));
-}
-
-static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
-{
-	send_unlock(map, base);
-	wide_write(map, make_cmd(map, cmd),
-		   base + (map->buswidth * ADDR_UNLOCK_1));
-}
-
-static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
-				    __u32 cmd, unsigned long addr)
-{
-	send_unlock(map, base);
-	wide_write(map, make_cmd(map, cmd), addr);
-}
-
-static inline int flash_is_busy(struct map_info *map, unsigned long addr,
-				int interleave)
-{
-
-	if ((interleave == 2) && (map->buswidth == 4)) {
-		__u32 read1, read2;
-
-		read1 = wide_read(map, addr);
-		read2 = wide_read(map, addr);
-
-		return (((read1 >> 16) & D6_MASK) !=
-			((read2 >> 16) & D6_MASK)) ||
-		       (((read1 & 0xffff) & D6_MASK) !=
-			((read2 & 0xffff) & D6_MASK));
-	}
-
-	return ((wide_read(map, addr) & D6_MASK) !=
-		(wide_read(map, addr) & D6_MASK));
-}
-
-static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
-				 int unlock)
-{
-	/* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
-	int SLA = unlock ?
-		(sect_addr |  (0x40 * map->buswidth)) :
-		(sect_addr & ~(0x40 * map->buswidth)) ;
-
-	__u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
-
-	wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
-	wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
-	wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
-	wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
-}
-
-static inline int is_sector_locked(struct map_info *map,
-				   unsigned long sect_addr)
-{
-	int status;
-
-	wide_write(map, CMD_RESET_DATA, 0);
-	send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
-
-	/* status is 0x0000 for unlocked and 0x0001 for locked */
-	status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
-	wide_write(map, CMD_RESET_DATA, 0);
-	return status;
-}
-
-static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
-			       int is_unlock)
-{
-	struct map_info *map;
-	struct mtd_erase_region_info *merip;
-	int eraseoffset, erasesize, eraseblocks;
-	int i;
-	int retval = 0;
-	int lock_status;
-
-	map = mtd->priv;
-
-	/* Pass the whole chip through sector by sector and check for each
-	   sector if the sector and the given interval overlap */
-	for(i = 0; i < mtd->numeraseregions; i++) {
-		merip = &mtd->eraseregions[i];
-
-		eraseoffset = merip->offset;
-		erasesize = merip->erasesize;
-		eraseblocks = merip->numblocks;
-
-		if (ofs > eraseoffset + erasesize)
-			continue;
-
-		while (eraseblocks > 0) {
-			if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
-				unlock_sector(map, eraseoffset, is_unlock);
-
-				lock_status = is_sector_locked(map, eraseoffset);
-
-				if (is_unlock && lock_status) {
-					printk("Cannot unlock sector at address %x length %xx\n",
-					       eraseoffset, merip->erasesize);
-					retval = -1;
-				} else if (!is_unlock && !lock_status) {
-					printk("Cannot lock sector at address %x length %x\n",
-					       eraseoffset, merip->erasesize);
-					retval = -1;
-				}
-			}
-			eraseoffset += erasesize;
-			eraseblocks --;
-		}
-	}
-	return retval;
-}
-
-static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	return amd_flash_do_unlock(mtd, ofs, len, 1);
-}
-
-static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	return amd_flash_do_unlock(mtd, ofs, len, 0);
-}
-
-
-/*
- * Reads JEDEC manufacturer ID and device ID and returns the index of the first
- * matching table entry (-1 if not found or alias for already found chip).
- */
-static int probe_new_chip(struct mtd_info *mtd, __u32 base,
-			  struct flchip *chips,
-			  struct amd_flash_private *private,
-			  const struct amd_flash_info *table, int table_size)
-{
-	__u32 mfr_id;
-	__u32 dev_id;
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private temp;
-	int i;
-
-	temp.device_type = DEVICE_TYPE_X16;	// Assume X16 (FIXME)
-	temp.interleave = 2;
-	map->fldrv_priv = &temp;
-
-	/* Enter autoselect mode. */
-	send_cmd(map, base, CMD_RESET_DATA);
-	send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
-
-	mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
-	dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
-
-	if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
-	    ((dev_id >> 16) == (dev_id & 0xffff))) {
-		mfr_id &= 0xffff;
-		dev_id &= 0xffff;
-	} else {
-		temp.interleave = 1;
-	}
-
-	for (i = 0; i < table_size; i++) {
-		if ((mfr_id == table[i].mfr_id) &&
-		    (dev_id == table[i].dev_id)) {
-			if (chips) {
-				int j;
-
-				/* Is this an alias for an already found chip?
-				 * In that case that chip should be in
-				 * autoselect mode now.
-				 */
-				for (j = 0; j < private->numchips; j++) {
-					__u32 mfr_id_other;
-					__u32 dev_id_other;
-
-					mfr_id_other =
-						wide_read(map, chips[j].start +
-							       (map->buswidth *
-								ADDR_MANUFACTURER
-							       ));
-					dev_id_other =
-						wide_read(map, chips[j].start +
-					    		       (map->buswidth *
-							        ADDR_DEVICE_ID));
-					if (temp.interleave == 2) {
-						mfr_id_other &= 0xffff;
-						dev_id_other &= 0xffff;
-					}
-					if ((mfr_id_other == mfr_id) &&
-					    (dev_id_other == dev_id)) {
-
-						/* Exit autoselect mode. */
-						send_cmd(map, base,
-							 CMD_RESET_DATA);
-
-						return -1;
-					}
-				}
-
-				if (private->numchips == MAX_AMD_CHIPS) {
-					printk(KERN_WARNING
-					       "%s: Too many flash chips "
-					       "detected. Increase "
-					       "MAX_AMD_CHIPS from %d.\n",
-					       map->name, MAX_AMD_CHIPS);
-
-					return -1;
-				}
-
-				chips[private->numchips].start = base;
-				chips[private->numchips].state = FL_READY;
-				chips[private->numchips].mutex =
-					&chips[private->numchips]._spinlock;
-				private->numchips++;
-			}
-
-			printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
-			       temp.interleave, (table[i].size)/(1024*1024),
-			       table[i].name, base);
-
-			mtd->size += table[i].size * temp.interleave;
-			mtd->numeraseregions += table[i].numeraseregions;
-
-			break;
-		}
-	}
-
-	/* Exit autoselect mode. */
-	send_cmd(map, base, CMD_RESET_DATA);
-
-	if (i == table_size) {
-		printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
-		       "mfr id 0x%x, dev id 0x%x\n", map->name,
-		       base, mfr_id, dev_id);
-		map->fldrv_priv = NULL;
-
-		return -1;
-	}
-
-	private->device_type = temp.device_type;
-	private->interleave = temp.interleave;
-
-	return i;
-}
-
-
-
-static struct mtd_info *amd_flash_probe(struct map_info *map)
-{
-	static const struct amd_flash_info table[] = {
-	{
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV160DT,
-		.name = "AMD AM29LV160DT",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV160DB,
-		.name = "AMD AM29LV160DB",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_TOSHIBA,
-		.dev_id = TC58FVT160,
-		.name = "Toshiba TC58FVT160",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_FUJITSU,
-		.dev_id = MBM29LV160TE,
-		.name = "Fujitsu MBM29LV160TE",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_TOSHIBA,
-		.dev_id = TC58FVB160,
-		.name = "Toshiba TC58FVB160",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_FUJITSU,
-		.dev_id = MBM29LV160BE,
-		.name = "Fujitsu MBM29LV160BE",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BB,
-		.name = "AMD AM29LV800BB",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29F800BB,
-		.name = "AMD AM29F800BB",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BT,
-		.name = "AMD AM29LV800BT",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29F800BT,
-		.name = "AMD AM29F800BT",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BB,
-		.name = "AMD AM29LV800BB",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_FUJITSU,
-		.dev_id = MBM29LV800BB,
-		.name = "Fujitsu MBM29LV800BB",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W800T,
-		.name = "ST M29W800T",
-		.size = 0x00100000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W160DT,
-		.name = "ST M29W160DT",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W160DB,
-		.name = "ST M29W160DB",
-		.size = 0x00200000,
-		.numeraseregions = 4,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29BDS323D,
-		.name = "AMD AM29BDS323D",
-		.size = 0x00400000,
-		.numeraseregions = 3,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
-			{ .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ATMEL,
-		.dev_id = AT49xV16x,
-		.name = "Atmel AT49xV16x",
-		.size = 0x00200000,
-		.numeraseregions = 2,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x02000, .numblocks =  8 },
-			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ATMEL,
-		.dev_id = AT49xV16xT,
-		.name = "Atmel AT49xV16xT",
-		.size = 0x00200000,
-		.numeraseregions = 2,
-		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
-		}
-	}
-	};
-
-	struct mtd_info *mtd;
-	struct flchip chips[MAX_AMD_CHIPS];
-	int table_pos[MAX_AMD_CHIPS];
-	struct amd_flash_private temp;
-	struct amd_flash_private *private;
-	u_long size;
-	unsigned long base;
-	int i;
-	int reg_idx;
-	int offset;
-
-	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-	if (!mtd) {
-		printk(KERN_WARNING
-		       "%s: kmalloc failed for info structure\n", map->name);
-		return NULL;
-	}
-	mtd->priv = map;
-
-	memset(&temp, 0, sizeof(temp));
-
-	printk("%s: Probing for AMD compatible flash...\n", map->name);
-
-	if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
-					   ARRAY_SIZE(table)))
-	    == -1) {
-		printk(KERN_WARNING
-		       "%s: Found no AMD compatible device at location zero\n",
-		       map->name);
-		kfree(mtd);
-
-		return NULL;
-	}
-
-	chips[0].start = 0;
-	chips[0].state = FL_READY;
-	chips[0].mutex = &chips[0]._spinlock;
-	temp.numchips = 1;
-	for (size = mtd->size; size > 1; size >>= 1) {
-		temp.chipshift++;
-	}
-	switch (temp.interleave) {
-		case 2:
-			temp.chipshift += 1;
-			break;
-		case 4:
-			temp.chipshift += 2;
-			break;
-	}
-
-	/* Find out if there are any more chips in the map. */
-	for (base = (1 << temp.chipshift);
-	     base < map->size;
-	     base += (1 << temp.chipshift)) {
-	     	int numchips = temp.numchips;
-		table_pos[numchips] = probe_new_chip(mtd, base, chips,
-			&temp, table, ARRAY_SIZE(table));
-	}
-
-	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
-				    mtd->numeraseregions, GFP_KERNEL);
-	if (!mtd->eraseregions) {
-		printk(KERN_WARNING "%s: Failed to allocate "
-		       "memory for MTD erase region info\n", map->name);
-		kfree(mtd);
-		map->fldrv_priv = NULL;
-		return NULL;
-	}
-
-	reg_idx = 0;
-	offset = 0;
-	for (i = 0; i < temp.numchips; i++) {
-		int dev_size;
-		int j;
-
-		dev_size = 0;
-		for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
-			mtd->eraseregions[reg_idx].offset = offset +
-				(table[table_pos[i]].regions[j].offset *
-				 temp.interleave);
-			mtd->eraseregions[reg_idx].erasesize =
-				table[table_pos[i]].regions[j].erasesize *
-				temp.interleave;
-			mtd->eraseregions[reg_idx].numblocks =
-				table[table_pos[i]].regions[j].numblocks;
-			if (mtd->erasesize <
-			    mtd->eraseregions[reg_idx].erasesize) {
-				mtd->erasesize =
-					mtd->eraseregions[reg_idx].erasesize;
-			}
-			dev_size += mtd->eraseregions[reg_idx].erasesize *
-				    mtd->eraseregions[reg_idx].numblocks;
-			reg_idx++;
-		}
-		offset += dev_size;
-	}
-	mtd->type = MTD_NORFLASH;
-	mtd->writesize = 1;
-	mtd->flags = MTD_CAP_NORFLASH;
-	mtd->name = map->name;
-	mtd->erase = amd_flash_erase;
-	mtd->read = amd_flash_read;
-	mtd->write = amd_flash_write;
-	mtd->sync = amd_flash_sync;
-	mtd->suspend = amd_flash_suspend;
-	mtd->resume = amd_flash_resume;
-	mtd->lock = amd_flash_lock;
-	mtd->unlock = amd_flash_unlock;
-
-	private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
-					      temp.numchips), GFP_KERNEL);
-	if (!private) {
-		printk(KERN_WARNING
-		       "%s: kmalloc failed for private structure\n", map->name);
-		kfree(mtd);
-		map->fldrv_priv = NULL;
-		return NULL;
-	}
-	memcpy(private, &temp, sizeof(temp));
-	memcpy(private->chips, chips,
-	       sizeof(struct flchip) * private->numchips);
-	for (i = 0; i < private->numchips; i++) {
-		init_waitqueue_head(&private->chips[i].wq);
-		spin_lock_init(&private->chips[i]._spinlock);
-	}
-
-	map->fldrv_priv = private;
-
-	map->fldrv = &amd_flash_chipdrv;
-
-	__module_get(THIS_MODULE);
-	return mtd;
-}
-
-
-
-static inline int read_one_chip(struct map_info *map, struct flchip *chip,
-			       loff_t adr, size_t len, u_char *buf)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long timeo = jiffies + HZ;
-
-retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-		printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
-		       map->name, chip->state);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current)) {
-			return -EINTR;
-		}
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-
-	adr += chip->start;
-
-	chip->state = FL_READY;
-
-	map_copy_from(map, buf, adr, len);
-
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return 0;
-}
-
-
-
-static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
-			  size_t *retlen, u_char *buf)
-{
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private *private = map->fldrv_priv;
-	unsigned long ofs;
-	int chipnum;
-	int ret = 0;
-
-	if ((from + len) > mtd->size) {
-		printk(KERN_WARNING "%s: read request past end of device "
-		       "(0x%lx)\n", map->name, (unsigned long)from + len);
-
-		return -EINVAL;
-	}
-
-	/* Offset within the first chip that the first read should start. */
-	chipnum = (from >> private->chipshift);
-	ofs = from - (chipnum <<  private->chipshift);
-
-	*retlen = 0;
-
-	while (len) {
-		unsigned long this_len;
-
-		if (chipnum >= private->numchips) {
-			break;
-		}
-
-		if ((len + ofs - 1) >> private->chipshift) {
-			this_len = (1 << private->chipshift) - ofs;
-		} else {
-			this_len = len;
-		}
-
-		ret = read_one_chip(map, &private->chips[chipnum], ofs,
-				    this_len, buf);
-		if (ret) {
-			break;
-		}
-
-		*retlen += this_len;
-		len -= this_len;
-		buf += this_len;
-
-		ofs = 0;
-		chipnum++;
-	}
-
-	return ret;
-}
-
-
-
-static int write_one_word(struct map_info *map, struct flchip *chip,
-			  unsigned long adr, __u32 datum)
-{
-	unsigned long timeo = jiffies + HZ;
-	struct amd_flash_private *private = map->fldrv_priv;
-	DECLARE_WAITQUEUE(wait, current);
-	int ret = 0;
-	int times_left;
-
-retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-		printk("%s: waiting for chip to write, state = %d\n",
-		       map->name, chip->state);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		printk(KERN_INFO "%s: woke up to write\n", map->name);
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-
-	chip->state = FL_WRITING;
-
-	adr += chip->start;
-	ENABLE_VPP(map);
-	send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
-	wide_write(map, datum, adr);
-
-	times_left = 500000;
-	while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
-		if (need_resched()) {
-			spin_unlock_bh(chip->mutex);
-			schedule();
-			spin_lock_bh(chip->mutex);
-		}
-	}
-
-	if (!times_left) {
-		printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
-		       map->name, adr);
-		ret = -EIO;
-	} else {
-		__u32 verify;
-		if ((verify = wide_read(map, adr)) != datum) {
-			printk(KERN_WARNING "%s: write to 0x%lx failed. "
-			       "datum = %x, verify = %x\n",
-			       map->name, adr, datum, verify);
-			ret = -EIO;
-		}
-	}
-
-	DISABLE_VPP(map);
-	chip->state = FL_READY;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return ret;
-}
-
-
-
-static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
-			   size_t *retlen, const u_char *buf)
-{
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private *private = map->fldrv_priv;
-	int ret = 0;
-	int chipnum;
-	unsigned long ofs;
-	unsigned long chipstart;
-
-	*retlen = 0;
-	if (!len) {
-		return 0;
-	}
-
-	chipnum = to >> private->chipshift;
-	ofs = to  - (chipnum << private->chipshift);
-	chipstart = private->chips[chipnum].start;
-
-	/* If it's not bus-aligned, do the first byte write. */
-	if (ofs & (map->buswidth - 1)) {
-		unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
-		int i = ofs - bus_ofs;
-		int n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
-
-		map_copy_from(map, tmp_buf,
-			       bus_ofs + private->chips[chipnum].start,
-			       map->buswidth);
-		while (len && i < map->buswidth)
-			tmp_buf[i++] = buf[n++], len--;
-
-		if (map->buswidth == 2) {
-			datum = *(__u16*)tmp_buf;
-		} else if (map->buswidth == 4) {
-			datum = *(__u32*)tmp_buf;
-		} else {
-			return -EINVAL;  /* should never happen, but be safe */
-		}
-
-		ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
-				     datum);
-		if (ret) {
-			return ret;
-		}
-
-		ofs += n;
-		buf += n;
-		(*retlen) += n;
-
-		if (ofs >> private->chipshift) {
-			chipnum++;
-			ofs = 0;
-			if (chipnum == private->numchips) {
-				return 0;
-			}
-		}
-	}
-
-	/* We are now aligned, write as much as possible. */
-	while(len >= map->buswidth) {
-		__u32 datum;
-
-		if (map->buswidth == 1) {
-			datum = *(__u8*)buf;
-		} else if (map->buswidth == 2) {
-			datum = *(__u16*)buf;
-		} else if (map->buswidth == 4) {
-			datum = *(__u32*)buf;
-		} else {
-			return -EINVAL;
-		}
-
-		ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-		if (ret) {
-			return ret;
-		}
-
-		ofs += map->buswidth;
-		buf += map->buswidth;
-		(*retlen) += map->buswidth;
-		len -= map->buswidth;
-
-		if (ofs >> private->chipshift) {
-			chipnum++;
-			ofs = 0;
-			if (chipnum == private->numchips) {
-				return 0;
-			}
-			chipstart = private->chips[chipnum].start;
-		}
-	}
-
-	if (len & (map->buswidth - 1)) {
-		int i = 0, n = 0;
-		u_char tmp_buf[2];
-		__u32 datum;
-
-		map_copy_from(map, tmp_buf,
-			       ofs + private->chips[chipnum].start,
-			       map->buswidth);
-		while (len--) {
-			tmp_buf[i++] = buf[n++];
-		}
-
-		if (map->buswidth == 2) {
-			datum = *(__u16*)tmp_buf;
-		} else if (map->buswidth == 4) {
-			datum = *(__u32*)tmp_buf;
-		} else {
-			return -EINVAL;  /* should never happen, but be safe */
-		}
-
-		ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-		if (ret) {
-			return ret;
-		}
-
-		(*retlen) += n;
-	}
-
-	return 0;
-}
-
-
-
-static inline int erase_one_block(struct map_info *map, struct flchip *chip,
-				  unsigned long adr, u_long size)
-{
-	unsigned long timeo = jiffies + HZ;
-	struct amd_flash_private *private = map->fldrv_priv;
-	DECLARE_WAITQUEUE(wait, current);
-
-retry:
-	spin_lock_bh(chip->mutex);
-
-	if (chip->state != FL_READY){
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if (signal_pending(current)) {
-			return -EINTR;
-		}
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-
-	chip->state = FL_ERASING;
-
-	adr += chip->start;
-	ENABLE_VPP(map);
-	send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
-	send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
-
-	timeo = jiffies + (HZ * 20);
-
-	spin_unlock_bh(chip->mutex);
-	msleep(1000);
-	spin_lock_bh(chip->mutex);
-
-	while (flash_is_busy(map, adr, private->interleave)) {
-
-		if (chip->state != FL_ERASING) {
-			/* Someone's suspended the erase. Sleep */
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			add_wait_queue(&chip->wq, &wait);
-
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_INFO "%s: erase suspended. Sleeping\n",
-			       map->name);
-			schedule();
-			remove_wait_queue(&chip->wq, &wait);
-
-			if (signal_pending(current)) {
-				return -EINTR;
-			}
-
-			timeo = jiffies + (HZ*2); /* FIXME */
-			spin_lock_bh(chip->mutex);
-			continue;
-		}
-
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_READY;
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_WARNING "%s: waiting for erase to complete "
-			       "timed out.\n", map->name);
-			DISABLE_VPP(map);
-
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-
-		if (need_resched())
-			schedule();
-		else
-			udelay(1);
-
-		spin_lock_bh(chip->mutex);
-	}
-
-	/* Verify every single word */
-	{
-		int address;
-		int error = 0;
-		__u8 verify;
-
-		for (address = adr; address < (adr + size); address++) {
-			if ((verify = map_read8(map, address)) != 0xFF) {
-				error = 1;
-				break;
-			}
-		}
-		if (error) {
-			chip->state = FL_READY;
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_WARNING
-			       "%s: verify error at 0x%x, size %ld.\n",
-			       map->name, address, size);
-			DISABLE_VPP(map);
-
-			return -EIO;
-		}
-	}
-
-	DISABLE_VPP(map);
-	chip->state = FL_READY;
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return 0;
-}
-
-
-
-static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private *private = map->fldrv_priv;
-	unsigned long adr, len;
-	int chipnum;
-	int ret = 0;
-	int i;
-	int 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 >> private->chipshift;
-	adr = instr->addr - (chipnum << private->chipshift);
-	len = instr->len;
-
-	i = first;
-
-	while (len) {
-		ret = erase_one_block(map, &private->chips[chipnum], adr,
-				      regions[i].erasesize);
-
-		if (ret) {
-			return ret;
-		}
-
-		adr += regions[i].erasesize;
-		len -= regions[i].erasesize;
-
-		if ((adr % (1 << private->chipshift)) ==
-		    ((regions[i].offset + (regions[i].erasesize *
-		    			   regions[i].numblocks))
-		     % (1 << private->chipshift))) {
-			i++;
-		}
-
-		if (adr >> private->chipshift) {
-			adr = 0;
-			chipnum++;
-			if (chipnum >= private->numchips) {
-				break;
-			}
-		}
-	}
-
-	instr->state = MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
-
-	return 0;
-}
-
-
-
-static void amd_flash_sync(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private *private = map->fldrv_priv;
-	int i;
-	struct flchip *chip;
-	int ret = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
-	for (i = 0; !ret && (i < private->numchips); i++) {
-		chip = &private->chips[i];
-
-	retry:
-		spin_lock_bh(chip->mutex);
-
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
-			chip->oldstate = chip->state;
-			chip->state = FL_SYNCING;
-			/* No need to wake_up() on this state change -
-			 * as the whole point is that nobody can do anything
-			 * with the chip now anyway.
-			 */
-		case FL_SYNCING:
-			spin_unlock_bh(chip->mutex);
-			break;
-
-		default:
-			/* Not an idle state */
-			add_wait_queue(&chip->wq, &wait);
-
-			spin_unlock_bh(chip->mutex);
-
-			schedule();
-
-		        remove_wait_queue(&chip->wq, &wait);
-
-			goto retry;
-		}
-	}
-
-	/* Unlock the chips again */
-	for (i--; i >= 0; i--) {
-		chip = &private->chips[i];
-
-		spin_lock_bh(chip->mutex);
-
-		if (chip->state == FL_SYNCING) {
-			chip->state = chip->oldstate;
-			wake_up(&chip->wq);
-		}
-		spin_unlock_bh(chip->mutex);
-	}
-}
-
-
-
-static int amd_flash_suspend(struct mtd_info *mtd)
-{
-printk("amd_flash_suspend(): not implemented!\n");
-	return -EINVAL;
-}
-
-
-
-static void amd_flash_resume(struct mtd_info *mtd)
-{
-printk("amd_flash_resume(): not implemented!\n");
-}
-
-
-
-static void amd_flash_destroy(struct mtd_info *mtd)
-{
-	struct map_info *map = mtd->priv;
-	struct amd_flash_private *private = map->fldrv_priv;
-	kfree(private);
-}
-
-int __init amd_flash_init(void)
-{
-	register_mtd_chip_driver(&amd_flash_chipdrv);
-	return 0;
-}
-
-void __exit amd_flash_exit(void)
-{
-	unregister_mtd_chip_driver(&amd_flash_chipdrv);
-}
-
-module_init(amd_flash_init);
-module_exit(amd_flash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
-MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
deleted file mode 100644
index 14e57b2..0000000
--- a/drivers/mtd/chips/jedec.c
+++ /dev/null
@@ -1,935 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * This code does not support anything wider than 8 bit flash chips, I am
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
- * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mtd/jedec.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-
-static struct mtd_info *jedec_probe(struct map_info *);
-static int jedec_probe8(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-static int jedec_probe16(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-static int jedec_probe32(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv);
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-			    unsigned long len);
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-		       size_t *retlen, const u_char *buf);
-
-static unsigned long my_bank_size;
-
-/* Listing of parts and sizes. We need this table to learn the sector
-   size of the chip and the total length */
-static const struct JEDECTable JEDEC_table[] = {
-	{
-		.jedec		= 0x013D,
-		.name		= "AMD Am29F017D",
-		.size		= 2*1024*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{
-		.jedec		= 0x01AD,
-		.name		= "AMD Am29F016",
-		.size		= 2*1024*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{
-		.jedec		= 0x01D5,
-		.name		= "AMD Am29F080",
-		.size		= 1*1024*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{
-		.jedec		= 0x01A4,
-		.name		= "AMD Am29F040",
-		.size		= 512*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{
-		.jedec		= 0x20E3,
-		.name		= "AMD Am29W040B",
-		.size		= 512*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{
-		.jedec		= 0xC2AD,
-		.name		= "Macronix MX29F016",
-		.size		= 2*1024*1024,
-		.sectorsize	= 64*1024,
-		.capabilities	= MTD_CAP_NORFLASH
-	},
-	{ .jedec = 0x0 }
-};
-
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
-static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-		      size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-			     size_t *retlen, u_char *buf);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-
-
-static struct mtd_chip_driver jedec_chipdrv = {
-	.probe	= jedec_probe,
-	.name	= "jedec",
-	.module	= THIS_MODULE
-};
-
-/* Probe entry point */
-
-static struct mtd_info *jedec_probe(struct map_info *map)
-{
-   struct mtd_info *MTD;
-   struct jedec_private *priv;
-   unsigned long Base;
-   unsigned long SectorSize;
-   unsigned count;
-   unsigned I,Uniq;
-   char Part[200];
-   memset(&priv,0,sizeof(priv));
-
-   MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
-   if (!MTD)
-	   return NULL;
-
-   priv = (struct jedec_private *)&MTD[1];
-
-   my_bank_size = map->size;
-
-   if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
-      kfree(MTD);
-      return NULL;
-   }
-
-   for (Base = 0; Base < map->size; Base += my_bank_size)
-   {
-      // Perhaps zero could designate all tests?
-      if (map->buswidth == 0)
-	 map->buswidth = 1;
-
-      if (map->buswidth == 1){
-	 if (jedec_probe8(map,Base,priv) == 0) {
-		 printk("did recognize jedec chip\n");
-		 kfree(MTD);
-	         return NULL;
-	 }
-      }
-      if (map->buswidth == 2)
-	 jedec_probe16(map,Base,priv);
-      if (map->buswidth == 4)
-	 jedec_probe32(map,Base,priv);
-   }
-
-   // Get the biggest sector size
-   SectorSize = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-	   //	   printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
-	   //	   printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
-      if (priv->chips[I].sectorsize > SectorSize)
-	 SectorSize = priv->chips[I].sectorsize;
-   }
-
-   // Quickly ensure that the other sector sizes are factors of the largest
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
-      {
-	 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
-	 kfree(MTD);
-	 return NULL;
-      }
-   }
-
-   /* Generate a part name that includes the number of different chips and
-      other configuration information */
-   count = 1;
-   strlcpy(Part,map->name,sizeof(Part)-10);
-   strcat(Part," ");
-   Uniq = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      const struct JEDECTable *JEDEC;
-
-      if (priv->chips[I+1].jedec == priv->chips[I].jedec)
-      {
-	 count++;
-	 continue;
-      }
-
-      // Locate the chip in the jedec table
-      JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
-      if (JEDEC == 0)
-      {
-	 printk("mtd: Internal Error, JEDEC not set\n");
-	 kfree(MTD);
-	 return NULL;
-      }
-
-      if (Uniq != 0)
-	 strcat(Part,",");
-      Uniq++;
-
-      if (count != 1)
-	 sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
-      else
-	 sprintf(Part+strlen(Part),"%s",JEDEC->name);
-      if (strlen(Part) > sizeof(Part)*2/3)
-	 break;
-      count = 1;
-   }
-
-   /* Determine if the chips are organized in a linear fashion, or if there
-      are empty banks. Note, the last bank does not count here, only the
-      first banks are important. Holes on non-bank boundaries can not exist
-      due to the way the detection algorithm works. */
-   if (priv->size < my_bank_size)
-      my_bank_size = priv->size;
-   priv->is_banked = 0;
-   //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
-   //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
-   if (!priv->size) {
-	   printk("priv->size is zero\n");
-	   kfree(MTD);
-	   return NULL;
-   }
-   if (priv->size/my_bank_size) {
-	   if (priv->size/my_bank_size == 1) {
-		   priv->size = my_bank_size;
-	   }
-	   else {
-		   for (I = 0; I != priv->size/my_bank_size - 1; I++)
-		   {
-		      if (priv->bank_fill[I] != my_bank_size)
-			 priv->is_banked = 1;
-
-		      /* This even could be eliminated, but new de-optimized read/write
-			 functions have to be written */
-		      printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
-		      if (priv->bank_fill[I] != priv->bank_fill[0])
-		      {
-			 printk("mtd: Failed. Cannot handle unsymmetric banking\n");
-			 kfree(MTD);
-			 return NULL;
-		      }
-		   }
-	   }
-   }
-   if (priv->is_banked == 1)
-      strcat(Part,", banked");
-
-   //   printk("Part: '%s'\n",Part);
-
-   memset(MTD,0,sizeof(*MTD));
-  // strlcpy(MTD->name,Part,sizeof(MTD->name));
-   MTD->name = map->name;
-   MTD->type = MTD_NORFLASH;
-   MTD->flags = MTD_CAP_NORFLASH;
-   MTD->writesize = 1;
-   MTD->erasesize = SectorSize*(map->buswidth);
-   //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
-   MTD->size = priv->size;
-   //   printk("MTD->size is %x\n",(unsigned int)MTD->size);
-   //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
-   MTD->erase = flash_erase;
-   if (priv->is_banked == 1)
-      MTD->read = jedec_read_banked;
-   else
-      MTD->read = jedec_read;
-   MTD->write = flash_write;
-   MTD->sync = jedec_sync;
-   MTD->priv = map;
-   map->fldrv_priv = priv;
-   map->fldrv = &jedec_chipdrv;
-   __module_get(THIS_MODULE);
-   return MTD;
-}
-
-/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
-static int checkparity(u_char C)
-{
-   u_char parity = 0;
-   while (C != 0)
-   {
-      parity ^= C & 1;
-      C >>= 1;
-   }
-
-   return parity == 1;
-}
-
-
-/* Take an array of JEDEC numbers that represent interleved flash chips
-   and process them. Check to make sure they are good JEDEC numbers, look
-   them up and then add them to the chip list */
-static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
-		  unsigned long base,struct jedec_private *priv)
-{
-   unsigned I,J;
-   unsigned long Size;
-   unsigned long SectorSize;
-   const struct JEDECTable *JEDEC;
-
-   // Test #2 JEDEC numbers exhibit odd parity
-   for (I = 0; I != Count; I++)
-   {
-      if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
-	 return 0;
-   }
-
-   // Finally, just make sure all the chip sizes are the same
-   JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-
-   if (JEDEC == 0)
-   {
-      printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-      return 0;
-   }
-
-   Size = JEDEC->size;
-   SectorSize = JEDEC->sectorsize;
-   for (I = 0; I != Count; I++)
-   {
-      JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-      if (JEDEC == 0)
-      {
-	 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-	 return 0;
-      }
-
-      if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
-      {
-	 printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
-	 return 0;
-      }
-   }
-
-   // Load the Chips
-   for (I = 0; I != MAX_JEDEC_CHIPS; I++)
-   {
-      if (priv->chips[I].jedec == 0)
-	 break;
-   }
-
-   if (I + Count > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
-      return 0;
-   }
-
-   // Add them to the table
-   for (J = 0; J != Count; J++)
-   {
-      unsigned long Bank;
-
-      JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
-      priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
-      priv->chips[I].size = JEDEC->size;
-      priv->chips[I].sectorsize = JEDEC->sectorsize;
-      priv->chips[I].base = base + J;
-      priv->chips[I].datashift = J*8;
-      priv->chips[I].capabilities = JEDEC->capabilities;
-      priv->chips[I].offset = priv->size + J;
-
-      // log2 n :|
-      priv->chips[I].addrshift = 0;
-      for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-
-      // Determine how filled this bank is.
-      Bank = base & (~(my_bank_size-1));
-      if (priv->bank_fill[Bank/my_bank_size] < base +
-	  (JEDEC->size << priv->chips[I].addrshift) - Bank)
-	 priv->bank_fill[Bank/my_bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
-      I++;
-   }
-
-   priv->size += priv->chips[I-1].size*Count;
-
-   return priv->chips[I-1].size;
-}
-
-/* Lookup the chip information from the JEDEC ID table. */
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
-{
-   __u16 Id = (mfr << 8) | id;
-   unsigned long I = 0;
-   for (I = 0; JEDEC_table[I].jedec != 0; I++)
-      if (JEDEC_table[I].jedec == Id)
-	 return JEDEC_table + I;
-   return NULL;
-}
-
-// Look for flash using an 8 bit bus interface
-static int jedec_probe8(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv)
-{
-   #define flread(x) map_read8(map,base+x)
-   #define flwrite(v,x) map_write8(map,v,base+x)
-
-   const unsigned long AutoSel1 = 0xAA;
-   const unsigned long AutoSel2 = 0x55;
-   const unsigned long AutoSel3 = 0x90;
-   const unsigned long Reset = 0xF0;
-   __u32 OldVal;
-   __u8 Mfg[1];
-   __u8 Id[1];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   //  Get the JEDEC numbers
-   Mfg[0] = flread(0);
-   Id[0] = flread(1);
-   //   printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
-
-   Size = handle_jedecs(map,Mfg,Id,1,base,priv);
-   //   printk("handle_jedecs Size is %x\n",(unsigned int)Size);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-
-   // Reset.
-   flwrite(Reset,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
-static int jedec_probe16(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv)
-{
-   return 0;
-}
-
-// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
-static int jedec_probe32(struct map_info *map,unsigned long base,
-		  struct jedec_private *priv)
-{
-   #define flread(x) map_read32(map,base+((x)<<2))
-   #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
-   const unsigned long AutoSel1 = 0xAAAAAAAA;
-   const unsigned long AutoSel2 = 0x55555555;
-   const unsigned long AutoSel3 = 0x90909090;
-   const unsigned long Reset = 0xF0F0F0F0;
-   __u32 OldVal;
-   __u8 Mfg[4];
-   __u8 Id[4];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   // Test #1, JEDEC numbers are readable from 0x??00/0x??01
-   if (flread(0) != flread(0x100) ||
-       flread(1) != flread(0x101))
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   // Split up the JEDEC numbers
-   OldVal = flread(0);
-   for (I = 0; I != 4; I++)
-      Mfg[I] = (OldVal >> (I*8));
-   OldVal = flread(1);
-   for (I = 0; I != 4; I++)
-      Id[I] = (OldVal >> (I*8));
-
-   Size = handle_jedecs(map,Mfg,Id,4,base,priv);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   /* Check if there is address wrap around within a single bank, if this
-      returns JEDEC numbers then we assume that it is wrap around. Notice
-      we call this routine with the JEDEC return still enabled, if two or
-      more flashes have a truncated address space the probe test will still
-      work */
-   if (base + (Size<<2)+0x555 < map->size &&
-       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
-   {
-      if (flread(base+Size) != flread(base+Size + 0x100) ||
-	  flread(base+Size + 1) != flread(base+Size + 0x101))
-      {
-	 jedec_probe32(map,base+Size,priv);
-      }
-   }
-
-   // Reset.
-   flwrite(0xF0F0F0F0,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* Linear read. */
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-		      size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-
-   map_copy_from(map, buf, from, len);
-   *retlen = len;
-   return 0;
-}
-
-/* Banked read. Take special care to jump past the holes in the bank
-   mapping. This version assumes symetry in the holes.. */
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-			     size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   *retlen = 0;
-   while (len > 0)
-   {
-      // Determine what bank and offset into that bank the first byte is
-      unsigned long bank = from & (~(priv->bank_fill[0]-1));
-      unsigned long offset = from & (priv->bank_fill[0]-1);
-      unsigned long get = len;
-      if (priv->bank_fill[0] - offset < len)
-	 get = priv->bank_fill[0] - offset;
-
-      bank /= priv->bank_fill[0];
-      map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
-      len -= get;
-      *retlen += get;
-      from += get;
-   }
-   return 0;
-}
-
-/* Pass the flags value that the flash return before it re-entered read
-   mode. */
-static void jedec_flash_failed(unsigned char code)
-{
-   /* Bit 5 being high indicates that there was an internal device
-      failure, erasure time limits exceeded or something */
-   if ((code & (1 << 5)) != 0)
-   {
-      printk("mtd: Internal Flash failure\n");
-      return;
-   }
-   printk("mtd: Programming didn't take\n");
-}
-
-/* This uses the erasure function described in the AMD Flash Handbook,
-   it will work for flashes with a fixed sector size only. Flashes with
-   a selection of sector sizes (ie the AMD Am29F800B) will need a different
-   routine. This routine tries to parallize erasing multiple chips/sectors
-   where possible */
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-   // Does IO to the currently selected chip
-   #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
-   unsigned long Time = 0;
-   unsigned long NoTime = 0;
-   unsigned long start = instr->addr, len = instr->len;
-   unsigned int I;
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   // Verify the arguments..
-   if (start + len > mtd->size ||
-       (start % mtd->erasesize) != 0 ||
-       (len % mtd->erasesize) != 0 ||
-       (len/mtd->erasesize) == 0)
-      return -EINVAL;
-
-   jedec_flash_chip_scan(priv,start,len);
-
-   // Start the erase sequence on each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      unsigned long off;
-      struct jedec_flash_chip *chip = priv->chips + I;
-
-      if (chip->length == 0)
-	 continue;
-
-      if (chip->start + chip->length > chip->size)
-      {
-	 printk("DIE\n");
-	 return -EIO;
-      }
-
-      flwrite(0xF0,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-      flwrite(0x80,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-
-      /* Once we start selecting the erase sectors the delay between each
-         command must not exceed 50us or it will immediately start erasing
-         and ignore the other sectors */
-      for (off = 0; off < len; off += chip->sectorsize)
-      {
-	 // Check to make sure we didn't timeout
-	 flwrite(0x30,chip->start + off);
-	 if (off == 0)
-	    continue;
-	 if ((flread(chip->start + off) & (1 << 3)) != 0)
-	 {
-	    printk("mtd: Ack! We timed out the erase timer!\n");
-	    return -EIO;
-	 }
-      }
-   }
-
-   /* We could split this into a timer routine and return early, performing
-      background erasure.. Maybe later if the need warrents */
-
-   /* Poll the flash for erasure completion, specs say this can take as long
-      as 480 seconds to do all the sectors (for a 2 meg flash).
-      Erasure time is dependent on chip age, temp and wear.. */
-
-   /* This being a generic routine assumes a 32 bit bus. It does read32s
-      and bundles interleved chips into the same grouping. This will work
-      for all bus widths */
-   Time = 0;
-   NoTime = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long off = 0;
-      unsigned todo[4] = {0,0,0,0};
-      unsigned todo_left = 0;
-      unsigned J;
-
-      if (chip->length == 0)
-	 continue;
-
-      /* Find all chips in this data line, realistically this is all
-         or nothing up to the interleve count */
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-	     (chip->base & (~((1<<chip->addrshift)-1))))
-	 {
-	    todo_left++;
-	    todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
-	 }
-      }
-
-      /*      printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
-	      (short)todo[2],(short)todo[3]);
-      */
-      while (1)
-      {
-	 __u32 Last[4];
-	 unsigned long Count = 0;
-
-	 /* During erase bit 7 is held low and bit 6 toggles, we watch this,
-	    should it stop toggling or go high then the erase is completed,
-  	    or this is not really flash ;> */
-	 switch (map->buswidth) {
-	 case 1:
-	    Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    break;
-	 case 2:
-	    Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    break;
-	 case 3:
-	    Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    break;
-	 }
-	 Count = 3;
-	 while (todo_left != 0)
-	 {
-	    for (J = 0; J != 4; J++)
-	    {
-	       __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
-	       __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
-	       __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
-	       if (todo[J] == 0)
-		  continue;
-
-	       if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
-	       {
-//		  printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
-		  continue;
-	       }
-
-	       if (Byte1 == Byte2)
-	       {
-		  jedec_flash_failed(Byte3);
-		  return -EIO;
-	       }
-
-	       todo[J] = 0;
-	       todo_left--;
-	    }
-
-/*	    if (NoTime == 0)
-	       Time += HZ/10 - schedule_timeout(HZ/10);*/
-	    NoTime = 0;
-
-	    switch (map->buswidth) {
-	    case 1:
-	       Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	      break;
-	    case 2:
-	       Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	      break;
-	    case 4:
-	       Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	      break;
-	    }
-	    Count++;
-
-/*	    // Count time, max of 15s per sector (according to AMD)
-	    if (Time > 15*len/mtd->erasesize*HZ)
-	    {
-	       printk("mtd: Flash Erase Timed out\n");
-	       return -EIO;
-	    }	    */
-	 }
-
-	 // Skip to the next chip if we used chip erase
-	 if (chip->length == chip->size)
-	    off = chip->size;
-	 else
-	    off += chip->sectorsize;
-
-	 if (off >= chip->length)
-	    break;
-	 NoTime = 1;
-      }
-
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-	 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-	     (chip->base & (~((1<<chip->addrshift)-1))))
-	    priv->chips[J].length = 0;
-      }
-   }
-
-   //printk("done\n");
-   instr->state = MTD_ERASE_DONE;
-   mtd_erase_callback(instr);
-   return 0;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* This is the simple flash writing function. It writes to every byte, in
-   sequence. It takes care of how to properly address the flash if
-   the flash is interleved. It can only be used if all the chips in the
-   array are identical!*/
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-		       size_t *retlen, const u_char *buf)
-{
-   /* Does IO to the currently selected chip. It takes the bank addressing
-      base (which is divisible by the chip size) adds the necessary lower bits
-      of addrshift (interleave index) and then adds the control register index. */
-   #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-   unsigned long base;
-   unsigned long off;
-   size_t save_len = len;
-
-   if (start + len > mtd->size)
-      return -EIO;
-
-   //printk("Here");
-
-   //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
-   while (len != 0)
-   {
-      struct jedec_flash_chip *chip = priv->chips;
-      unsigned long bank;
-      unsigned long boffset;
-
-      // Compute the base of the flash.
-      off = ((unsigned long)start) % (chip->size << chip->addrshift);
-      base = start - off;
-
-      // Perform banked addressing translation.
-      bank = base & (~(priv->bank_fill[0]-1));
-      boffset = base & (priv->bank_fill[0]-1);
-      bank = (bank/priv->bank_fill[0])*my_bank_size;
-      base = bank + boffset;
-
-    //  printk("Flasing %X %X %X\n",base,chip->size,len);
-     // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
-
-      // Loop over this page
-      for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
-      {
-	 unsigned char oldbyte = map_read8(map,base+off);
-	 unsigned char Last[4];
-	 unsigned long Count = 0;
-
-	 if (oldbyte == *buf) {
-	//	 printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
-	    continue;
-	 }
-	 if (((~oldbyte) & *buf) != 0)
-	    printk("mtd: warn: Trying to set a 0 to a 1\n");
-
-	 // Write
-	 flwrite(0xAA,0x555);
-	 flwrite(0x55,0x2AA);
-	 flwrite(0xA0,0x555);
-	 map_write8(map,*buf,base + off);
-	 Last[0] = map_read8(map,base + off);
-	 Last[1] = map_read8(map,base + off);
-	 Last[2] = map_read8(map,base + off);
-
-	 /* Wait for the flash to finish the operation. We store the last 4
-	    status bytes that have been retrieved so we can determine why
-	    it failed. The toggle bits keep toggling when there is a
-	    failure */
-	 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
-	      Count < 10000; Count++)
-	    Last[Count % 4] = map_read8(map,base + off);
-	 if (Last[(Count - 1) % 4] != *buf)
-	 {
-	    jedec_flash_failed(Last[(Count - 3) % 4]);
-	    return -EIO;
-	 }
-      }
-   }
-   *retlen = save_len;
-   return 0;
-}
-
-/* This is used to enhance the speed of the erase routine,
-   when things are being done to multiple chips it is possible to
-   parallize the operations, particularly full memory erases of multi
-   chip memories benifit */
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-		     unsigned long len)
-{
-   unsigned int I;
-
-   // Zero the records
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-      priv->chips[I].start = priv->chips[I].length = 0;
-
-   // Intersect the region with each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long ByteStart;
-      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-
-      // End is before this chip or the start is after it
-      if (start+len < chip->offset ||
-	  ChipEndByte - (1 << chip->addrshift) < start)
-	 continue;
-
-      if (start < chip->offset)
-      {
-	 ByteStart = chip->offset;
-	 chip->start = 0;
-      }
-      else
-      {
-	 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
-	 ByteStart = start;
-      }
-
-      if (start + len >= ChipEndByte)
-	 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
-      else
-	 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
-   }
-}
-
-int __init jedec_init(void)
-{
-	register_mtd_chip_driver(&jedec_chipdrv);
-	return 0;
-}
-
-static void __exit jedec_exit(void)
-{
-	unregister_mtd_chip_driver(&jedec_chipdrv);
-}
-
-module_init(jedec_init);
-module_exit(jedec_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
-MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
deleted file mode 100644
index c9cd3d2..0000000
--- a/drivers/mtd/chips/sharp.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * MTD chip driver for pre-CFI Sharp flash chips
- *
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- *           2000,2001 Lineo, Inc.
- *
- * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
- *
- * Devices supported:
- *   LH28F016SCT Symmetrical block flash memory, 2Mx8
- *   LH28F008SCT Symmetrical block flash memory, 1Mx8
- *
- * Documentation:
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
- *   016sctl9.pdf
- *
- * Limitations:
- *   This driver only supports 4x1 arrangement of chips.
- *   Not tested on anything but PowerPC.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/cfi.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#define CMD_RESET		0xffffffff
-#define CMD_READ_ID		0x90909090
-#define CMD_READ_STATUS		0x70707070
-#define CMD_CLEAR_STATUS	0x50505050
-#define CMD_BLOCK_ERASE_1	0x20202020
-#define CMD_BLOCK_ERASE_2	0xd0d0d0d0
-#define CMD_BYTE_WRITE		0x40404040
-#define CMD_SUSPEND		0xb0b0b0b0
-#define CMD_RESUME		0xd0d0d0d0
-#define CMD_SET_BLOCK_LOCK_1	0x60606060
-#define CMD_SET_BLOCK_LOCK_2	0x01010101
-#define CMD_SET_MASTER_LOCK_1	0x60606060
-#define CMD_SET_MASTER_LOCK_2	0xf1f1f1f1
-#define CMD_CLEAR_BLOCK_LOCKS_1	0x60606060
-#define CMD_CLEAR_BLOCK_LOCKS_2	0xd0d0d0d0
-
-#define SR_READY		0x80808080 // 1 = ready
-#define SR_ERASE_SUSPEND	0x40404040 // 1 = block erase suspended
-#define SR_ERROR_ERASE		0x20202020 // 1 = error in block erase or clear lock bits
-#define SR_ERROR_WRITE		0x10101010 // 1 = error in byte write or set lock bit
-#define	SR_VPP			0x08080808 // 1 = Vpp is low
-#define SR_WRITE_SUSPEND	0x04040404 // 1 = byte write suspended
-#define SR_PROTECT		0x02020202 // 1 = lock bit set
-#define SR_RESERVED		0x01010101
-
-#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
-
-/* Configuration options */
-
-#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
-
-static struct mtd_info *sharp_probe(struct map_info *);
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-	size_t *retlen, u_char *buf);
-static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
-	size_t *retlen, const u_char *buf);
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
-static void sharp_sync(struct mtd_info *mtd);
-static int sharp_suspend(struct mtd_info *mtd);
-static void sharp_resume(struct mtd_info *mtd);
-static void sharp_destroy(struct mtd_info *mtd);
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-	unsigned long adr, __u32 datum);
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-	unsigned long adr);
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-	unsigned long adr);
-#endif
-
-
-struct sharp_info{
-	struct flchip *chip;
-	int bogus;
-	int chipshift;
-	int numchips;
-	struct flchip chips[1];
-};
-
-static void sharp_destroy(struct mtd_info *mtd);
-
-static struct mtd_chip_driver sharp_chipdrv = {
-	.probe		= sharp_probe,
-	.destroy	= sharp_destroy,
-	.name		= "sharp",
-	.module		= THIS_MODULE
-};
-
-
-static struct mtd_info *sharp_probe(struct map_info *map)
-{
-	struct mtd_info *mtd = NULL;
-	struct sharp_info *sharp = NULL;
-	int width;
-
-	mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-	if(!mtd)
-		return NULL;
-
-	sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
-	if(!sharp) {
-		kfree(mtd);
-		return NULL;
-	}
-
-	width = sharp_probe_map(map,mtd);
-	if(!width){
-		kfree(mtd);
-		kfree(sharp);
-		return NULL;
-	}
-
-	mtd->priv = map;
-	mtd->type = MTD_NORFLASH;
-	mtd->erase = sharp_erase;
-	mtd->read = sharp_read;
-	mtd->write = sharp_write;
-	mtd->sync = sharp_sync;
-	mtd->suspend = sharp_suspend;
-	mtd->resume = sharp_resume;
-	mtd->flags = MTD_CAP_NORFLASH;
-	mtd->writesize = 1;
-	mtd->name = map->name;
-
-	sharp->chipshift = 23;
-	sharp->numchips = 1;
-	sharp->chips[0].start = 0;
-	sharp->chips[0].state = FL_READY;
-	sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
-	sharp->chips[0].word_write_time = 0;
-	init_waitqueue_head(&sharp->chips[0].wq);
-	spin_lock_init(&sharp->chips[0]._spinlock);
-
-	map->fldrv = &sharp_chipdrv;
-	map->fldrv_priv = sharp;
-
-	__module_get(THIS_MODULE);
-	return mtd;
-}
-
-static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
-{
-	map_word map_cmd;
-	map_cmd.x[0] = cmd;
-	map_write(map, map_cmd, adr);
-}
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
-{
-	map_word tmp, read0, read4;
-	unsigned long base = 0;
-	int width = 4;
-
-	tmp = map_read(map, base+0);
-
-	sharp_send_cmd(map, CMD_READ_ID, base+0);
-
-	read0 = map_read(map, base+0);
-	read4 = map_read(map, base+4);
-	if(read0.x[0] == 0x89898989){
-		printk("Looks like sharp flash\n");
-		switch(read4.x[0]){
-		case 0xaaaaaaaa:
-		case 0xa0a0a0a0:
-			/* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
-			/* a0 - LH28F016SCT-Z4  2Mx8, 32 64k blocks*/
-			mtd->erasesize = 0x10000 * width;
-			mtd->size = 0x200000 * width;
-			return width;
-		case 0xa6a6a6a6:
-			/* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
-			/* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
-			mtd->erasesize = 0x10000 * width;
-			mtd->size = 0x100000 * width;
-			return width;
-#if 0
-		case 0x00000000: /* unknown */
-			/* XX - LH28F004SCT 512kx8, 8 64k blocks*/
-			mtd->erasesize = 0x10000 * width;
-			mtd->size = 0x80000 * width;
-			return width;
-#endif
-		default:
-			printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
-				read0.x[0], read4.x[0]);
-		}
-	}else if((map_read(map, base+0).x[0] == CMD_READ_ID)){
-		/* RAM, probably */
-		printk("Looks like RAM\n");
-		map_write(map, tmp, base+0);
-	}else{
-		printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
-			read0.x[0], read4.x[0]);
-	}
-
-	return 0;
-}
-
-/* This function returns with the chip->mutex lock held. */
-static int sharp_wait(struct map_info *map, struct flchip *chip)
-{
-	int i;
-	map_word status;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-	int adr = 0;
-
-retry:
-	spin_lock_bh(chip->mutex);
-
-	switch(chip->state){
-	case FL_READY:
-		sharp_send_cmd(map, CMD_READ_STATUS, adr);
-		chip->state = FL_STATUS;
-	case FL_STATUS:
-		for(i=0;i<100;i++){
-			status = map_read(map, adr);
-			if((status.x[0] & SR_READY)==SR_READY)
-				break;
-			udelay(1);
-		}
-		break;
-	default:
-		printk("Waiting for chip\n");
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-
-		spin_unlock_bh(chip->mutex);
-
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		if(signal_pending(current))
-			return -EINTR;
-
-		timeo = jiffies + HZ;
-
-		goto retry;
-	}
-
-	sharp_send_cmd(map, CMD_RESET, adr);
-
-	chip->state = FL_READY;
-
-	return 0;
-}
-
-static void sharp_release(struct flchip *chip)
-{
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-}
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-	size_t *retlen, u_char *buf)
-{
-	struct map_info *map = mtd->priv;
-	struct sharp_info *sharp = map->fldrv_priv;
-	int chipnum;
-	int ret = 0;
-	int ofs = 0;
-
-	chipnum = (from >> sharp->chipshift);
-	ofs = from & ((1 << sharp->chipshift)-1);
-
-	*retlen = 0;
-
-	while(len){
-		unsigned long thislen;
-
-		if(chipnum>=sharp->numchips)
-			break;
-
-		thislen = len;
-		if(ofs+thislen >= (1<<sharp->chipshift))
-			thislen = (1<<sharp->chipshift) - ofs;
-
-		ret = sharp_wait(map,&sharp->chips[chipnum]);
-		if(ret<0)
-			break;
-
-		map_copy_from(map,buf,ofs,thislen);
-
-		sharp_release(&sharp->chips[chipnum]);
-
-		*retlen += thislen;
-		len -= thislen;
-		buf += thislen;
-
-		ofs = 0;
-		chipnum++;
-	}
-	return ret;
-}
-
-static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
-	size_t *retlen, const u_char *buf)
-{
-	struct map_info *map = mtd->priv;
-	struct sharp_info *sharp = map->fldrv_priv;
-	int ret = 0;
-	int i,j;
-	int chipnum;
-	unsigned long ofs;
-	union { u32 l; unsigned char uc[4]; } tbuf;
-
-	*retlen = 0;
-
-	while(len){
-		tbuf.l = 0xffffffff;
-		chipnum = to >> sharp->chipshift;
-		ofs = to & ((1<<sharp->chipshift)-1);
-
-		j=0;
-		for(i=ofs&3;i<4 && len;i++){
-			tbuf.uc[i] = *buf;
-			buf++;
-			to++;
-			len--;
-			j++;
-		}
-		sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
-		if(ret<0)
-			return ret;
-		(*retlen)+=j;
-	}
-
-	return 0;
-}
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-	unsigned long adr, __u32 datum)
-{
-	int ret;
-	int timeo;
-	int try;
-	int i;
-	map_word data, status;
-
-	status.x[0] = 0;
-	ret = sharp_wait(map,chip);
-
-	for(try=0;try<10;try++){
-		sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
-		/* cpu_to_le32 -> hack to fix the writel be->le conversion */
-		data.x[0] = cpu_to_le32(datum);
-		map_write(map, data, adr);
-
-		chip->state = FL_WRITING;
-
-		timeo = jiffies + (HZ/2);
-
-		sharp_send_cmd(map, CMD_READ_STATUS, adr);
-		for(i=0;i<100;i++){
-			status = map_read(map, adr);
-			if((status.x[0] & SR_READY) == SR_READY)
-				break;
-		}
-		if(i==100){
-			printk("sharp: timed out writing\n");
-		}
-
-		if(!(status.x[0] & SR_ERRORS))
-			break;
-
-		printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
-
-		sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-	}
-	sharp_send_cmd(map, CMD_RESET, adr);
-	chip->state = FL_READY;
-
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-
-	return 0;
-}
-
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct map_info *map = mtd->priv;
-	struct sharp_info *sharp = map->fldrv_priv;
-	unsigned long adr,len;
-	int chipnum, ret=0;
-
-//printk("sharp_erase()\n");
-	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;
-
-	chipnum = instr->addr >> sharp->chipshift;
-	adr = instr->addr & ((1<<sharp->chipshift)-1);
-	len = instr->len;
-
-	while(len){
-		ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
-		if(ret)return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
-		if(adr >> sharp->chipshift){
-			adr = 0;
-			chipnum++;
-			if(chipnum>=sharp->numchips)
-				break;
-		}
-	}
-
-	instr->state = MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
-
-	return 0;
-}
-
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
-	unsigned long adr)
-{
-	int ret;
-	unsigned long timeo;
-	map_word status;
-	DECLARE_WAITQUEUE(wait, current);
-
-	sharp_send_cmd(map, CMD_READ_STATUS, adr);
-	status = map_read(map, adr);
-
-	timeo = jiffies + HZ;
-
-	while(time_before(jiffies, timeo)){
-		sharp_send_cmd(map, CMD_READ_STATUS, adr);
-		status = map_read(map, adr);
-		if((status.x[0] & SR_READY)==SR_READY){
-			ret = 0;
-			goto out;
-		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-
-		//spin_unlock_bh(chip->mutex);
-
-		schedule_timeout(1);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-
-		//spin_lock_bh(chip->mutex);
-
-		if (signal_pending(current)){
-			ret = -EINTR;
-			goto out;
-		}
-
-	}
-	ret = -ETIME;
-out:
-	return ret;
-}
-
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-	unsigned long adr)
-{
-	int ret;
-	//int timeo;
-	map_word status;
-	//int i;
-
-//printk("sharp_erase_oneblock()\n");
-
-#ifdef AUTOUNLOCK
-	/* This seems like a good place to do an unlock */
-	sharp_unlock_oneblock(map,chip,adr);
-#endif
-
-	sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
-	sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
-
-	chip->state = FL_ERASING;
-
-	ret = sharp_do_wait_for_ready(map,chip,adr);
-	if(ret<0)return ret;
-
-	sharp_send_cmd(map, CMD_READ_STATUS, adr);
-	status = map_read(map, adr);
-
-	if(!(status.x[0] & SR_ERRORS)){
-		sharp_send_cmd(map, CMD_RESET, adr);
-		chip->state = FL_READY;
-		//spin_unlock_bh(chip->mutex);
-		return 0;
-	}
-
-	printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-	sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-
-	//spin_unlock_bh(chip->mutex);
-
-	return -EIO;
-}
-
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-	unsigned long adr)
-{
-	int i;
-	map_word status;
-
-	sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr);
-	sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr);
-
-	udelay(100);
-
-	status = map_read(map, adr);
-	printk("status=%08lx\n", status.x[0]);
-
-	for(i=0;i<1000;i++){
-		//sharp_send_cmd(map, CMD_READ_STATUS, adr);
-		status = map_read(map, adr);
-		if((status.x[0] & SR_READY) == SR_READY)
-			break;
-		udelay(100);
-	}
-	if(i==1000){
-		printk("sharp: timed out unlocking block\n");
-	}
-
-	if(!(status.x[0] & SR_ERRORS)){
-		sharp_send_cmd(map, CMD_RESET, adr);
-		chip->state = FL_READY;
-		return;
-	}
-
-	printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-	sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-}
-#endif
-
-static void sharp_sync(struct mtd_info *mtd)
-{
-	//printk("sharp_sync()\n");
-}
-
-static int sharp_suspend(struct mtd_info *mtd)
-{
-	printk("sharp_suspend()\n");
-	return -EINVAL;
-}
-
-static void sharp_resume(struct mtd_info *mtd)
-{
-	printk("sharp_resume()\n");
-
-}
-
-static void sharp_destroy(struct mtd_info *mtd)
-{
-	printk("sharp_destroy()\n");
-
-}
-
-static int __init sharp_probe_init(void)
-{
-	printk("MTD Sharp chip driver <ds@lineo.com>\n");
-
-	register_mtd_chip_driver(&sharp_chipdrv);
-
-	return 0;
-}
-
-static void __exit sharp_probe_exit(void)
-{
-	unregister_mtd_chip_driver(&sharp_chipdrv);
-}
-
-module_init(sharp_probe_init);
-module_exit(sharp_probe_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Schleef <ds@schleef.org>");
-MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index fc4cc8b..be4b994 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -373,7 +373,7 @@
 
 #ifndef MODULE
 static int block2mtd_init_called = 0;
-static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
+static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 
 
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index d990d81..b665e4a 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -60,7 +60,7 @@
 	  (i.e., run-time calling physmap_configure()).
 
 config MTD_PHYSMAP_OF
-	tristate "Flash device in physical memory map based on OF descirption"
+	tristate "Flash device in physical memory map based on OF description"
 	depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
 	help
 	  This provides a 'mapping' driver which allows the NOR Flash and
@@ -358,22 +358,6 @@
 	  Mapping for the Flaga digital module. If you don't have one, ignore
 	  this setting.
 
-config MTD_BEECH
-	tristate "CFI Flash device mapped on IBM 405LP Beech"
-	depends on MTD_CFI && BEECH
-	help
-	  This enables access routines for the flash chips on the IBM
-	  405LP Beech board. If you have one of these boards and would like
-	  to use the flash chips on it, say 'Y'.
-
-config MTD_ARCTIC
-	tristate "CFI Flash device mapped on IBM 405LP Arctic"
-	depends on MTD_CFI && ARCTIC2
-	help
-	  This enables access routines for the flash chips on the IBM 405LP
-	  Arctic board. If you have one of these boards and would like to
-	  use the flash chips on it, say 'Y'.
-
 config MTD_WALNUT
 	tristate "Flash device mapped on IBM 405GP Walnut"
 	depends on MTD_JEDECPROBE && WALNUT
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index de036c5..3acbb5d 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -58,8 +58,6 @@
 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_WALNUT)        += walnut.o
 obj-$(CONFIG_MTD_H720X)		+= h720x-flash.o
 obj-$(CONFIG_MTD_SBC8240)	+= sbc8240.o
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
deleted file mode 100644
index 2cc9024..0000000
--- a/drivers/mtd/maps/arctic-mtd.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Arctic boards.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- * modified for Arctic by,
- * David Gibson
- * IBM OzLabs, Canberra, Australia
- * <arctic@gibson.dropbear.id.au>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-/*
- * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
- * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
- * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
- * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
- */
-
-#define FFS1_SIZE	0x01000000 /* 16MiB */
-#define KERNEL_SIZE	0x00500000 /* 5.12MiB */
-#define FFS2_SIZE	0x00a60000 /* 10.624MiB */
-#define FIRMWARE_SIZE	0x000a0000 /* 640KiB */
-
-
-#define NAME     	"Arctic Linux Flash"
-#define PADDR    	SUBZERO_BOOTFLASH_PADDR
-#define BUSWIDTH	2
-#define SIZE		SUBZERO_BOOTFLASH_SIZE
-#define PARTITIONS	4
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-{
-  /* do nothing for now */
-}
-
-static struct map_info arctic_mtd_map = {
-	.name		= NAME,
-	.size		= SIZE,
-	.bankwidth	= BUSWIDTH,
-	.phys		= PADDR,
-};
-
-static struct mtd_info *arctic_mtd;
-
-static struct mtd_partition arctic_partitions[PARTITIONS] = {
-	{ .name		= "Filesystem",
-	  .size		= FFS1_SIZE,
-	  .offset	= 0,},
-        { .name		= "Kernel",
-	  .size		= KERNEL_SIZE,
-	  .offset	= FFS1_SIZE,},
-	{ .name		= "Filesystem",
-	  .size		= FFS2_SIZE,
-	  .offset	= FFS1_SIZE + KERNEL_SIZE,},
-	{ .name		= "Firmware",
-	  .size		= FIRMWARE_SIZE,
-	  .offset	= SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-};
-
-static int __init
-init_arctic_mtd(void)
-{
-	int err;
-
-	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-	arctic_mtd_map.virt = ioremap(PADDR, SIZE);
-
-	if (!arctic_mtd_map.virt) {
-		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-		return -EIO;
-	}
-	simple_map_init(&arctic_mtd_map);
-
-	printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-	arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-
-	if (!arctic_mtd) {
-		iounmap(arctic_mtd_map.virt);
-		return -ENXIO;
-	}
-
-	arctic_mtd->owner = THIS_MODULE;
-
-	err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
-	if (err) {
-		printk("%s: add_mtd_partitions failed\n", NAME);
-		iounmap(arctic_mtd_map.virt);
-	}
-
-	return err;
-}
-
-static void __exit
-cleanup_arctic_mtd(void)
-{
-	if (arctic_mtd) {
-		del_mtd_partitions(arctic_mtd);
-		map_destroy(arctic_mtd);
-		iounmap((void *) arctic_mtd_map.virt);
-	}
-}
-
-module_init(init_arctic_mtd);
-module_exit(cleanup_arctic_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
deleted file mode 100644
index d76d598..0000000
--- a/drivers/mtd/maps/beech-mtd.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Beech boards.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-#define NAME     "Beech Linux Flash"
-#define PADDR    BEECH_BIGFLASH_PADDR
-#define SIZE     BEECH_BIGFLASH_SIZE
-#define BUSWIDTH 1
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-
-static struct map_info beech_mtd_map = {
-	.name =		NAME,
-	.size =		SIZE,
-	.bankwidth =	BUSWIDTH,
-	.phys =		PADDR
-};
-
-static struct mtd_info *beech_mtd;
-
-static struct mtd_partition beech_partitions[2] = {
-	{
-	      .name = "Linux Kernel",
-	      .size = BEECH_KERNEL_SIZE,
-	      .offset = BEECH_KERNEL_OFFSET
-	}, {
-	      .name = "Free Area",
-	      .size = BEECH_FREE_AREA_SIZE,
-	      .offset = BEECH_FREE_AREA_OFFSET
-	}
-};
-
-static int __init
-init_beech_mtd(void)
-{
-	int err;
-
-	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-	beech_mtd_map.virt = ioremap(PADDR, SIZE);
-
-	if (!beech_mtd_map.virt) {
-		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-		return -EIO;
-	}
-
-	simple_map_init(&beech_mtd_map);
-
-	printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-	beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-
-	if (!beech_mtd) {
-		iounmap(beech_mtd_map.virt);
-		return -ENXIO;
-	}
-
-	beech_mtd->owner = THIS_MODULE;
-
-	err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
-	if (err) {
-		printk("%s: add_mtd_partitions failed\n", NAME);
-		iounmap(beech_mtd_map.virt);
-	}
-
-	return err;
-}
-
-static void __exit
-cleanup_beech_mtd(void)
-{
-	if (beech_mtd) {
-		del_mtd_partitions(beech_mtd);
-		map_destroy(beech_mtd);
-		iounmap((void *) beech_mtd_map.virt);
-	}
-}
-
-module_init(init_beech_mtd);
-module_exit(cleanup_beech_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 9f53c65..7b96cd02 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -358,7 +358,7 @@
 	/* Turn other PAR off so the first probe doesn't find it */
 	*intel1par = 0;
 
-	/* Probe for the the size of the first Intel flash */
+	/* Probe for the size of the first Intel flash */
 	nettel_intel_map.size = maxsize;
 	nettel_intel_map.phys = intel0addr;
 	nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 72107dc..bbb42c3 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -186,7 +186,7 @@
 	else {
  		if (strcmp(of_probe, "ROM"))
 			dev_dbg(&dev->dev, "map_probe: don't know probe type "
-			"'%s', mapping as rom\n");
+			"'%s', mapping as rom\n", of_probe);
 		info->mtd = do_map_probe("mtd_rom", &info->map);
 	}
 	if (info->mtd == NULL) {
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 1af9890..9c62368 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -347,7 +347,6 @@
 		slave->mtd.subpage_sft = master->subpage_sft;
 
 		slave->mtd.name = parts[i].name;
-		slave->mtd.bank_size = master->bank_size;
 		slave->mtd.owner = master->owner;
 
 		slave->mtd.read = part_read;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index d05873b..f1d60b6 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -232,11 +232,13 @@
           will be named "excite_nandflash.ko".
 
 config MTD_NAND_CAFE
-       tristate "NAND support for OLPC CAFÉ chip"
-       depends on PCI
-       help
-	 Use NAND flash attached to the CAFÉ chip designed for the $100
-	 laptop.
+	tristate "NAND support for OLPC CAFÉ chip"
+	depends on PCI
+	select REED_SOLOMON
+	select REED_SOLOMON_DEC16
+	help
+	  Use NAND flash attached to the CAFÉ chip designed for the $100
+	  laptop.
 
 config MTD_NAND_CS553X
 	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
@@ -270,4 +272,13 @@
 	  The simulator may simulate various NAND flash chips for the
 	  MTD nand layer.
 
+config MTD_NAND_PLATFORM
+	tristate "Support for generic platform NAND driver"
+	depends on MTD_NAND
+	help
+	  This implements a generic NAND driver for on-SOC platform
+	  devices. You will need to provide platform-specific functions
+	  via platform_data.
+
+
 endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 6872031..edba1db 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -26,6 +26,6 @@
 obj-$(CONFIG_MTD_NAND_AT91)		+= at91_nand.o
 obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)	+= excite_nandflash.o
+obj-$(CONFIG_MTD_NAND_PLATFORM)		+= plat_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
-cafe_nand-objs := cafe.o cafe_ecc.o
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 14b80cc..512e999 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -82,6 +82,10 @@
 		at91_set_gpio_value(host->board->enable_pin, 1);
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -151,6 +155,12 @@
 #ifdef CONFIG_MTD_PARTITIONS
 	if (host->board->partition_info)
 		partitions = host->board->partition_info(mtd->size, &num_partitions);
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	else {
+		mtd->name = "at91_nand";
+		num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+	}
+#endif
 
 	if ((!partitions) || (num_partitions == 0)) {
 		printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
deleted file mode 100644
index ea5c849..0000000
--- a/drivers/mtd/nand/cafe_ecc.c
+++ /dev/null
@@ -1,1381 +0,0 @@
-/* Error correction for CAFÉ NAND controller
- *
- * © 2006 Marvell, Inc.
- * Author: Tom Chiou
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-
-static unsigned short gf4096_mul(unsigned short, unsigned short);
-static unsigned short gf64_mul(unsigned short, unsigned short);
-static unsigned short gf4096_inv(unsigned short);
-static unsigned short err_pos(unsigned short);
-static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short,
-				unsigned short, unsigned short, unsigned short,
-				unsigned short, unsigned short, unsigned short *);
-static void zero_4x5_col3(unsigned short[4][5]);
-static void zero_4x5_col2(unsigned short[4][5]);
-static void zero_4x5_col1(unsigned short[4][5]);
-static void swap_4x5_rows(unsigned short[4][5], int, int, int);
-static void swap_2x3_rows(unsigned short m[2][3]);
-static void solve_4x5(unsigned short m[4][5], unsigned short *, int *);
-static void sort_coefs(int *, unsigned short *, int);
-static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short,
-			       unsigned short, unsigned short, unsigned short,
-			       unsigned short, unsigned short, unsigned short *);
-static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short,
-				unsigned short, unsigned short, unsigned short,
-				unsigned short *);
-static void zero_3x4_col2(unsigned short[3][4]);
-static void zero_3x4_col1(unsigned short[3][4]);
-static void swap_3x4_rows(unsigned short[3][4], int, int, int);
-static void solve_3x4(unsigned short[3][4], unsigned short *, int *);
-static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short,
-			       unsigned short, unsigned short, unsigned short,
-			       unsigned short *);
-
-static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short,
-			       unsigned short, unsigned short *);
-static void find_2x2_soln(unsigned short, unsigned short, unsigned short,
-			  unsigned short, unsigned short, unsigned short,
-			  unsigned short *);
-static void solve_2x3(unsigned short[2][3], unsigned short *);
-static int chk_no_err_only(unsigned short *, unsigned short *);
-static int chk_1_err_only(unsigned short *, unsigned short *);
-static int chk_2_err_only(unsigned short *, unsigned short *);
-static int chk_3_err_only(unsigned short *, unsigned short *);
-static int chk_4_err_only(unsigned short *, unsigned short *);
-
-static unsigned short gf64_mul(unsigned short a, unsigned short b)
-{
-	unsigned short tmp1, tmp2, tmp3, tmp4, tmp5;
-	unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c;
-
-	tmp1 = ((a) ^ (a >> 5));
-	tmp2 = ((a >> 4) ^ (a >> 5));
-	tmp3 = ((a >> 3) ^ (a >> 4));
-	tmp4 = ((a >> 2) ^ (a >> 3));
-	tmp5 = ((a >> 1) ^ (a >> 2));
-
-	c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^
-		  ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1;
-
-	c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^
-		  (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1;
-
-	c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^
-		  (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1;
-
-	c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^
-		  (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1;
-
-	c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^
-		  ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1;
-
-	c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^
-		  ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1;
-
-	c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5);
-
-	return c;
-}
-
-static unsigned short gf4096_mul(unsigned short a, unsigned short b)
-{
-	unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c;
-
-	ah = (a >> 6) & 0x3f;
-	al = a & 0x3f;
-	bh = (b >> 6) & 0x3f;
-	bl = b & 0x3f;
-	alxah = al ^ ah;
-	blxbh = bl ^ bh;
-
-	ablh = gf64_mul(alxah, blxbh);
-	albl = gf64_mul(al, bl);
-	ahbh = gf64_mul(ah, bh);
-
-	ahbhB = ((ahbh & 0x1) << 5) |
-	    ((ahbh & 0x20) >> 1) |
-	    ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1);
-
-	c = ((ablh ^ albl) << 6) | (ahbhB ^ albl);
-	return c;
-}
-
-static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats)
-{
-	find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats);
-}
-
-static void find_3bit_err_coefs(unsigned short s0, unsigned short s1,
-				unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs)
-{
-	unsigned short m[3][4];
-	int row_order[3];
-
-	row_order[0] = 0;
-	row_order[1] = 1;
-	row_order[2] = 2;
-	m[0][0] = s2;
-	m[0][1] = s1;
-	m[0][2] = s0;
-	m[0][3] = s3;
-	m[1][0] = s3;
-	m[1][1] = s2;
-	m[1][2] = s1;
-	m[1][3] = s4;
-	m[2][0] = s4;
-	m[2][1] = s3;
-	m[2][2] = s2;
-	m[2][3] = s5;
-
-	if (m[0][2] != 0x0) {
-		zero_3x4_col2(m);
-	} else if (m[1][2] != 0x0) {
-		swap_3x4_rows(m, 0, 1, 4);
-		zero_3x4_col2(m);
-	} else if (m[2][2] != 0x0) {
-		swap_3x4_rows(m, 0, 2, 4);
-		zero_3x4_col2(m);
-	} else {
-		printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n");
-	}
-
-	if (m[1][1] != 0x0) {
-		zero_3x4_col1(m);
-	} else if (m[2][1] != 0x0) {
-		swap_3x4_rows(m, 1, 2, 4);
-		zero_3x4_col1(m);
-	} else {
-		printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n");
-	}
-
-	/* solve coefs */
-	solve_3x4(m, coefs, row_order);
-}
-
-static void zero_3x4_col2(unsigned short m[3][4])
-{
-	unsigned short minv1, minv2;
-
-	minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2]));
-	minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2]));
-	m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-	m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-	m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1);
-	m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-	m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-	m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2);
-}
-
-static void zero_3x4_col1(unsigned short m[3][4])
-{
-	unsigned short minv;
-	minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1]));
-	m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv);
-	m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv);
-}
-
-static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width)
-{
-	unsigned short tmp0;
-	int cnt;
-	for (cnt = 0; cnt < col_width; cnt++) {
-		tmp0 = m[i][cnt];
-		m[i][cnt] = m[j][cnt];
-		m[j][cnt] = tmp0;
-	}
-}
-
-static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order)
-{
-	unsigned short tmp[3];
-	tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0]));
-	tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1]));
-	tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2]));
-	sort_coefs(row_order, tmp, 3);
-	coefs[0] = tmp[0];
-	coefs[1] = tmp[1];
-	coefs[2] = tmp[2];
-}
-
-static void find_3bit_err_pats(unsigned short s0, unsigned short s1,
-			       unsigned short s2, unsigned short r0,
-			       unsigned short r1, unsigned short r2,
-			       unsigned short *pats)
-{
-	find_2x2_soln(r0 ^ r2, r1 ^ r2,
-		      gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2),
-		      gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats);
-	pats[2] = s0 ^ pats[0] ^ pats[1];
-}
-
-static void find_4bit_err_coefs(unsigned short s0, unsigned short s1,
-				unsigned short s2, unsigned short s3,
-				unsigned short s4, unsigned short s5,
-				unsigned short s6, unsigned short s7,
-				unsigned short *coefs)
-{
-	unsigned short m[4][5];
-	int row_order[4];
-
-	row_order[0] = 0;
-	row_order[1] = 1;
-	row_order[2] = 2;
-	row_order[3] = 3;
-
-	m[0][0] = s3;
-	m[0][1] = s2;
-	m[0][2] = s1;
-	m[0][3] = s0;
-	m[0][4] = s4;
-	m[1][0] = s4;
-	m[1][1] = s3;
-	m[1][2] = s2;
-	m[1][3] = s1;
-	m[1][4] = s5;
-	m[2][0] = s5;
-	m[2][1] = s4;
-	m[2][2] = s3;
-	m[2][3] = s2;
-	m[2][4] = s6;
-	m[3][0] = s6;
-	m[3][1] = s5;
-	m[3][2] = s4;
-	m[3][3] = s3;
-	m[3][4] = s7;
-
-	if (m[0][3] != 0x0) {
-		zero_4x5_col3(m);
-	} else if (m[1][3] != 0x0) {
-		swap_4x5_rows(m, 0, 1, 5);
-		zero_4x5_col3(m);
-	} else if (m[2][3] != 0x0) {
-		swap_4x5_rows(m, 0, 2, 5);
-		zero_4x5_col3(m);
-	} else if (m[3][3] != 0x0) {
-		swap_4x5_rows(m, 0, 3, 5);
-		zero_4x5_col3(m);
-	} else {
-		printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n");
-	}
-
-	if (m[1][2] != 0x0) {
-		zero_4x5_col2(m);
-	} else if (m[2][2] != 0x0) {
-		swap_4x5_rows(m, 1, 2, 5);
-		zero_4x5_col2(m);
-	} else if (m[3][2] != 0x0) {
-		swap_4x5_rows(m, 1, 3, 5);
-		zero_4x5_col2(m);
-	} else {
-		printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n");
-	}
-
-	if (m[2][1] != 0x0) {
-		zero_4x5_col1(m);
-	} else if (m[3][1] != 0x0) {
-		swap_4x5_rows(m, 2, 3, 5);
-		zero_4x5_col1(m);
-	} else {
-		printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n");
-	}
-
-	solve_4x5(m, coefs, row_order);
-}
-
-static void zero_4x5_col3(unsigned short m[4][5])
-{
-	unsigned short minv1, minv2, minv3;
-
-	minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3]));
-	minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3]));
-	minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3]));
-
-	m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-	m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-	m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1);
-	m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1);
-	m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-	m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-	m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2);
-	m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2);
-	m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3);
-	m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3);
-	m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3);
-	m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3);
-}
-
-static void zero_4x5_col2(unsigned short m[4][5])
-{
-	unsigned short minv2, minv3;
-
-	minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2]));
-	minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2]));
-
-	m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2);
-	m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2);
-	m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2);
-	m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3);
-	m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3);
-	m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3);
-}
-
-static void zero_4x5_col1(unsigned short m[4][5])
-{
-	unsigned short minv;
-
-	minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1]));
-
-	m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv);
-	m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv);
-}
-
-static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width)
-{
-	unsigned short tmp0;
-	int cnt;
-
-	for (cnt = 0; cnt < col_width; cnt++) {
-		tmp0 = m[i][cnt];
-		m[i][cnt] = m[j][cnt];
-		m[j][cnt] = tmp0;
-	}
-}
-
-static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order)
-{
-	unsigned short tmp[4];
-
-	tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0]));
-	tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1]));
-	tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2]));
-	tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^
-			gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3]));
-	sort_coefs(row_order, tmp, 4);
-	coefs[0] = tmp[0];
-	coefs[1] = tmp[1];
-	coefs[2] = tmp[2];
-	coefs[3] = tmp[3];
-}
-
-static void sort_coefs(int *order, unsigned short *soln, int len)
-{
-	int cnt, start_cnt, least_ord, least_cnt;
-	unsigned short tmp0;
-	for (start_cnt = 0; start_cnt < len; start_cnt++) {
-		for (cnt = start_cnt; cnt < len; cnt++) {
-			if (cnt == start_cnt) {
-				least_ord = order[cnt];
-				least_cnt = start_cnt;
-			} else {
-				if (least_ord > order[cnt]) {
-					least_ord = order[cnt];
-					least_cnt = cnt;
-				}
-			}
-		}
-		if (least_cnt != start_cnt) {
-			tmp0 = order[least_cnt];
-			order[least_cnt] = order[start_cnt];
-			order[start_cnt] = tmp0;
-			tmp0 = soln[least_cnt];
-			soln[least_cnt] = soln[start_cnt];
-			soln[start_cnt] = tmp0;
-		}
-	}
-}
-
-static void find_4bit_err_pats(unsigned short s0, unsigned short s1,
-			       unsigned short s2, unsigned short s3,
-			       unsigned short z1, unsigned short z2,
-			       unsigned short z3, unsigned short z4,
-			       unsigned short *pats)
-{
-	unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1,
-		z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3;
-	unsigned short tmp0, tmp1, tmp2, tmp3;
-
-	z4_z1 = z4 ^ z1;
-	z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3);
-	z4_z2 = z4 ^ z2;
-	s0z4_s1 = gf4096_mul(s0, z4) ^ s1;
-	z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1);
-	z4_z3 = z4 ^ z3;
-	z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2);
-	s1z4_s2 = gf4096_mul(s1, z4) ^ s2;
-	z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3);
-	z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1);
-	z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2);
-	s2z4_s3 = gf4096_mul(s2, z4) ^ s3;
-
-	//find err pat 0,1
-	find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^
-		      gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2,
-							       z3z4_z3z3) ^
-		      gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1,
-							       z3z3z4_z3z3z3) ^
-		      gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3),
-		      gf4096_mul(z2z4_z2z2,
-				 z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2,
-							     z3z4_z3z3),
-		      gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2,
-								  z4_z3),
-		      gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats);
-	tmp0 = pats[0];
-	tmp1 = pats[1];
-	tmp2 = pats[0] ^ pats[1] ^ s0;
-	tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1;
-
-	//find err pat 2,3
-	find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats);
-	pats[2] = pats[0];
-	pats[3] = pats[1];
-	pats[0] = tmp0;
-	pats[1] = tmp1;
-}
-
-static void find_2x2_soln(unsigned short c00, unsigned short c01,
-			  unsigned short c10, unsigned short c11,
-			  unsigned short lval0, unsigned short lval1,
-			  unsigned short *soln)
-{
-	unsigned short m[2][3];
-	m[0][0] = c00;
-	m[0][1] = c01;
-	m[0][2] = lval0;
-	m[1][0] = c10;
-	m[1][1] = c11;
-	m[1][2] = lval1;
-
-	if (m[0][1] != 0x0) {
-		/* */
-	} else if (m[1][1] != 0x0) {
-		swap_2x3_rows(m);
-	} else {
-		printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n");
-	}
-
-	solve_2x3(m, soln);
-}
-
-static void swap_2x3_rows(unsigned short m[2][3])
-{
-	unsigned short tmp0;
-	int cnt;
-
-	for (cnt = 0; cnt < 3; cnt++) {
-		tmp0 = m[0][cnt];
-		m[0][cnt] = m[1][cnt];
-		m[1][cnt] = tmp0;
-	}
-}
-
-static void solve_2x3(unsigned short m[2][3], unsigned short *coefs)
-{
-	unsigned short minv;
-
-	minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1]));
-	m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv);
-	m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv);
-	coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0]));
-	coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1]));
-}
-
-static unsigned char gf64_inv[64] = {
-	 0,  1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25,
-	61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45,  6,
-	63,  2, 27, 21, 56,  9, 50, 19, 13, 47, 48,  5,  7, 30, 12, 41,
-	42,  4, 38, 18, 10, 29, 17, 60, 36,  8, 59, 58, 55, 16,  3, 32
-};
-
-static unsigned short gf4096_inv(unsigned short din)
-{
-	unsigned short alahxal, ah2B, deno, inv, bl, bh;
-	unsigned short ah, al, ahxal;
-	unsigned short dout;
-
-	ah = (din >> 6) & 0x3f;
-	al = din & 0x3f;
-	ahxal = ah ^ al;
-	ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) |
-		((ah >> 1) & 0x10) |
-		((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) |
-		((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1);
-	alahxal = gf64_mul(ahxal, al);
-	deno = alahxal ^ ah2B;
-	inv = gf64_inv[deno];
-	bl = gf64_mul(inv, ahxal);
-	bh = gf64_mul(inv, ah);
-	dout = ((bh & 0x3f) << 6) | (bl & 0x3f);
-	return (((bh & 0x3f) << 6) | (bl & 0x3f));
-}
-
-static unsigned short err_pos_lut[4096] = {
-	0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff,
-	0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff,
-	0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff,
-	0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff,
-	0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7,
-	0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff,
-	0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff,
-	0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f,
-	0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8,
-	0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe,
-	0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff,
-	0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1,
-	0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff,
-	0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff,
-	0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff,
-	0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8,
-	0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e,
-	0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff,
-	0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff,
-	0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff,
-	0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535,
-	0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d,
-	0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff,
-	0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5,
-	0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff,
-	0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294,
-	0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff,
-	0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4,
-	0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f,
-	0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b,
-	0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff,
-	0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff,
-	0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff,
-	0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158,
-	0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a,
-	0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff,
-	0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff,
-	0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017,
-	0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a,
-	0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351,
-	0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff,
-	0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff,
-	0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074,
-	0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da,
-	0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433,
-	0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285,
-	0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff,
-	0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d,
-	0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff,
-	0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff,
-	0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331,
-	0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff,
-	0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6,
-	0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3,
-	0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff,
-	0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf,
-	0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc,
-	0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381,
-	0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff,
-	0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f,
-	0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff,
-	0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488,
-	0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442,
-	0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6,
-	0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1,
-	0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae,
-	0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff,
-	0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff,
-	0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2,
-	0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec,
-	0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134,
-	0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b,
-	0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff,
-	0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff,
-	0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff,
-	0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5,
-	0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff,
-	0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff,
-	0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff,
-	0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff,
-	0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2,
-	0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff,
-	0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff,
-	0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff,
-	0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff,
-	0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff,
-	0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff,
-	0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff,
-	0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8,
-	0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb,
-	0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff,
-	0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff,
-	0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd,
-	0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff,
-	0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8,
-	0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9,
-	0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f,
-	0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7,
-	0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff,
-	0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d,
-	0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178,
-	0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff,
-	0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba,
-	0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff,
-	0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e,
-	0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff,
-	0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6,
-	0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff,
-	0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff,
-	0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc,
-	0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6,
-	0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5,
-	0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff,
-	0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc,
-	0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff,
-	0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3,
-	0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff,
-	0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6,
-	0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff,
-	0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a,
-	0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff,
-	0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff,
-	0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff,
-	0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff,
-	0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7,
-	0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff,
-	0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff,
-	0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af,
-	0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff,
-	0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2,
-	0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff,
-	0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff,
-	0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff,
-	0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339,
-	0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff,
-	0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff,
-	0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402,
-	0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff,
-	0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368,
-	0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b,
-	0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f,
-	0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff,
-	0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1,
-	0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff,
-	0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff,
-	0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb,
-	0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc,
-	0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097,
-	0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431,
-	0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1,
-	0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff,
-	0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6,
-	0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd,
-	0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff,
-	0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb,
-	0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff,
-	0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd,
-	0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff,
-	0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff,
-	0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519,
-	0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff,
-	0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084,
-	0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0,
-	0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c,
-	0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f,
-	0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a,
-	0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211,
-	0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff,
-	0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff,
-	0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff,
-	0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff,
-	0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff,
-	0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff,
-	0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180,
-	0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0,
-	0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004,
-	0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302,
-	0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff,
-	0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff,
-	0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272,
-	0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff,
-	0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344,
-	0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff,
-	0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e,
-	0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d,
-	0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff,
-	0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330,
-	0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042,
-	0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364,
-	0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff,
-	0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff,
-	0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f,
-	0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb,
-	0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e,
-	0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c,
-	0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194,
-	0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff,
-	0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff,
-	0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff,
-	0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff,
-	0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6,
-	0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff,
-	0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290,
-	0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff,
-	0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9,
-	0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d,
-	0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff,
-	0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9,
-	0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167,
-	0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020,
-	0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347,
-	0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff,
-	0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff,
-	0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff,
-	0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff,
-	0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff,
-	0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039,
-	0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096,
-	0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff,
-	0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8,
-	0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff,
-	0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd,
-	0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e,
-	0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f,
-	0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff,
-	0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7,
-	0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb,
-	0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff,
-	0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078,
-	0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300,
-	0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200,
-	0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f,
-	0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff,
-	0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216,
-	0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d,
-	0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0,
-	0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff,
-	0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff,
-	0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff,
-	0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff,
-	0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff,
-	0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff,
-	0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086,
-	0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff,
-	0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444,
-	0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff,
-	0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110,
-	0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099,
-	0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff,
-	0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da,
-	0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff,
-	0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff,
-	0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff,
-	0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff,
-	0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff,
-	0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283,
-	0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff,
-	0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff,
-	0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff,
-	0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff,
-	0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff,
-	0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195,
-	0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff,
-	0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff,
-	0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff,
-	0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff,
-	0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff,
-	0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245,
-	0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff,
-	0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6,
-	0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-	0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1,
-	0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da,
-	0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff,
-	0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff,
-	0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5,
-	0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223,
-	0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002
-};
-
-static unsigned short err_pos(unsigned short din)
-{
-	BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
-	return err_pos_lut[din];
-}
-static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-	if ((chk_syndrome_list[0] | chk_syndrome_list[1] |
-	     chk_syndrome_list[2] | chk_syndrome_list[3] |
-	     chk_syndrome_list[4] | chk_syndrome_list[5] |
-	     chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) {
-		return -EINVAL;
-	} else {
-		err_info[0] = 0x0;
-		return 0;
-	}
-}
-static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-	unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
-	tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0]));
-	tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1]));
-	tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2]));
-	tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3]));
-	tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4]));
-	tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5]));
-	tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6]));
-	if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) {
-		err_info[0] = 0x1;	// encode 1-symbol error as 0x1
-		err_info[1] = err_pos(tmp0);
-		err_info[1] = (unsigned short)(0x55e - err_info[1]);
-		err_info[5] = chk_syndrome_list[0];
-		return 0;
-	} else
-		return -EINVAL;
-}
-static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-	unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
-	unsigned short coefs[4];
-	unsigned short err_pats[4];
-	int found_num_root = 0;
-	unsigned short bit2_root0, bit2_root1;
-	unsigned short bit2_root0_inv, bit2_root1_inv;
-	unsigned short err_loc_eqn, test_root;
-	unsigned short bit2_loc0, bit2_loc1;
-	unsigned short bit2_pat0, bit2_pat1;
-
-	find_2x2_soln(chk_syndrome_list[1],
-		      chk_syndrome_list[0],
-		      chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs);
-	for (test_root = 0x1; test_root < 0xfff; test_root++) {
-		err_loc_eqn =
-		    gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-		if (err_loc_eqn == 0x0) {
-			if (found_num_root == 0) {
-				bit2_root0 = test_root;
-				found_num_root = 1;
-			} else if (found_num_root == 1) {
-				bit2_root1 = test_root;
-				found_num_root = 2;
-				break;
-			}
-		}
-	}
-	if (found_num_root != 2)
-		return -EINVAL;
-	else {
-		bit2_root0_inv = gf4096_inv(bit2_root0);
-		bit2_root1_inv = gf4096_inv(bit2_root1);
-		find_2bit_err_pats(chk_syndrome_list[0],
-				   chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats);
-		bit2_pat0 = err_pats[0];
-		bit2_pat1 = err_pats[1];
-		//for(x+1)
-		tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv));	//rinv0^4
-		tmp1 = gf4096_mul(bit2_root0_inv, tmp0);	//rinv0^5
-		tmp2 = gf4096_mul(bit2_root0_inv, tmp1);	//rinv0^6
-		tmp3 = gf4096_mul(bit2_root0_inv, tmp2);	//rinv0^7
-		tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv));	//rinv1^4
-		tmp5 = gf4096_mul(bit2_root1_inv, tmp4);	//rinv1^5
-		tmp6 = gf4096_mul(bit2_root1_inv, tmp5);	//rinv1^6
-		tmp7 = gf4096_mul(bit2_root1_inv, tmp6);	//rinv1^7
-		//check if only 2-bit error
-		if ((chk_syndrome_list[4] ==
-		     (gf4096_mul(bit2_pat0, tmp0) ^
-		      gf4096_mul(bit2_pat1,
-				 tmp4))) & (chk_syndrome_list[5] ==
-					    (gf4096_mul(bit2_pat0, tmp1) ^
-					     gf4096_mul(bit2_pat1,
-							tmp5))) &
-		    (chk_syndrome_list[6] ==
-		     (gf4096_mul(bit2_pat0, tmp2) ^
-		      gf4096_mul(bit2_pat1,
-				 tmp6))) & (chk_syndrome_list[7] ==
-					    (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) {
-			if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) {
-				return -EINVAL;
-			} else {
-				bit2_loc0 = 0x55e - err_pos(bit2_root0_inv);
-				bit2_loc1 = 0x55e - err_pos(bit2_root1_inv);
-				err_info[0] = 0x2;	// encode 2-symbol error as 0x2
-				err_info[1] = bit2_loc0;
-				err_info[2] = bit2_loc1;
-				err_info[5] = bit2_pat0;
-				err_info[6] = bit2_pat1;
-				return 0;
-			}
-		} else
-			return -EINVAL;
-	}
-}
-static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-	unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
-	unsigned short coefs[4];
-	unsigned short err_pats[4];
-	int found_num_root = 0;
-	unsigned short bit3_root0, bit3_root1, bit3_root2;
-	unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv;
-	unsigned short err_loc_eqn, test_root;
-
-	find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1],
-			    chk_syndrome_list[2], chk_syndrome_list[3],
-			    chk_syndrome_list[4], chk_syndrome_list[5], coefs);
-
-	for (test_root = 0x1; test_root < 0xfff; test_root++) {
-		err_loc_eqn = gf4096_mul(coefs[2],
-					 gf4096_mul(gf4096_mul(test_root, test_root),
-						    test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root))
-			^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-
-		if (err_loc_eqn == 0x0) {
-			if (found_num_root == 0) {
-				bit3_root0 = test_root;
-				found_num_root = 1;
-			} else if (found_num_root == 1) {
-				bit3_root1 = test_root;
-				found_num_root = 2;
-			} else if (found_num_root == 2) {
-				bit3_root2 = test_root;
-				found_num_root = 3;
-				break;
-			}
-		}
-	}
-	if (found_num_root != 3)
-		return -EINVAL;
-	else {
-		bit3_root0_inv = gf4096_inv(bit3_root0);
-		bit3_root1_inv = gf4096_inv(bit3_root1);
-		bit3_root2_inv = gf4096_inv(bit3_root2);
-
-		find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1],
-				   chk_syndrome_list[2], bit3_root0_inv,
-				   bit3_root1_inv, bit3_root2_inv, err_pats);
-
-		//check if only 3-bit error
-		tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv);
-		tmp0 = gf4096_mul(tmp0, tmp0);
-		tmp0 = gf4096_mul(tmp0, bit3_root0_inv);
-		tmp0 = gf4096_mul(tmp0, bit3_root0_inv);	//rinv0^6
-		tmp1 = gf4096_mul(tmp0, bit3_root0_inv);	//rinv0^7
-		tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv);
-		tmp2 = gf4096_mul(tmp2, tmp2);
-		tmp2 = gf4096_mul(tmp2, bit3_root1_inv);
-		tmp2 = gf4096_mul(tmp2, bit3_root1_inv);	//rinv1^6
-		tmp3 = gf4096_mul(tmp2, bit3_root1_inv);	//rinv1^7
-		tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv);
-		tmp4 = gf4096_mul(tmp4, tmp4);
-		tmp4 = gf4096_mul(tmp4, bit3_root2_inv);
-		tmp4 = gf4096_mul(tmp4, bit3_root2_inv);	//rinv2^6
-		tmp5 = gf4096_mul(tmp4, bit3_root2_inv);	//rinv2^7
-
-		//check if only 3 errors
-		if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^
-					      gf4096_mul(err_pats[1], tmp2) ^
-					      gf4096_mul(err_pats[2], tmp4))) &
-		    (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^
-					      gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) {
-			if ((err_pos(bit3_root0_inv) == 0xfff) |
-			    (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) {
-				return -EINVAL;
-			} else {
-				err_info[0] = 0x3;
-				err_info[1] = (0x55e - err_pos(bit3_root0_inv));
-				err_info[2] = (0x55e - err_pos(bit3_root1_inv));
-				err_info[3] = (0x55e - err_pos(bit3_root2_inv));
-				err_info[5] = err_pats[0];
-				err_info[6] = err_pats[1];
-				err_info[7] = err_pats[2];
-				return 0;
-			}
-		} else
-			return -EINVAL;
-	}
-}
-static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-	unsigned short coefs[4];
-	unsigned short err_pats[4];
-	int found_num_root = 0;
-	unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3;
-	unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv;
-	unsigned short err_loc_eqn, test_root;
-
-	find_4bit_err_coefs(chk_syndrome_list[0],
-			    chk_syndrome_list[1],
-			    chk_syndrome_list[2],
-			    chk_syndrome_list[3],
-			    chk_syndrome_list[4],
-			    chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs);
-
-	for (test_root = 0x1; test_root < 0xfff; test_root++) {
-		err_loc_eqn =
-		    gf4096_mul(coefs[3],
-			       gf4096_mul(gf4096_mul
-					  (gf4096_mul(test_root, test_root),
-					   test_root),
-					  test_root)) ^ gf4096_mul(coefs[2],
-								   gf4096_mul
-								   (gf4096_mul(test_root, test_root), test_root))
-		    ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root)
-		    ^ 0x1;
-		if (err_loc_eqn == 0x0) {
-			if (found_num_root == 0) {
-				bit4_root0 = test_root;
-				found_num_root = 1;
-			} else if (found_num_root == 1) {
-				bit4_root1 = test_root;
-				found_num_root = 2;
-			} else if (found_num_root == 2) {
-				bit4_root2 = test_root;
-				found_num_root = 3;
-			} else {
-				found_num_root = 4;
-				bit4_root3 = test_root;
-				break;
-			}
-		}
-	}
-	if (found_num_root != 4) {
-		return -EINVAL;
-	} else {
-		bit4_root0_inv = gf4096_inv(bit4_root0);
-		bit4_root1_inv = gf4096_inv(bit4_root1);
-		bit4_root2_inv = gf4096_inv(bit4_root2);
-		bit4_root3_inv = gf4096_inv(bit4_root3);
-		find_4bit_err_pats(chk_syndrome_list[0],
-				   chk_syndrome_list[1],
-				   chk_syndrome_list[2],
-				   chk_syndrome_list[3],
-				   bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats);
-		err_info[0] = 0x4;
-		err_info[1] = (0x55e - err_pos(bit4_root0_inv));
-		err_info[2] = (0x55e - err_pos(bit4_root1_inv));
-		err_info[3] = (0x55e - err_pos(bit4_root2_inv));
-		err_info[4] = (0x55e - err_pos(bit4_root3_inv));
-		err_info[5] = err_pats[0];
-		err_info[6] = err_pats[1];
-		err_info[7] = err_pats[2];
-		err_info[8] = err_pats[3];
-		return 0;
-	}
-}
-
-void correct_12bit_symbol(unsigned char *buf, unsigned short sym,
-			  unsigned short val)
-{
-	if (unlikely(sym > 1366)) {
-		printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym);
-	} else if (sym == 0) {
-		buf[0] ^= val;
-	} else if (sym & 1) {
-		buf[1+(3*(sym-1))/2] ^= (val >> 4);
-		buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4);
-	} else {
-		buf[2+(3*(sym-2))/2] ^= (val >> 8);
-		buf[3+(3*(sym-2))/2] ^= (val & 0xff);
-	}
-}
-
-static int debugecc = 0;
-module_param(debugecc, int, 0644);
-
-int cafe_correct_ecc(unsigned char *buf,
-		     unsigned short *chk_syndrome_list)
-{
-	unsigned short err_info[9];
-	int i;
-
-	if (debugecc) {
-		printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n",
-		       chk_syndrome_list[0], chk_syndrome_list[1],
-		       chk_syndrome_list[2], chk_syndrome_list[3],
-		       chk_syndrome_list[4], chk_syndrome_list[5],
-		       chk_syndrome_list[6], chk_syndrome_list[7]);
-		for (i=0; i < 2048; i+=16) {
-			printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-			       i,
-			       buf[i], buf[i+1], buf[i+2], buf[i+3],
-			       buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-			       buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-			       buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-		}
-		for ( ; i < 2112; i+=16) {
-			printk(KERN_WARNING "O   %02x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-			       i - 2048,
-			       buf[i], buf[i+1], buf[i+2], buf[i+3],
-			       buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-			       buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-			       buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-		}
-	}
-
-
-
-	if (chk_no_err_only(chk_syndrome_list, err_info) &&
-	    chk_1_err_only(chk_syndrome_list, err_info) &&
-	    chk_2_err_only(chk_syndrome_list, err_info) &&
-	    chk_3_err_only(chk_syndrome_list, err_info) &&
-	    chk_4_err_only(chk_syndrome_list, err_info)) {
-		return -EIO;
-	}
-
-	for (i=0; i < err_info[0]; i++) {
-		if (debugecc)
-			printk(KERN_WARNING "Correct symbol %d with 0x%03x\n",
-			       err_info[1+i], err_info[5+i]);
-
-		correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]);
-	}
-
-	return err_info[0];
-}
-
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe_nand.c
similarity index 87%
rename from drivers/mtd/nand/cafe.c
rename to drivers/mtd/nand/cafe_nand.c
index c328a75..cff969d 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -11,6 +11,7 @@
 #undef DEBUG
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/rslib.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -46,13 +47,14 @@
 #define CAFE_GLOBAL_IRQ_MASK	0x300c
 #define CAFE_NAND_RESET		0x3034
 
-int cafe_correct_ecc(unsigned char *buf,
-		     unsigned short *chk_syndrome_list);
+/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+#define CTRL1_CHIPSELECT	(1<<19)
 
 struct cafe_priv {
 	struct nand_chip nand;
 	struct pci_dev *pdev;
 	void __iomem *mmio;
+	struct rs_control *rs;
 	uint32_t ctl1;
 	uint32_t ctl2;
 	int datalen;
@@ -195,8 +197,8 @@
 
 	cafe->data_pos = cafe->datalen = 0;
 
-	/* Set command valid bit */
-	ctl1 = 0x80000000 | command;
+	/* Set command valid bit, mask in the chip select bit  */
+	ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
 
 	/* Set RD or WR bits as appropriate */
 	if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
@@ -309,8 +311,16 @@
 
 static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
 {
-	//struct cafe_priv *cafe = mtd->priv;
-	//	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+	struct cafe_priv *cafe = mtd->priv;
+
+	cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+
+	/* Mask the appropriate bit into the stored value of ctl1
+	   which will be used by cafe_nand_cmdfunc() */
+	if (chipnr)
+		cafe->ctl1 |= CTRL1_CHIPSELECT;
+	else
+		cafe->ctl1 &= ~CTRL1_CHIPSELECT;
 }
 
 static int cafe_nand_interrupt(int irq, void *id)
@@ -374,28 +384,66 @@
 	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
 	if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
-		unsigned short syn[8];
-		int i;
+		unsigned short syn[8], pat[4];
+		int pos[4];
+		u8 *oob = chip->oob_poi;
+		int i, n;
 
 		for (i=0; i<8; i+=2) {
 			uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
-			syn[i] = tmp & 0xfff;
-			syn[i+1] = (tmp >> 16) & 0xfff;
+			syn[i] = cafe->rs->index_of[tmp & 0xfff];
+			syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
 		}
 
-		if ((i = cafe_correct_ecc(buf, syn)) < 0) {
+		n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+		                pat);
+
+		for (i = 0; i < n; i++) {
+			int p = pos[i];
+
+			/* The 12-bit symbols are mapped to bytes here */
+
+			if (p > 1374) {
+				/* out of range */
+				n = -1374;
+			} else if (p == 0) {
+				/* high four bits do not correspond to data */
+				if (pat[i] > 0xff)
+					n = -2048;
+				else
+					buf[0] ^= pat[i];
+			} else if (p == 1365) {
+				buf[2047] ^= pat[i] >> 4;
+				oob[0] ^= pat[i] << 4;
+			} else if (p > 1365) {
+				if ((p & 1) == 1) {
+					oob[3*p/2 - 2048] ^= pat[i] >> 4;
+					oob[3*p/2 - 2047] ^= pat[i] << 4;
+				} else {
+					oob[3*p/2 - 2049] ^= pat[i] >> 8;
+					oob[3*p/2 - 2048] ^= pat[i];
+				}
+			} else if ((p & 1) == 1) {
+				buf[3*p/2] ^= pat[i] >> 4;
+				buf[3*p/2 + 1] ^= pat[i] << 4;
+			} else {
+				buf[3*p/2 - 1] ^= pat[i] >> 8;
+				buf[3*p/2] ^= pat[i];
+			}
+		}
+
+		if (n < 0) {
 			dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
 				cafe_readl(cafe, NAND_ADDR2) * 2048);
-			for (i=0; i< 0x5c; i+=4)
+			for (i = 0; i < 0x5c; i += 4)
 				printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
 			mtd->ecc_stats.failed++;
 		} else {
-			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
-			mtd->ecc_stats.corrected += i;
+			dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+			mtd->ecc_stats.corrected += n;
 		}
 	}
 
-
 	return 0;
 }
 
@@ -416,7 +464,7 @@
 
 static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
 	.offs =	14,
 	.len = 4,
 	.veroffs = 18,
@@ -426,7 +474,7 @@
 
 static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
 	.offs =	14,
 	.len = 4,
 	.veroffs = 18,
@@ -442,7 +490,7 @@
 
 static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
 	.offs =	14,
 	.len = 1,
 	.veroffs = 15,
@@ -452,7 +500,7 @@
 
 static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+		| NAND_BBT_2BIT | NAND_BBT_VERSION,
 	.offs =	14,
 	.len = 1,
 	.veroffs = 15,
@@ -525,6 +573,48 @@
 	return 0;
 }
 
+/* F_2[X]/(X**6+X+1)  */
+static unsigned short __devinit gf64_mul(u8 a, u8 b)
+{
+	u8 c;
+	unsigned int i;
+
+	c = 0;
+	for (i = 0; i < 6; i++) {
+		if (a & 1)
+			c ^= b;
+		a >>= 1;
+		b <<= 1;
+		if ((b & 0x40) != 0)
+			b ^= 0x43;
+	}
+
+	return c;
+}
+
+/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
+static u16 __devinit gf4096_mul(u16 a, u16 b)
+{
+	u8 ah, al, bh, bl, ch, cl;
+
+	ah = a >> 6;
+	al = a & 0x3f;
+	bh = b >> 6;
+	bl = b & 0x3f;
+
+	ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+	cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+
+	return (ch << 6) ^ cl;
+}
+
+static int __devinit cafe_mul(int x)
+{
+	if (x == 0)
+		return 1;
+	return gf4096_mul(x, 0xe01);
+}
+
 static int __devinit cafe_nand_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
@@ -564,6 +654,12 @@
 	}
 	cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
 
+	cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+	if (!cafe->rs) {
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
 	cafe->nand.cmdfunc = cafe_nand_cmdfunc;
 	cafe->nand.dev_ready = cafe_device_ready;
 	cafe->nand.read_byte = cafe_read_byte;
@@ -646,7 +742,7 @@
 		cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
 
 	/* Scan to find existence of the device */
-	if (nand_scan_ident(mtd, 1)) {
+	if (nand_scan_ident(mtd, 2)) {
 		err = -ENXIO;
 		goto out_irq;
 	}
@@ -713,6 +809,7 @@
 	cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
 	free_irq(pdev->irq, mtd);
 	nand_release(mtd);
+	free_rs(cafe->rs);
 	pci_iounmap(pdev, cafe->mmio);
 	dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
 	kfree(mtd);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 04de315..7e68203 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -303,28 +303,27 @@
 	struct nand_chip *chip = mtd->priv;
 	u16 bad;
 
+	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
 	if (getchip) {
-		page = (int)(ofs >> chip->page_shift);
 		chipnr = (int)(ofs >> chip->chip_shift);
 
 		nand_get_device(chip, mtd, FL_READING);
 
 		/* Select the NAND device */
 		chip->select_chip(mtd, chipnr);
-	} else
-		page = (int)(ofs >> chip->page_shift);
+	}
 
 	if (chip->options & NAND_BUSWIDTH_16) {
 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-			      page & chip->pagemask);
+			      page);
 		bad = cpu_to_le16(chip->read_word(mtd));
 		if (chip->badblockpos & 0x1)
 			bad >>= 8;
 		if ((bad & 0xFF) != 0xff)
 			res = 1;
 	} else {
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
-			      page & chip->pagemask);
+		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
 		if (chip->read_byte(mtd) != 0xff)
 			res = 1;
 	}
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
new file mode 100644
index 0000000..cd725fc
--- /dev/null
+++ b/drivers/mtd/nand/plat_nand.c
@@ -0,0 +1,150 @@
+/*
+ * Generic NAND driver
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+struct plat_nand_data {
+	struct nand_chip	chip;
+	struct mtd_info		mtd;
+	void __iomem		*io_base;
+#ifdef CONFIG_MTD_PARTITIONS
+	int			nr_parts;
+	struct mtd_partition	*parts;
+#endif
+};
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init plat_nand_probe(struct platform_device *pdev)
+{
+	struct platform_nand_data *pdata = pdev->dev.platform_data;
+	struct plat_nand_data *data;
+	int res = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "failed to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	data->io_base = ioremap(pdev->resource[0].start,
+				pdev->resource[0].end - pdev->resource[0].start + 1);
+	if (data->io_base == NULL) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		kfree(data);
+		return -EIO;
+	}
+
+	data->chip.priv = &data;
+	data->mtd.priv = &data->chip;
+	data->mtd.owner = THIS_MODULE;
+
+	data->chip.IO_ADDR_R = data->io_base;
+	data->chip.IO_ADDR_W = data->io_base;
+	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+	data->chip.dev_ready = pdata->ctrl.dev_ready;
+	data->chip.select_chip = pdata->ctrl.select_chip;
+	data->chip.chip_delay = pdata->chip.chip_delay;
+	data->chip.options |= pdata->chip.options;
+
+	data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+	data->chip.ecc.layout = pdata->chip.ecclayout;
+	data->chip.ecc.mode = NAND_ECC_SOFT;
+
+	platform_set_drvdata(pdev, data);
+
+	/* Scan to find existance of the device */
+	if (nand_scan(&data->mtd, 1)) {
+		res = -ENXIO;
+		goto out;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	if (pdata->chip.part_probe_types) {
+		res = parse_mtd_partitions(&data->mtd,
+					pdata->chip.part_probe_types,
+					&data->parts, 0);
+		if (res > 0) {
+			add_mtd_partitions(&data->mtd, data->parts, res);
+			return 0;
+		}
+	}
+	if (pdata->chip.partitions) {
+		data->parts = pdata->chip.partitions;
+		res = add_mtd_partitions(&data->mtd, data->parts,
+			pdata->chip.nr_partitions);
+	} else
+#endif
+	res = add_mtd_device(&data->mtd);
+
+	if (!res)
+		return res;
+
+	nand_release(&data->mtd);
+out:
+	platform_set_drvdata(pdev, NULL);
+	iounmap(data->io_base);
+	kfree(data);
+	return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit plat_nand_remove(struct platform_device *pdev)
+{
+	struct plat_nand_data *data = platform_get_drvdata(pdev);
+	struct platform_nand_data *pdata = pdev->dev.platform_data;
+
+	nand_release(&data->mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+	if (data->parts && data->parts != pdata->chip.partitions)
+		kfree(data->parts);
+#endif
+	iounmap(data->io_base);
+	kfree(data);
+
+	return 0;
+}
+
+static struct platform_driver plat_nand_driver = {
+	.probe		= plat_nand_probe,
+	.remove		= plat_nand_remove,
+	.driver		= {
+		.name	= "gen_nand",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init plat_nand_init(void)
+{
+	return platform_driver_register(&plat_nand_driver);
+}
+
+static void __exit plat_nand_exit(void)
+{
+	platform_driver_unregister(&plat_nand_driver);
+}
+
+module_init(plat_nand_init);
+module_exit(plat_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Simple generic NAND driver");
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 000794c..0537fac 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -2192,7 +2192,7 @@
  * @param mtd		MTD device structure
  *
  * OneNAND detection method:
- *   Compare the the values from command with ones from register
+ *   Compare the values from command with ones from register
  */
 static int onenand_probe(struct mtd_info *mtd)
 {
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 9588da3..127f608 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -95,8 +95,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
-static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
+static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
 
 #if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA))
 #define EL3_SUSPEND
@@ -360,7 +359,7 @@
 	printk(", IRQ %d.\n", dev->irq);
 
 	if (el3_debug > 0)
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+		printk(KERN_INFO "%s", version);
 	return 0;
 
 }
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80924f7..f26ca33 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -103,7 +103,7 @@
 
 
 static char version[] __devinitdata =
-DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
+DRV_NAME ": Donald Becker and others.\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6db12d0..fa489b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2513,6 +2513,8 @@
 
 source "drivers/net/wireless/Kconfig"
 
+source "drivers/net/usb/Kconfig"
+
 source "drivers/net/pcmcia/Kconfig"
 
 source "drivers/net/wan/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7faeeea..a77affa 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -207,6 +207,14 @@
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
 obj-$(CONFIG_NET_PCMCIA) += pcmcia/
+
+obj-$(CONFIG_USB_CATC)          += usb/
+obj-$(CONFIG_USB_KAWETH)        += usb/
+obj-$(CONFIG_USB_PEGASUS)       += usb/
+obj-$(CONFIG_USB_RTL8150)       += usb/
+obj-$(CONFIG_USB_USBNET)        += usb/
+obj-$(CONFIG_USB_ZD1201)        += usb/
+
 obj-y += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index d28f88b..78cf00f 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -2038,6 +2038,15 @@
 	return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void atl1_poll_controller(struct net_device *netdev)
+{
+	disable_irq(netdev->irq);
+	atl1_intr(netdev->irq, netdev);
+	enable_irq(netdev->irq);
+}
+#endif
+
 /*
  * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
  * will assert. We do soft reset <0x1400=1> according
@@ -2190,6 +2199,9 @@
 	netdev->do_ioctl = &atl1_ioctl;
 	netdev->tx_timeout = &atl1_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = atl1_poll_controller;
+#endif
 	netdev->vlan_rx_register = atl1_vlan_rx_register;
 	netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
 	netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 18aba83..82d78ff 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -31,10 +31,8 @@
 
 */
 
-static const char versionA[] =
+static const char version[] =
 "atp.c:v1.09=ac 2002/10/01 Donald Becker <becker@scyld.com>\n";
-static const char versionB[] =
-"  http://www.scyld.com/network/atp.html\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -324,7 +322,7 @@
 
 #ifndef MODULE
 	if (net_debug)
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+		printk(KERN_INFO "%s", version);
 #endif
 
 	printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
@@ -926,7 +924,7 @@
 
 static int __init atp_init_module(void) {
 	if (debug)					/* Emit version even if no cards detected. */
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+		printk(KERN_INFO "%s", version);
 	return atp_init();
 }
 
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 724bce5..223517d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3461,7 +3461,7 @@
 /*---------------------------- Hashing Policies -----------------------------*/
 
 /*
- * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * Hash for the output device based upon layer 3 and layer 4 data. If
  * the packet is a frag or not TCP or UDP, just use layer 3 data.  If it is
  * altogether not IP, mimic bond_xmit_hash_policy_l2()
  */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 3a03a74..637ae8f 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1214,7 +1214,7 @@
 	int i;
 #endif
 
-	flush_scheduled_work();
+	cancel_work_sync(&adapter->reset_task);
 
 	e1000_release_manageability(adapter);
 
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 39654e1..4768023 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1126,7 +1126,7 @@
 	printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
 		"network cable problem");
 	/* This is not a duplicate. One message for the console,
-	   one for the the log file  */
+	   one for the log file  */
 	printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
 		"network cable problem");
 	eepro_complete_selreset(ioaddr);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 6c267c3..98003419 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -28,7 +28,7 @@
 */
 
 static const char * const version =
-"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://www.scyld.com/network/eepro100.html\n"
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n"
 "eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
 
 /* A few user-configurable values that apply to all boards.
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4e3f14c..5e51794 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -93,8 +93,6 @@
 static char version[] __devinitdata =
 DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
 static char version2[] __devinitdata =
-"  http://www.scyld.com/network/epic100.html\n";
-static char version3[] __devinitdata =
 "  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -323,8 +321,8 @@
 #ifndef MODULE
 	static int printed_version;
 	if (!printed_version++)
-		printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-			version, version2, version3);
+		printk (KERN_INFO "%s" KERN_INFO "%s",
+			version, version2);
 #endif
 
 	card_idx++;
@@ -1596,8 +1594,8 @@
 {
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
-	printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-		version, version2, version3);
+	printk (KERN_INFO "%s" KERN_INFO "%s",
+		version, version2);
 #endif
 
 	return pci_register_driver(&epic_driver);
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 6e90619..36d2c7d 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -140,7 +140,7 @@
 	  modems that connect to a serial interface. The driver supports the
 	  ser12 design in half-duplex mode. This is the old driver.  It is
 	  still provided in case your serial interface chip does not work with
-	  the full-duplex driver. This driver is depreciated.  To configure
+	  the full-duplex driver. This driver is deprecated.  To configure
 	  the driver, use the sethdlc utility available in the standard ax25
 	  utilities package. For information on the modems, see
 	  <http://www.baycom.de/> and
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 2ab173d..1e67720f 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -113,7 +113,7 @@
 /* RxOver  overflow in Recv FIFO                                */
 /* SipRcv  received serial gap  (or other condition you set)    */
 /* Interrupts are enabled by writing a one to the IER register  */
-/* Interrupts are cleared by writting a one to the ISR register */
+/* Interrupts are cleared by writing a one to the ISR register */
 /*                                                              */
 /* 6. The remaining registers: 0x6 and 0x3 appear to be         */
 /*    reserved parts of 16 or 32 bit registersthe remainder     */
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index f15aebd..52c99d0 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -315,7 +315,7 @@
  * hw - Struct containing variables accessed by shared code
  *
  * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * If the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
  * valid.
  *
  * Returns:
diff --git a/drivers/net/meth.h b/drivers/net/meth.h
index 84960da..ea3b8fc 100644
--- a/drivers/net/meth.h
+++ b/drivers/net/meth.h
@@ -126,7 +126,7 @@
 				       /*   Note: when loopback is set this bit becomes collision control.  Setting this bit will */
 				       /*         cause a collision to be reported. */
 
-				       /* Bits 5 and 6 are used to determine the the Destination address filter mode */
+				       /* Bits 5 and 6 are used to determine the Destination address filter mode */
 #define METH_ACCEPT_MY 0			/* 00: Accept PHY address only */
 #define METH_ACCEPT_MCAST 0x20	/* 01: Accept physical, broadcast, and multicast filter matches only */
 #define METH_ACCEPT_AMCAST 0x40	/* 10: Accept physical, broadcast, and all multicast packets */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 223e0e6..4cf0d3f 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -131,7 +131,6 @@
   KERN_INFO DRV_NAME " dp8381x driver, version "
       DRV_VERSION ", " DRV_RELDATE "\n"
   KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
-  KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
   KERN_INFO "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 589785d..995c0a5 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -63,8 +63,7 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n"
-KERN_INFO "  http://www.scyld.com/network/ne2k-pci.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
 
 #if defined(__powerpc__)
 #define inl_le(addr)  le32_to_cpu(inl(addr))
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 1060154..4ecb8ca 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -189,16 +189,20 @@
 {
     struct ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
+     struct tok_info *ti = netdev_priv(dev);
 
     DEBUG(0, "ibmtr_detach(0x%p)\n", link);
+    
+    /* 
+     * When the card removal interrupt hits tok_interrupt(), 
+     * bail out early, so we don't crash the machine 
+     */
+    ti->sram_phys |= 1;
 
     if (link->dev_node)
 	unregister_netdev(dev);
-
-    {
-	struct tok_info *ti = netdev_priv(dev);
-	del_timer_sync(&(ti->tr_timer));
-    }
+    
+    del_timer_sync(&(ti->tr_timer));
 
     ibmtr_release(link);
 
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index eed433d..f71dab3 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -662,10 +662,10 @@
 		phy_error(phydev);
 
 	/*
-	 * Finish any pending work; we might have been scheduled
-	 * to be called from keventd ourselves, though.
+	 * Finish any pending work; we might have been scheduled to be called
+	 * from keventd ourselves, but cancel_work_sync() handles that.
 	 */
-	run_scheduled_work(&phydev->phy_queue);
+	cancel_work_sync(&phydev->phy_queue);
 
 	free_irq(phydev->irq, phydev);
 
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index b07da10..e048957 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3594,7 +3594,9 @@
 	skge->duplex = -1;
 	skge->speed = -1;
 	skge->advertising = skge_supported_modes(hw);
-	skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
+
+	if (pci_wake_enabled(hw->pdev))
+		skge->wol = wol_supported(hw) & WAKE_MAGIC;
 
 	hw->dev[port] = dev;
 
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index f51ba31..e1f912d 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -110,8 +110,7 @@
 
 /* These identify the driver base version and may not be removed. */
 static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
-KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e5e901e..923b9c7 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3716,10 +3716,8 @@
 	unsigned int restart_timer;
 
 	tg3_full_lock(tp, 0);
-	tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
 
 	if (!netif_running(tp->dev)) {
-		tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
 		tg3_full_unlock(tp);
 		return;
 	}
@@ -3750,8 +3748,6 @@
 		mod_timer(&tp->timer, jiffies + 1);
 
 out:
-	tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
-
 	tg3_full_unlock(tp);
 }
 
@@ -7390,12 +7386,7 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 
-	/* Calling flush_scheduled_work() may deadlock because
-	 * linkwatch_event() may be on the workqueue and it will try to get
-	 * the rtnl_lock which we are holding.
-	 */
-	while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
-		msleep(1);
+	cancel_work_sync(&tp->reset_task);
 
 	netif_stop_queue(dev);
 
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 4d334cf..bd9f4f4 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2228,7 +2228,7 @@
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
-#define TG3_FLAG_IN_RESET_TASK		0x04000000
+
 #define TG3_FLAG_40BIT_DMA_BUG		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
 #define TG3_FLAG_SUPPORT_MSI		0x20000000
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 9b08afb..ea89677 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -269,7 +269,7 @@
             This would turn on IM for devices that is not contributing
             to backlog congestion with unnecessary latency.
 
-             We monitor the the device RX-ring and have:
+             We monitor the device RX-ring and have:
 
              HW Interrupt Mitigation either ON or OFF.
 
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index fa44070..38f3b99 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1021,7 +1021,7 @@
 		np->tx_ring[entry].length |= DescEndRing;
 
 	/* Now acquire the irq spinlock.
-	 * The difficult race is the the ordering between
+	 * The difficult race is the ordering between
 	 * increasing np->cur_tx and setting DescOwned:
 	 * - if np->cur_tx is increased first the interrupt
 	 *   handler could consider the packet as transmitted
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 985a181..2470b1e 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -1043,7 +1043,7 @@
 
 
 /*
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
 
 Must be called in locked state with interrupts disabled
 */
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index f2dd776..f725735 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -639,7 +639,7 @@
 
 	typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
 
-	/* "I feel a presence... another warrior is on the the mesa."
+	/* "I feel a presence... another warrior is on the mesa."
 	 */
 	wmb();
 	iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
diff --git a/drivers/usb/net/Kconfig b/drivers/net/usb/Kconfig
similarity index 100%
rename from drivers/usb/net/Kconfig
rename to drivers/net/usb/Kconfig
diff --git a/drivers/usb/net/Makefile b/drivers/net/usb/Makefile
similarity index 100%
rename from drivers/usb/net/Makefile
rename to drivers/net/usb/Makefile
diff --git a/drivers/usb/net/asix.c b/drivers/net/usb/asix.c
similarity index 100%
rename from drivers/usb/net/asix.c
rename to drivers/net/usb/asix.c
diff --git a/drivers/usb/net/catc.c b/drivers/net/usb/catc.c
similarity index 100%
rename from drivers/usb/net/catc.c
rename to drivers/net/usb/catc.c
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/net/usb/cdc_ether.c
similarity index 100%
rename from drivers/usb/net/cdc_ether.c
rename to drivers/net/usb/cdc_ether.c
diff --git a/drivers/usb/net/cdc_subset.c b/drivers/net/usb/cdc_subset.c
similarity index 100%
rename from drivers/usb/net/cdc_subset.c
rename to drivers/net/usb/cdc_subset.c
diff --git a/drivers/usb/net/dm9601.c b/drivers/net/usb/dm9601.c
similarity index 100%
rename from drivers/usb/net/dm9601.c
rename to drivers/net/usb/dm9601.c
diff --git a/drivers/usb/net/gl620a.c b/drivers/net/usb/gl620a.c
similarity index 100%
rename from drivers/usb/net/gl620a.c
rename to drivers/net/usb/gl620a.c
diff --git a/drivers/usb/net/kaweth.c b/drivers/net/usb/kaweth.c
similarity index 100%
rename from drivers/usb/net/kaweth.c
rename to drivers/net/usb/kaweth.c
diff --git a/drivers/usb/net/kawethfw.h b/drivers/net/usb/kawethfw.h
similarity index 100%
rename from drivers/usb/net/kawethfw.h
rename to drivers/net/usb/kawethfw.h
diff --git a/drivers/usb/net/mcs7830.c b/drivers/net/usb/mcs7830.c
similarity index 100%
rename from drivers/usb/net/mcs7830.c
rename to drivers/net/usb/mcs7830.c
diff --git a/drivers/usb/net/net1080.c b/drivers/net/usb/net1080.c
similarity index 100%
rename from drivers/usb/net/net1080.c
rename to drivers/net/usb/net1080.c
diff --git a/drivers/usb/net/pegasus.c b/drivers/net/usb/pegasus.c
similarity index 100%
rename from drivers/usb/net/pegasus.c
rename to drivers/net/usb/pegasus.c
diff --git a/drivers/usb/net/pegasus.h b/drivers/net/usb/pegasus.h
similarity index 100%
rename from drivers/usb/net/pegasus.h
rename to drivers/net/usb/pegasus.h
diff --git a/drivers/usb/net/plusb.c b/drivers/net/usb/plusb.c
similarity index 100%
rename from drivers/usb/net/plusb.c
rename to drivers/net/usb/plusb.c
diff --git a/drivers/usb/net/rndis_host.c b/drivers/net/usb/rndis_host.c
similarity index 100%
rename from drivers/usb/net/rndis_host.c
rename to drivers/net/usb/rndis_host.c
diff --git a/drivers/usb/net/rtl8150.c b/drivers/net/usb/rtl8150.c
similarity index 100%
rename from drivers/usb/net/rtl8150.c
rename to drivers/net/usb/rtl8150.c
diff --git a/drivers/usb/net/usbnet.c b/drivers/net/usb/usbnet.c
similarity index 100%
rename from drivers/usb/net/usbnet.c
rename to drivers/net/usb/usbnet.c
diff --git a/drivers/usb/net/usbnet.h b/drivers/net/usb/usbnet.h
similarity index 98%
rename from drivers/usb/net/usbnet.h
rename to drivers/net/usb/usbnet.h
index cbb53e0..82db5a8 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -129,7 +129,7 @@
 
 
 /* Drivers that reuse some of the standard USB CDC infrastructure
- * (notably, using multiple interfaces according to the the CDC
+ * (notably, using multiple interfaces according to the CDC
  * union descriptor) get some helper code.
  */
 struct cdc_state {
diff --git a/drivers/usb/net/zaurus.c b/drivers/net/usb/zaurus.c
similarity index 100%
rename from drivers/usb/net/zaurus.c
rename to drivers/net/usb/zaurus.c
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 38fac3b..7d5b8c2 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -149,7 +149,7 @@
 	/* Vitally important.  If we don't do this it seems we get an
 	 * interrupt somewhere during the power cycle, since
 	 * hw_unavailable is already set it doesn't get ACKed, we get
-	 * into an interrupt loop and the the PMU decides to turn us
+	 * into an interrupt loop and the PMU decides to turn us
 	 * off. */
 	disable_irq(dev->irq);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index f8483c1..10e07e8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -658,12 +658,6 @@
 
 #define BCM43xx_MAX_80211_CORES		2
 
-#ifdef CONFIG_BCM947XX
-#define core_offset(bcm) (bcm)->current_core_offset
-#else
-#define core_offset(bcm) 0
-#endif
-
 /* Generic information about a core. */
 struct bcm43xx_coreinfo {
 	u8 available:1,
@@ -789,10 +783,6 @@
 
 	/* The currently active core. */
 	struct bcm43xx_coreinfo *current_core;
-#ifdef CONFIG_BCM947XX
-	/** current core memory offset */
-	u32 current_core_offset;
-#endif
 	struct bcm43xx_coreinfo *active_80211_core;
 	/* coreinfo structs for all possible cores follow.
 	 * Note that a core might not exist.
@@ -943,25 +933,25 @@
 static inline
 u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread16(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
 {
-	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite16(value, bcm->mmio_addr + offset);
 }
 
 static inline
 u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread32(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
 {
-	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite32(value, bcm->mmio_addr + offset);
 }
 
 static inline
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index e3d2e61..1f7731f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -660,10 +660,6 @@
 	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
 	if (dma64)
 		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
-#endif
 
 	ring->bcm = bcm;
 	ring->nr_slots = nr_slots;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 5e96bca..ef6b253 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -61,10 +61,6 @@
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_BCM947XX
-extern char *nvram_get(char *name);
-#endif
-
 #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
@@ -142,10 +138,6 @@
 	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 43XG 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#ifdef CONFIG_BCM947XX
-	/* SB bus on BCM947xx */
-	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#endif
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
@@ -786,9 +778,6 @@
 {
 	u16 value;
 	u16 *sprom;
-#ifdef CONFIG_BCM947XX
-	char *c;
-#endif
 
 	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
 			GFP_KERNEL);
@@ -796,28 +785,7 @@
 		printk(KERN_ERR PFX "sprom_extract OOM\n");
 		return -ENOMEM;
 	}
-#ifdef CONFIG_BCM947XX
-	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
-	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
-
-	if ((c = nvram_get("il0macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
-
-	if ((c = nvram_get("et1macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
-
-	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
-	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
-	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
-
-	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
-	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
-	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
-
-	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
-#else
 	bcm43xx_sprom_read(bcm, sprom);
-#endif
 
 	/* boardflags2 */
 	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
@@ -1225,12 +1193,6 @@
 			goto error;
 		udelay(10);
 	}
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		bcm->current_core_offset = 0x1000 * core;
-	else
-		bcm->current_core_offset = 0;
-#endif
 
 	return 0;
 error:
@@ -1387,19 +1349,6 @@
 
 	if ((bcm43xx_core_enabled(bcm)) &&
 	    !bcm43xx_using_pio(bcm)) {
-//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
-#if 0
-#ifndef CONFIG_BCM947XX
-		/* reset all used DMA controllers. */
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		if (bcm->current_core->rev < 5)
-			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-#endif
-#endif
 	}
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -2140,32 +2089,11 @@
 	return err;
 }
 
-#ifdef CONFIG_BCM947XX
-static struct pci_device_id bcm43xx_47xx_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-	{ 0 }
-};
-#endif
-
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
 	int err;
 
 	bcm->irq = bcm->pci_dev->irq;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0) {
-		struct pci_dev *d;
-		struct pci_device_id *id;
-		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
-			d = pci_get_device(id->vendor, id->device, NULL);
-			if (d != NULL) {
-				bcm->irq = d->irq;
-				pci_dev_put(d);
-				break;
-			}
-		}
-	}
-#endif
 	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
 			  IRQF_SHARED, KBUILD_MODNAME, bcm);
 	if (err)
@@ -2645,10 +2573,6 @@
 			chip_id_16 = 0x4610;
 		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
 			chip_id_16 = 0x4710;
-#ifdef CONFIG_BCM947XX
-		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
-			chip_id_16 = 0x4309;
-#endif
 		else {
 			printk(KERN_ERR PFX "Could not determine Chip ID\n");
 			return -ENODEV;
@@ -4144,11 +4068,6 @@
 	struct bcm43xx_private *bcm;
 	int err;
 
-#ifdef CONFIG_BCM947XX
-	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
-		return -ENODEV;
-#endif
-
 #ifdef DEBUG_SINGLE_DEVICE_ONLY
 	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
 		return -ENODEV;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index f763571..c8f3c53 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -33,25 +33,6 @@
 
 #include "bcm43xx.h"
 
-#ifdef CONFIG_BCM947XX
-#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-
-static inline void e_aton(char *str, char *dest)
-{
-	int i = 0;
-	u16 *d = (u16 *) dest;
-
-	for (;;) {
-		dest[i++] = (char) simple_strtoul(str, NULL, 16);
-		str += 2;
-		if (!*str++ || i == 6)
-			break;
-	}
-	for (i = 0; i < 3; i++)
-		d[i] = cpu_to_be16(d[i]);
-}
-#endif
-
 #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
 /* Magic helper macro to pad structures. Ignore those above. It's magic. */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 841b3c1..283be4a 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -3054,7 +3054,7 @@
 	(iw_handler) prism54_set_wap,	/* SIOCSIWAP */
 	(iw_handler) prism54_get_wap,	/* SIOCGIWAP */
 	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) NULL,	/* SIOCGIWAPLIST depreciated */
+	(iw_handler) NULL,	/* SIOCGIWAPLIST deprecated */
 	(iw_handler) prism54_set_scan,	/* SIOCSIWSCAN */
 	(iw_handler) prism54_get_scan,	/* SIOCGIWSCAN */
 	(iw_handler) prism54_set_essid,	/* SIOCSIWESSID */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index a037b11..0847953 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -115,7 +115,7 @@
 			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
 			u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
 
-			/* set the cards base address for writting the data */
+			/* set the card's base address for writing the data */
 			isl38xx_w32_flush(device_base, reg,
 					  ISL38XX_DIR_MEM_BASE_REG);
 			wmb();	/* be paranoid */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 67b867f8..5740d4d 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -176,7 +176,7 @@
   volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
     (psaoff(0, psa_comp_number) << 1);
 
-  /* Authorize writting to PSA */
+  /* Authorize writing to PSA */
   hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
 
   while(n-- > 0)
@@ -1676,7 +1676,7 @@
       fee_write(base, 0x60,
 		dac, 2);
 
-      /* We now should verify here that the EEprom writting was ok */
+      /* We now should verify here that the EEprom writing was ok */
 
       /* ReRead the first area */
       fee_read(base, 0x00,
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 4d1c490..4b9de009 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -120,7 +120,7 @@
  * the Wavelan itself (NCR -> AT&T -> Lucent).
  *
  * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * writing a Wavelan ISA driver for the MACH microkernel. Girish
  * Welling <welling@paul.rutgers.edu> had also worked on it.
  * Keith Moore modify this for the Pcmcia hardware.
  * 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index e04cffc..8459549 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -40,6 +40,7 @@
 	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
@@ -67,8 +68,11 @@
 	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
 	{}
 };
 
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 3f4a7cf..f2a90a7 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -109,7 +109,6 @@
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  http://www.scyld.com/network/yellowfin.html\n"
 KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 3bb7739..8e58ea3 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -119,7 +119,7 @@
  * system is in its list of supported devices.  Returns the matching
  * pci_device_id structure or %NULL if there is no match.
  *
- * Depreciated, don't use this as it will not catch any dynamic ids
+ * Deprecated, don't use this as it will not catch any dynamic ids
  * that a driver might want to check for.
  */
 const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5e43983..76422ed 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -98,7 +98,7 @@
 	bool "RTC UIE emulation on dev interface"
 	depends on RTC_INTF_DEV
 	help
-	  Provides an emulation for RTC_UIE if the underlaying rtc chip
+	  Provides an emulation for RTC_UIE if the underlying rtc chip
 	  driver does not expose RTC_UIE ioctls.  Those requests generate
 	  once-per-second update interrupts, used for synchronization.
 
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 6abf481..e0f91df 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -104,7 +104,7 @@
 
 	writeb(tmp, rtc->regbase + RCR1);
 
-	rtc_update_irq(&rtc->rtc_dev, 1, events);
+	rtc_update_irq(rtc->rtc_dev, 1, events);
 
 	spin_unlock(&rtc->lock);
 
@@ -139,7 +139,7 @@
 
 		rtc->rearm_aie = 1;
 
-		rtc_update_irq(&rtc->rtc_dev, 1, events);
+		rtc_update_irq(rtc->rtc_dev, 1, events);
 	}
 
 	spin_unlock(&rtc->lock);
@@ -153,7 +153,7 @@
 
 	spin_lock(&rtc->lock);
 
-	rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
+	rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
 
 	spin_unlock(&rtc->lock);
 
@@ -341,7 +341,7 @@
 		tm->tm_sec--;
 #endif
 
-	dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+	dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
 		"mday=%d, mon=%d, year=%d, wday=%d\n",
 		__FUNCTION__,
 		tm->tm_sec, tm->tm_min, tm->tm_hour,
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index bbd5b8b..d6b06ab 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -23,7 +23,7 @@
 
 /*
  * The room for the SCCB (only for writing) is not equal to a pages size
- * (as it is specified as the maximum size in the the SCLP documentation)
+ * (as it is specified as the maximum size in the SCLP documentation)
  * because of the additional data structure described above.
  */
 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 29d1760..0b96d49 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -2860,7 +2860,7 @@
 			if (!atomic_read(&queue->set_pci_flags_count)){
 				/*
 				 * there's no outstanding PCI any more, so we
-				 * have to request a PCI to be sure the the PCI
+				 * have to request a PCI to be sure that the PCI
 				 * will wake at some time in the future then we
 				 * can flush packed buffers that might still be
 				 * hanging around, which can happen if no
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 1f9554e..324899c 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -118,97 +118,32 @@
 
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF
 
-static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
 {
-	int i;
+	int idx;
 
 	adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
 				    GFP_KERNEL);
-
 	if (!adapter->req_list)
 		return -ENOMEM;
 
-	for (i=0; i<REQUEST_LIST_SIZE; i++)
-		INIT_LIST_HEAD(&adapter->req_list[i]);
-
+	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+		INIT_LIST_HEAD(&adapter->req_list[idx]);
 	return 0;
 }
 
 static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
 {
-	struct zfcp_fsf_req *request, *tmp;
-	unsigned int i;
-
-	for (i=0; i<REQUEST_LIST_SIZE; i++) {
-		if (list_empty(&adapter->req_list[i]))
-			continue;
-
-		list_for_each_entry_safe(request, tmp,
-					 &adapter->req_list[i], list)
-			list_del(&request->list);
-	}
-
 	kfree(adapter->req_list);
 }
 
-void zfcp_reqlist_add(struct zfcp_adapter *adapter,
-		      struct zfcp_fsf_req *fsf_req)
-{
-	unsigned int i;
-
-	i = fsf_req->req_id % REQUEST_LIST_SIZE;
-	list_add_tail(&fsf_req->list, &adapter->req_list[i]);
-}
-
-void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
-{
-	struct zfcp_fsf_req *request, *tmp;
-	unsigned int i, counter;
-	u64 dbg_tmp[2];
-
-	i = req_id % REQUEST_LIST_SIZE;
-	BUG_ON(list_empty(&adapter->req_list[i]));
-
-	counter = 0;
-	list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
-		if (request->req_id == req_id) {
-			dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
-			dbg_tmp[1] = (u64) counter;
-			debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
-			list_del(&request->list);
-			break;
-		}
-		counter++;
-	}
-}
-
-struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
-					   unsigned long req_id)
-{
-	struct zfcp_fsf_req *request, *tmp;
-	unsigned int i;
-
-	/* 0 is reserved as an invalid req_id */
-	if (req_id == 0)
-		return NULL;
-
-	i = req_id % REQUEST_LIST_SIZE;
-
-	list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
-		if (request->req_id == req_id)
-			return request;
-
-	return NULL;
-}
-
 int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
 {
-	unsigned int i;
+	unsigned int idx;
 
-	for (i=0; i<REQUEST_LIST_SIZE; i++)
-		if (!list_empty(&adapter->req_list[i]))
+	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+		if (!list_empty(&adapter->req_list[idx]))
 			return 0;
-
 	return 1;
 }
 
@@ -913,6 +848,8 @@
 	unit->sysfs_device.release = zfcp_sysfs_unit_release;
 	dev_set_drvdata(&unit->sysfs_device, unit);
 
+	init_waitqueue_head(&unit->scsi_scan_wq);
+
 	/* mark unit unusable as long as sysfs registration is not complete */
 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
 
@@ -1104,7 +1041,7 @@
 
 	/* initialize list of fsf requests */
 	spin_lock_init(&adapter->req_list_lock);
-	retval = zfcp_reqlist_init(adapter);
+	retval = zfcp_reqlist_alloc(adapter);
 	if (retval) {
 		ZFCP_LOG_INFO("request list initialization failed\n");
 		goto failed_low_mem_buffers;
@@ -1165,6 +1102,7 @@
 	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
  sysfs_failed:
 	dev_set_drvdata(&ccw_device->dev, NULL);
+	zfcp_reqlist_free(adapter);
  failed_low_mem_buffers:
 	zfcp_free_low_mem_buffers(adapter);
 	if (qdio_free(ccw_device) != 0)
@@ -1497,7 +1435,7 @@
 
 	if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) {
 		ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port "
-			       "with d_id 0x%08x on adapter %s\n",
+			       "with d_id 0x%06x on adapter %s\n",
 			       status_buffer->d_id,
 			       zfcp_get_busid_by_adapter(adapter));
 	} else {
@@ -1522,7 +1460,7 @@
 
 	if (!port || (port->wwpn != els_logo->nport_wwpn)) {
 		ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port "
-			       "with d_id 0x%08x on adapter %s\n",
+			       "with d_id 0x%06x on adapter %s\n",
 			       status_buffer->d_id,
 			       zfcp_get_busid_by_adapter(adapter));
 	} else {
@@ -1704,7 +1642,7 @@
 	/* looks like a valid d_id */
         port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
 	atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
-	ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%08x\n",
+	ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%06x\n",
 		       zfcp_get_busid_by_port(port), port->wwpn, port->d_id);
 	goto out;
 
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 32933ed..2264963 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -637,6 +637,7 @@
 #define ZFCP_STATUS_UNIT_SHARED			0x00000004
 #define ZFCP_STATUS_UNIT_READONLY		0x00000008
 #define ZFCP_STATUS_UNIT_REGISTERED		0x00000010
+#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING	0x00000020
 
 /* FSF request status (this does not have a common part) */
 #define ZFCP_STATUS_FSFREQ_NOT_INIT		0x00000000
@@ -980,6 +981,10 @@
         struct scsi_device     *device;        /* scsi device struct pointer */
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
+	wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
+						  all scsi_scan_target
+						  requests have been
+						  completed. */
 };
 
 /* FSF request */
@@ -1085,6 +1090,42 @@
 #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
 
 /*
+ * Helper functions for request ID management.
+ */
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+	return req_id % REQUEST_LIST_SIZE;
+}
+
+static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+				    struct zfcp_fsf_req *fsf_req)
+{
+	unsigned int idx;
+
+	idx = zfcp_reqlist_hash(fsf_req->req_id);
+	list_add_tail(&fsf_req->list, &adapter->req_list[idx]);
+}
+
+static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
+				       struct zfcp_fsf_req *fsf_req)
+{
+	list_del(&fsf_req->list);
+}
+
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+	struct zfcp_fsf_req *request;
+	unsigned int idx;
+
+	idx = zfcp_reqlist_hash(req_id);
+	list_for_each_entry(request, &adapter->req_list[idx], list)
+		if (request->req_id == req_id)
+			return request;
+	return NULL;
+}
+
+/*
  *  functions needed for reference/usage counting
  */
 
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c1f2d4b..aef66bc 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -179,7 +179,7 @@
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-	zfcp_erp_adapter_reopen(adapter, 0);
+	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
 }
 
 void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
@@ -342,9 +342,9 @@
 	adisc->wwpn = fc_host_port_name(adapter->scsi_host);
 	adisc->wwnn = fc_host_node_name(adapter->scsi_host);
 	adisc->nport_id = fc_host_port_id(adapter->scsi_host);
-	ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
+	ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x "
 		      "(wwpn=0x%016Lx, wwnn=0x%016Lx, "
-		      "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+		      "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
 		      adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
 		      (wwn_t) adisc->wwnn, adisc->hard_nport_id,
 		      adisc->nport_id);
@@ -352,7 +352,7 @@
 	retval = zfcp_fsf_send_els(send_els);
 	if (retval != 0) {
 		ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
-				"0x%08x on adapter %s\n", send_els->d_id,
+				"0x%06x on adapter %s\n", send_els->d_id,
 				zfcp_get_busid_by_adapter(adapter));
 		goto freemem;
 	}
@@ -398,7 +398,7 @@
 	if (send_els->status != 0) {
 		ZFCP_LOG_NORMAL("ELS request rejected/timed out, "
 				"force physical port reopen "
-				"(adapter %s, port d_id=0x%08x)\n",
+				"(adapter %s, port d_id=0x%06x)\n",
 				zfcp_get_busid_by_adapter(adapter), d_id);
 		debug_text_event(adapter->erp_dbf, 3, "forcreop");
 		if (zfcp_erp_port_forced_reopen(port, 0))
@@ -411,9 +411,9 @@
 
 	adisc = zfcp_sg_to_address(send_els->resp);
 
-	ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
-		      "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
-		      "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+	ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id "
+		      "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+		      "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
 		      d_id, fc_host_port_id(adapter->scsi_host),
 		      (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
 		      adisc->hard_nport_id, adisc->nport_id);
@@ -847,8 +847,7 @@
 	if (erp_action->fsf_req) {
 		/* take lock to ensure that request is not deleted meanwhile */
 		spin_lock(&adapter->req_list_lock);
-		if (zfcp_reqlist_ismember(adapter,
-					    erp_action->fsf_req->req_id)) {
+		if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
 			/* fsf_req still exists */
 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
 			debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1377,7 +1376,7 @@
 
 	if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
 		ZFCP_LOG_NORMAL("port erp failed (adapter %s, "
-				"port d_id=0x%08x)\n",
+				"port d_id=0x%06x)\n",
 				zfcp_get_busid_by_port(port), port->d_id);
 	else
 		ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n",
@@ -1591,6 +1590,62 @@
 	return result;
 }
 
+struct zfcp_erp_add_work {
+	struct zfcp_unit  *unit;
+	struct work_struct work;
+};
+
+/**
+ * zfcp_erp_scsi_scan
+ * @data: pointer to a struct zfcp_erp_add_work
+ *
+ * Registers a logical unit with the SCSI stack.
+ */
+static void zfcp_erp_scsi_scan(struct work_struct *work)
+{
+	struct zfcp_erp_add_work *p =
+		container_of(work, struct zfcp_erp_add_work, work);
+	struct zfcp_unit *unit = p->unit;
+	struct fc_rport *rport = unit->port->rport;
+	scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
+			 unit->scsi_lun, 0);
+	atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+	wake_up(&unit->scsi_scan_wq);
+	zfcp_unit_put(unit);
+	kfree(p);
+}
+
+/**
+ * zfcp_erp_schedule_work
+ * @unit: pointer to unit which should be registered with SCSI stack
+ *
+ * Schedules work which registers a unit with the SCSI stack
+ */
+static void
+zfcp_erp_schedule_work(struct zfcp_unit *unit)
+{
+	struct zfcp_erp_add_work *p;
+
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
+				"the FCP-LUN 0x%Lx connected to "
+				"the port with WWPN 0x%Lx connected to "
+				"the adapter %s with the SCSI stack.\n",
+				unit->fcp_lun,
+				unit->port->wwpn,
+				zfcp_get_busid_by_unit(unit));
+		return;
+	}
+
+	zfcp_unit_get(unit);
+	memset(p, 0, sizeof(*p));
+	atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+	INIT_WORK(&p->work, zfcp_erp_scsi_scan);
+	p->unit = unit;
+	schedule_work(&p->work);
+}
+
 /*
  * function:	
  *
@@ -2401,7 +2456,7 @@
 				retval = ZFCP_ERP_FAILED;
 			}
 		} else {
-			ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> "
+			ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> "
 				       "trying open\n", port->wwpn, port->d_id);
 			retval = zfcp_erp_port_strategy_open_port(erp_action);
 		}
@@ -2441,7 +2496,7 @@
 	case ZFCP_ERP_STEP_UNINITIALIZED:
 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
 	case ZFCP_ERP_STEP_PORT_CLOSING:
-		ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n",
+		ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n",
 			       port->wwpn, port->d_id);
 		retval = zfcp_erp_port_strategy_open_port(erp_action);
 		break;
@@ -3092,9 +3147,9 @@
 		    && port->rport) {
 			atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
 					&unit->status);
- 			scsi_scan_target(&port->rport->dev, 0,
-					 port->rport->scsi_target_id,
-					 unit->scsi_lun, 0);
+			if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+					     &unit->status) == 0)
+				zfcp_erp_schedule_work(unit);
 		}
 		zfcp_unit_put(unit);
 		break;
@@ -3121,7 +3176,7 @@
 						zfcp_get_busid_by_port(port),
 						port->wwpn);
 			else {
-				scsi_flush_work(adapter->scsi_host);
+				scsi_target_unblock(&port->rport->dev);
 				port->rport->maxframe_size = port->maxframe_size;
 				port->rport->supported_classes =
 					port->supported_classes;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 01386ac..991d456 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -184,10 +184,6 @@
 				      unsigned long);
 extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
 					 struct scsi_cmnd *);
-extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
-extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
-extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
-						  unsigned long);
 extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
 
 #endif	/* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 4c0a59a..a8b0254 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -828,7 +828,7 @@
 
 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
 		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
-				"nonexisting port with d_id 0x%08x on "
+				"nonexisting port with d_id 0x%06x on "
 				"adapter %s. Ignored.\n",
 				status_buffer->d_id & ZFCP_DID_MASK,
 				zfcp_get_busid_by_adapter(adapter));
@@ -853,7 +853,7 @@
 				&status_buffer->status_subtype, sizeof (u32));
 		ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
 				"for a reopen indication on port with "
-				"d_id 0x%08x on the adapter %s. "
+				"d_id 0x%06x on the adapter %s. "
 				"Ignored. (debug info 0x%x)\n",
 				status_buffer->d_id,
 				zfcp_get_busid_by_adapter(adapter),
@@ -1156,7 +1156,7 @@
 	}
 
 	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
-		       "(adapter%s, port d_id=0x%08x, "
+		       "(adapter%s, port d_id=0x%06x, "
 		       "unit x%016Lx, old_req_id=0x%lx)\n",
 		       zfcp_get_busid_by_adapter(adapter),
 		       unit->port->d_id,
@@ -1554,7 +1554,7 @@
 
 	case FSF_ACCESS_DENIED:
 		ZFCP_LOG_NORMAL("access denied, cannot send generic service "
-				"command (adapter %s, port d_id=0x%08x)\n",
+				"command (adapter %s, port d_id=0x%06x)\n",
 				zfcp_get_busid_by_port(port), port->d_id);
 		for (counter = 0; counter < 2; counter++) {
 			subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -1576,7 +1576,7 @@
 
         case FSF_GENERIC_COMMAND_REJECTED:
 		ZFCP_LOG_INFO("generic service command rejected "
-			      "(adapter %s, port d_id=0x%08x)\n",
+			      "(adapter %s, port d_id=0x%06x)\n",
 			      zfcp_get_busid_by_port(port), port->d_id);
 		ZFCP_LOG_INFO("status qualifier:\n");
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
@@ -1602,7 +1602,7 @@
 
         case FSF_PORT_BOXED:
 		ZFCP_LOG_INFO("port needs to be reopened "
-			      "(adapter %s, port d_id=0x%08x)\n",
+			      "(adapter %s, port d_id=0x%06x)\n",
 			      zfcp_get_busid_by_port(port), port->d_id);
 		debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
 		zfcp_erp_port_boxed(port);
@@ -1683,7 +1683,7 @@
 				  NULL, &lock_flags, &fsf_req);
 	if (ret < 0) {
                 ZFCP_LOG_INFO("error: creation of ELS request failed "
-			      "(adapter %s, port d_id: 0x%08x)\n",
+			      "(adapter %s, port d_id: 0x%06x)\n",
                               zfcp_get_busid_by_adapter(adapter), d_id);
                 goto failed_req;
 	}
@@ -1708,7 +1708,7 @@
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-				      "(adapter %s, port d_id: 0x%08x)\n",
+				      "(adapter %s, port d_id: 0x%06x)\n",
 				      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1725,7 +1725,7 @@
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-				      "(adapter %s, port d_id: 0x%08x)\n",
+				      "(adapter %s, port d_id: 0x%06x)\n",
 				      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1739,7 +1739,7 @@
                 /* reject request */
 		ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
                               ", ELS request too big (adapter %s, "
-			      "port d_id: 0x%08x)\n",
+			      "port d_id: 0x%06x)\n",
 			      zfcp_get_busid_by_adapter(adapter), d_id);
                 ret = -EOPNOTSUPP;
                 goto failed_send;
@@ -1760,13 +1760,13 @@
 	ret = zfcp_fsf_req_send(fsf_req);
 	if (ret) {
 		ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
-			       "(adapter %s, port d_id: 0x%08x)\n",
+			       "(adapter %s, port d_id: 0x%06x)\n",
 			       zfcp_get_busid_by_adapter(adapter), d_id);
 		goto failed_send;
 	}
 
 	ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
-		       "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
+		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
 	goto out;
 
  failed_send:
@@ -1859,7 +1859,7 @@
 	case FSF_ELS_COMMAND_REJECTED:
 		ZFCP_LOG_INFO("ELS has been rejected because command filter "
 			      "prohibited sending "
-			      "(adapter: %s, port d_id: 0x%08x)\n",
+			      "(adapter: %s, port d_id: 0x%06x)\n",
 			      zfcp_get_busid_by_adapter(adapter), d_id);
 
 		break;
@@ -1907,7 +1907,7 @@
 
 	case FSF_ACCESS_DENIED:
 		ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
-				"(adapter %s, port d_id=0x%08x)\n",
+				"(adapter %s, port d_id=0x%06x)\n",
 				zfcp_get_busid_by_adapter(adapter), d_id);
 		for (counter = 0; counter < 2; counter++) {
 			subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -2070,7 +2070,7 @@
 	ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
 			"WWNN 0x%016Lx, "
 			"WWPN 0x%016Lx, "
-			"S_ID 0x%08x,\n"
+			"S_ID 0x%06x,\n"
 			"adapter version 0x%x, "
 			"LIC version 0x%x, "
 			"FC link speed %d Gb/s\n",
@@ -3043,6 +3043,7 @@
 	queue_designator = &header->fsf_status_qual.fsf_queue_designator;
 
 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
+			  ZFCP_STATUS_COMMON_ACCESS_BOXED |
 			  ZFCP_STATUS_UNIT_SHARED |
 			  ZFCP_STATUS_UNIT_READONLY,
 			  &unit->status);
@@ -4645,23 +4646,22 @@
 	fsf_req->adapter = adapter;
 	fsf_req->fsf_command = fsf_cmd;
 	INIT_LIST_HEAD(&fsf_req->list);
-	
-	/* this is serialized (we are holding req_queue-lock of adapter */
-	if (adapter->req_no == 0)
-		adapter->req_no++;
-	fsf_req->req_id = adapter->req_no++;
-
 	init_timer(&fsf_req->timer);
-	zfcp_fsf_req_qtcb_init(fsf_req);
 
 	/* initialize waitqueue which may be used to wait on 
 	   this request completion */
 	init_waitqueue_head(&fsf_req->completion_wq);
 
         ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
-        if(ret < 0) {
+        if (ret < 0)
                 goto failed_sbals;
-	}
+
+	/* this is serialized (we are holding req_queue-lock of adapter) */
+	if (adapter->req_no == 0)
+		adapter->req_no++;
+	fsf_req->req_id = adapter->req_no++;
+
+	zfcp_fsf_req_qtcb_init(fsf_req);
 
 	/*
 	 * We hold queue_lock here. Check if QDIOUP is set and let request fail
@@ -4788,7 +4788,7 @@
 		retval = -EIO;
 		del_timer(&fsf_req->timer);
 		spin_lock(&adapter->req_list_lock);
-		zfcp_reqlist_remove(adapter, fsf_req->req_id);
+		zfcp_reqlist_remove(adapter, fsf_req);
 		spin_unlock(&adapter->req_list_lock);
 		/* undo changes in request queue made for this request */
 		zfcp_qdio_zero_sbals(req_queue->buffer,
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 1e12a78..bdf5782 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -222,7 +222,7 @@
                 * Since we have been using this adapter, it is save to assume
                 * that it is not failed but recoverable. The card seems to
                 * report link-up events by self-initiated queue shutdown.
-                * That is why we need to clear the the link-down flag
+                * That is why we need to clear the link-down flag
                 * which is set again in case we have missed by a mile.
                 */
                zfcp_erp_adapter_reopen(
@@ -283,10 +283,10 @@
 }
 
 /**
- * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ * zfcp_qdio_reqid_check - checks for valid reqids.
  */
-static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, 
-				 unsigned long req_id)
+static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+				  unsigned long req_id)
 {
 	struct zfcp_fsf_req *fsf_req;
 	unsigned long flags;
@@ -294,23 +294,22 @@
 	debug_long_event(adapter->erp_dbf, 4, req_id);
 
 	spin_lock_irqsave(&adapter->req_list_lock, flags);
-	fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+	fsf_req = zfcp_reqlist_find(adapter, req_id);
 
-	if (!fsf_req) {
-		spin_unlock_irqrestore(&adapter->req_list_lock, flags);
-		ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id);
-		zfcp_erp_adapter_reopen(adapter, 0);
-		return -EINVAL;
-	}
+	if (!fsf_req)
+		/*
+		 * Unknown request means that we have potentially memory
+		 * corruption and must stop the machine immediatly.
+		 */
+		panic("error: unknown request id (%ld) on adapter %s.\n",
+		      req_id, zfcp_get_busid_by_adapter(adapter));
 
-	zfcp_reqlist_remove(adapter, req_id);
+	zfcp_reqlist_remove(adapter, fsf_req);
 	atomic_dec(&adapter->reqs_active);
 	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
 
 	/* finish the FSF request */
 	zfcp_fsf_req_complete(fsf_req);
-
-	return 0;
 }
 
 /*
@@ -374,27 +373,9 @@
 
 			/* look for QDIO request identifiers in SB */
 			buffere = &buffer->element[buffere_index];
-			retval = zfcp_qdio_reqid_check(adapter,
-					(unsigned long) buffere->addr);
+			zfcp_qdio_reqid_check(adapter,
+					      (unsigned long) buffere->addr);
 
-			if (retval) {
-				ZFCP_LOG_NORMAL("bug: unexpected inbound "
-						"packet on adapter %s "
-						"(reqid=0x%lx, "
-						"first_element=%d, "
-						"elements_processed=%d)\n",
-						zfcp_get_busid_by_adapter(adapter),
-						(unsigned long) buffere->addr,
-						first_element,
-						elements_processed);
-				ZFCP_LOG_NORMAL("hex dump of inbound buffer "
-						"at address %p "
-						"(buffer_index=%d, "
-						"buffere_index=%d)\n", buffer,
-						buffer_index, buffere_index);
-				ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-					      (char *) buffer, SBAL_SIZE);
-			}
 			/*
 			 * A single used SBALE per inbound SBALE has been
 			 * implemented by QDIO so far. Hope they will
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 99db020..16e2d64 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -22,6 +22,7 @@
 #define ZFCP_LOG_AREA			ZFCP_LOG_AREA_SCSI
 
 #include "zfcp_ext.h"
+#include <asm/atomic.h>
 
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
@@ -179,6 +180,10 @@
 	struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
 
 	if (unit) {
+		zfcp_erp_wait(unit->port->adapter);
+		wait_event(unit->scsi_scan_wq,
+			   atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+					    &unit->status) == 0);
 		atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
 		sdpnt->hostdata = NULL;
 		unit->device = NULL;
@@ -402,8 +407,8 @@
 
 	/* Check whether corresponding fsf_req is still pending */
 	spin_lock(&adapter->req_list_lock);
-	fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
-					scpnt->host_scribble);
+	fsf_req = zfcp_reqlist_find(adapter,
+				    (unsigned long) scpnt->host_scribble);
 	spin_unlock(&adapter->req_list_lock);
 	if (!fsf_req) {
 		write_unlock_irqrestore(&adapter->abort_lock, flags);
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 74b999d..4fab0c2 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -156,7 +156,7 @@
 #define BPP_ICR      0x18
 #define BPP_SIZE     0x1A
 
-/* BPP_CSR.  Bits of type RW1 are cleared with writting '1'. */
+/* BPP_CSR.  Bits of type RW1 are cleared with writing '1'. */
 #define P_DEV_ID_MASK   0xf0000000      /* R   */
 #define P_DEV_ID_ZEBRA  0x40000000
 #define P_DEV_ID_L64854 0xa0000000      /*      == NCR 89C100+89C105. Pity. */
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 33682ce..3009ad8 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -387,12 +387,11 @@
 	 *	Ok now init the communication subsystem
 	 */
 
-	dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+	dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
 	if (dev->queues == NULL) {
 		printk(KERN_ERR "Error could not allocate comm region.\n");
 		return NULL;
 	}
-	memset(dev->queues, 0, sizeof(struct aac_queue_block));
 
 	if (aac_comm_init(dev)<0){
 		kfree(dev->queues);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 5824a75..9aca57e 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1223,13 +1223,11 @@
 		 * Warning: no sleep allowed while
 		 * holding spinlock
 		 */
-		hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-		fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+		hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+		fib = kzalloc(sizeof(struct fib), GFP_ATOMIC);
 		if (fib && hw_fib) {
 			struct aac_aifcmd * aif;
 
-			memset(hw_fib, 0, sizeof(struct hw_fib));
-			memset(fib, 0, sizeof(struct fib));
 			fib->hw_fib_va = hw_fib;
 			fib->dev = aac;
 			aac_fib_init(fib);
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index 42c7dcd..fcd25f7 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -248,16 +248,14 @@
 		 * manage the linked lists.
 		 */
 		if ((!dev->aif_thread)
-		 || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+		 || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
 			return 1;
-		if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+		if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
 			kfree (fib);
 			return 1;
 		}
-		memset(hw_fib, 0, sizeof(struct hw_fib));
 		memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
 		  (index & ~0x00000002L)), sizeof(struct hw_fib));
-		memset(fib, 0, sizeof(struct fib));
 		INIT_LIST_HEAD(&fib->fiblink);
 		fib->type = FSAFS_NTC_FIB_CONTEXT;
 		fib->size = sizeof(struct fib);
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 0c71315..291cd14 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -539,8 +539,10 @@
 	}
 
 	/* Failure to reset here is an option ... */
+	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+	dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
 	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
-	if ((((status & 0xff) != 0xff) || reset_devices) &&
+	if ((((status & 0x0c) != 0x0c) || reset_devices) &&
 	  !aac_rx_restart_adapter(dev, 0))
 		++restart;
 	/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 8d72bba..0bada00 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -966,7 +966,7 @@
 			      |  AHD_BUSFREEREV_BUG;
 		ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
 
-		/* If the user requested the the SLOWCRC bit to be set. */
+		/* If the user requested that the SLOWCRC bit to be set. */
 		if (aic79xx_slowcrc)
 			ahd->features |= AHD_AIC79XXB_SLOWCRC;
 
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
index e6b7012..e78ce0f 100644
--- a/drivers/scsi/aic94xx/Makefile
+++ b/drivers/scsi/aic94xx/Makefile
@@ -6,7 +6,7 @@
 #
 # This file is licensed under GPLv2.
 #
-# This file is part of the the aic94xx driver.
+# This file is part of the aic94xx driver.
 #
 # The aic94xx driver is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 2a2cc6c..2311019 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -319,10 +319,9 @@
 	int     result,id,lun,i;
 	u_int   elem;
 
-	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+	buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
 	if (!buffer)
 		return -ENOMEM;
-	memset(buffer,0,512);
 	
 	memset(cmd,0,sizeof(cmd));
 	cmd[0] = MODE_SENSE;
@@ -530,10 +529,9 @@
 	u_char  *buffer;
 	int result;
 
-	buffer = kmalloc(512, GFP_KERNEL);
+	buffer = kzalloc(512, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
-	memset(buffer,0,512);
 
 	dprintk("%s %s voltag: 0x%x => \"%s\"\n",
 		clear     ? "clear"     : "set",
@@ -922,11 +920,10 @@
 	if (sd->type != TYPE_MEDIUM_CHANGER)
 		return -ENODEV;
     
-	ch = kmalloc(sizeof(*ch), GFP_KERNEL);
+	ch = kzalloc(sizeof(*ch), GFP_KERNEL);
 	if (NULL == ch)
 		return -ENOMEM;
 
-	memset(ch,0,sizeof(*ch));
 	ch->minor = ch_devcount;
 	sprintf(ch->name,"ch%d",ch->minor);
 	mutex_init(&ch->lock);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index a965ed3..564ea90 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -541,7 +541,7 @@
 
 
 /*
- * Safe settings. If set to zero the the BIOS/default values with
+ * Safe settings. If set to zero the BIOS/default values with
  * command line overrides will be used. If set to 1 then safe and
  * slow settings will be used.
  */
@@ -617,7 +617,7 @@
 
 /*
  * Mapping from the eeprom delay index value (index into this array)
- * to the the number of actual seconds that the delay should be for.
+ * to the number of actual seconds that the delay should be for.
  */
 static char __devinitdata eeprom_index_to_delay_map[] = 
 	{ 1, 3, 5, 10, 16, 30, 60, 120 };
@@ -4136,7 +4136,7 @@
  * @io_port:	base I/O address
  * @addr:	offset into SEEPROM
  *
- * Returns the the byte read.
+ * Returns the byte read.
  **/
 static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
 {
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index fb6433a..8c7d2bb 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1308,13 +1308,12 @@
 		schedule_timeout_uninterruptible(1);
 	} while (m == EMPTY_QUEUE);
 
-	status = kmalloc(4, GFP_KERNEL|ADDR32);
+	status = kzalloc(4, GFP_KERNEL|ADDR32);
 	if(status == NULL) {
 		adpt_send_nop(pHba, m);
 		printk(KERN_ERR"IOP reset failed - no free memory.\n");
 		return -ENOMEM;
 	}
-	memset(status,0,4);
 
 	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1504,21 +1503,19 @@
 					continue;
 				}
 				if( pHba->channel[bus_no].device[scsi_id] == NULL){
-					pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
 					if(pDev == NULL) {
 						return -ENOMEM;
 					}
 					pHba->channel[bus_no].device[scsi_id] = pDev;
-					memset(pDev,0,sizeof(struct adpt_device));
 				} else {
 					for( pDev = pHba->channel[bus_no].device[scsi_id];	
 							pDev->next_lun; pDev = pDev->next_lun){
 					}
-					pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
 					if(pDev->next_lun == NULL) {
 						return -ENOMEM;
 					}
-					memset(pDev->next_lun,0,sizeof(struct adpt_device));
 					pDev = pDev->next_lun;
 				}
 				pDev->tid = tid;
@@ -1667,12 +1664,11 @@
 		reply_size = REPLY_FRAME_SIZE;
 	}
 	reply_size *= 4;
-	reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
+	reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
 	if(reply == NULL) {
 		printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name);
 		return -ENOMEM;
 	}
-	memset(reply,0,REPLY_FRAME_SIZE*4);
 	sg_offset = (msg[0]>>4)&0xf;
 	msg[2] = 0x40000000; // IOCTL context
 	msg[3] = (u32)reply;
@@ -2444,7 +2440,7 @@
 				}
 				pDev = pHba->channel[bus_no].device[scsi_id];	
 				if( pDev == NULL){
-					pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
 					if(pDev == NULL) {
 						return -ENOMEM;
 					}
@@ -2453,12 +2449,11 @@
 					while (pDev->next_lun) {
 						pDev = pDev->next_lun;
 					}
-					pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
 					if(pDev == NULL) {
 						return -ENOMEM;
 					}
 				}
-				memset(pDev,0,sizeof(struct adpt_device));
 				pDev->tid = d->lct_data.tid;
 				pDev->scsi_channel = bus_no;
 				pDev->scsi_id = scsi_id;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 2b5b8a9..8263f75 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -721,19 +721,23 @@
 	return ide_stopped;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idescsi_add_settings(ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
 
 /*
- *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ *			drive	setting name	read/write	data type	min	max	mul_factor	div_factor	data pointer		set function
  */
-	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
-	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
-	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
-	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
-	ide_add_setting(drive,	"log",		SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
+	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
+	ide_add_setting(drive,	"transform",	SETTING_RW,	TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
+	ide_add_setting(drive,	"log",		SETTING_RW,	TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
 }
+#else
+static inline void idescsi_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *	Driver initialization.
@@ -756,7 +760,7 @@
 	struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
 	struct gendisk *g = scsi->disk;
 
-	ide_unregister_subdriver(drive, scsi->driver);
+	ide_proc_unregister_driver(drive, scsi->driver);
 
 	ide_unregister_region(g);
 
@@ -770,13 +774,11 @@
 
 static int ide_scsi_probe(ide_drive_t *);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static ide_proc_entry_t idescsi_proc[] = {
 	{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
 	{ NULL, 0, NULL, NULL }
 };
-#else
-# define idescsi_proc	NULL
 #endif
 
 static ide_driver_t idescsi_driver = {
@@ -790,11 +792,13 @@
 	.version		= IDESCSI_VERSION,
 	.media			= ide_scsi,
 	.supports_dsc_overlap	= 0,
-	.proc			= idescsi_proc,
 	.do_request		= idescsi_do_request,
 	.end_request		= idescsi_end_request,
 	.error                  = idescsi_atapi_error,
 	.abort                  = idescsi_atapi_abort,
+#ifdef CONFIG_IDE_PROC_FS
+	.proc			= idescsi_proc,
+#endif
 };
 
 static int idescsi_ide_open(struct inode *inode, struct file *filp)
@@ -1153,7 +1157,7 @@
 	idescsi->host = host;
 	idescsi->disk = g;
 	g->private_data = &idescsi->driver;
-	ide_register_subdriver(drive, &idescsi_driver);
+	ide_proc_register_driver(drive, &idescsi_driver);
 	err = 0;
 	idescsi_setup(drive, idescsi);
 	g->fops = &idescsi_ops;
@@ -1165,7 +1169,7 @@
 	}
 	/* fall through on error */
 	ide_unregister_region(g);
-	ide_unregister_subdriver(drive, &idescsi_driver);
+	ide_proc_unregister_driver(drive, &idescsi_driver);
 
 	put_disk(g);
 out_host_put:
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 2c7b77e..4baa79e 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -92,6 +92,7 @@
 static unsigned int ipr_transop_timeout = 0;
 static unsigned int ipr_enable_cache = 1;
 static unsigned int ipr_debug = 0;
+static unsigned int ipr_dual_ioa_raid = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
@@ -158,6 +159,8 @@
 MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
 module_param_named(debug, ipr_debug, int, 0);
 MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
+module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
+MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -206,6 +209,8 @@
 	"8009: Impending cache battery pack failure"},
 	{0x02040400, 0, 0,
 	"34FF: Disk device format in progress"},
+	{0x02048000, 0, IPR_DEFAULT_LOG_LEVEL,
+	"9070: IOA requested reset"},
 	{0x023F0000, 0, 0,
 	"Synchronization required"},
 	{0x024E0000, 0, 0,
@@ -951,6 +956,53 @@
 }
 
 /**
+ * strip_and_pad_whitespace - Strip and pad trailing whitespace.
+ * @i:		index into buffer
+ * @buf:		string to modify
+ *
+ * This function will strip all trailing whitespace, pad the end
+ * of the string with a single space, and NULL terminate the string.
+ *
+ * Return value:
+ * 	new length of string
+ **/
+static int strip_and_pad_whitespace(int i, char *buf)
+{
+	while (i && buf[i] == ' ')
+		i--;
+	buf[i+1] = ' ';
+	buf[i+2] = '\0';
+	return i + 2;
+}
+
+/**
+ * ipr_log_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:		string to print at start of printk
+ * @hostrcb:	hostrcb pointer
+ * @vpd:		vendor/product id/sn struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+				struct ipr_vpd *vpd)
+{
+	char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3];
+	int i = 0;
+
+	memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
+	i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer);
+
+	memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN);
+	i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer);
+
+	memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN);
+	buffer[IPR_SERIAL_NUM_LEN + i] = '\0';
+
+	ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer);
+}
+
+/**
  * ipr_log_vpd - Log the passed VPD to the error log.
  * @vpd:		vendor/product id/sn struct
  *
@@ -974,6 +1026,23 @@
 }
 
 /**
+ * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:		string to print at start of printk
+ * @hostrcb:	hostrcb pointer
+ * @vpd:		vendor/product id/sn/wwn struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+				    struct ipr_ext_vpd *vpd)
+{
+	ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd);
+	ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix,
+		     be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1]));
+}
+
+/**
  * ipr_log_ext_vpd - Log the passed extended VPD to the error log.
  * @vpd:		vendor/product id/sn/wwn struct
  *
@@ -1287,10 +1356,11 @@
 
 	error = &hostrcb->hcam.u.error.u.type_17_error;
 	error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+	strstrip(error->failure_reason);
 
-	ipr_err("%s\n", error->failure_reason);
-	ipr_err("Remote Adapter VPD:\n");
-	ipr_log_ext_vpd(&error->vpd);
+	ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+		     be32_to_cpu(hostrcb->hcam.u.error.prc));
+	ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd);
 	ipr_log_hex_data(ioa_cfg, error->data,
 			 be32_to_cpu(hostrcb->hcam.length) -
 			 (offsetof(struct ipr_hostrcb_error, u) +
@@ -1312,10 +1382,11 @@
 
 	error = &hostrcb->hcam.u.error.u.type_07_error;
 	error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+	strstrip(error->failure_reason);
 
-	ipr_err("%s\n", error->failure_reason);
-	ipr_err("Remote Adapter VPD:\n");
-	ipr_log_vpd(&error->vpd);
+	ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+		     be32_to_cpu(hostrcb->hcam.u.error.prc));
+	ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd);
 	ipr_log_hex_data(ioa_cfg, error->data,
 			 be32_to_cpu(hostrcb->hcam.length) -
 			 (offsetof(struct ipr_hostrcb_error, u) +
@@ -1672,12 +1743,15 @@
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
 	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+	u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
 
 	list_del(&hostrcb->queue);
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 
 	if (!ioasc) {
 		ipr_handle_log_data(ioa_cfg, hostrcb);
+		if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED)
+			ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
 	} else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
 		dev_err(&ioa_cfg->pdev->dev,
 			"Host RCB failed with IOASC: 0x%08X\n", ioasc);
@@ -2635,8 +2709,13 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	while(ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	}
+
 	ioa_cfg->errors_logged = 0;
 	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
@@ -2958,6 +3037,11 @@
 	unsigned long lock_flags;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	while(ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	}
 
 	if (ioa_cfg->ucode_sglist) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -4656,18 +4740,19 @@
 	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
 	struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
 	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+	u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
 
 	if (!res) {
 		ipr_scsi_eh_done(ipr_cmd);
 		return;
 	}
 
-	if (!ipr_is_gscsi(res))
+	if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS)
 		ipr_gen_sense(ipr_cmd);
 
 	ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
-	switch (ioasc & IPR_IOASC_IOASC_MASK) {
+	switch (masked_ioasc) {
 	case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
 		if (ipr_is_naca_model(res))
 			scsi_cmd->result |= (DID_ABORT << 16);
@@ -5363,6 +5448,7 @@
 			ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
 	}
 
+	scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS);
 	dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n");
 
 	ioa_cfg->reset_retries = 0;
@@ -5799,6 +5885,94 @@
 }
 
 /**
+ * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function enables dual IOA RAID support if possible.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages;
+	struct ipr_mode_page24 *mode_page;
+	int length;
+
+	ENTER;
+	mode_page = ipr_get_mode_page(mode_pages, 0x24,
+				      sizeof(struct ipr_mode_page24));
+
+	if (mode_page)
+		mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF;
+
+	length = mode_pages->hdr.length + 1;
+	mode_pages->hdr.length = 0;
+
+	ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11,
+			      ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
+			      length);
+
+	ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function handles the failure of a Mode Sense to the IOAFP.
+ * Some adapters do not handle all mode pages.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd)
+{
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
+		ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+/**
+ * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function send a mode sense to the IOA to retrieve
+ * the IOA Advanced Function Control mode page.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE),
+			     0x24, ioa_cfg->vpd_cbs_dma +
+			     offsetof(struct ipr_misc_cbs, mode_pages),
+			     sizeof(struct ipr_mode_pages));
+
+	ipr_cmd->job_step = ipr_ioafp_mode_select_page24;
+	ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
  * ipr_init_res_table - Initialize the resource table
  * @ipr_cmd:	ipr command struct
  *
@@ -5866,7 +6040,10 @@
 		}
 	}
 
-	ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+	if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+		ipr_cmd->job_step = ipr_ioafp_mode_sense_page24;
+	else
+		ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
 
 	LEAVE;
 	return IPR_RC_JOB_CONTINUE;
@@ -5888,8 +6065,11 @@
 	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
 	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
 	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+	struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
 
 	ENTER;
+	if (cap->cap & IPR_CAP_DUAL_IOA_RAID)
+		ioa_cfg->dual_raid = 1;
 	dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n",
 		 ucode_vpd->major_release, ucode_vpd->card_type,
 		 ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]);
@@ -5973,6 +6153,37 @@
 }
 
 /**
+ * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a Page 0xD0 inquiry to the adapter
+ * to retrieve adapter capabilities.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+	struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
+
+	ENTER;
+	ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+	memset(cap, 0, sizeof(*cap));
+
+	if (ipr_inquiry_page_supported(page0, 0xD0)) {
+		ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0,
+				  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap),
+				  sizeof(struct ipr_inquiry_cap));
+		return IPR_RC_JOB_RETURN;
+	}
+
+	LEAVE;
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
  * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
  * @ipr_cmd:	ipr command struct
  *
@@ -5992,7 +6203,7 @@
 	if (!ipr_inquiry_page_supported(page0, 1))
 		ioa_cfg->cache_state = CACHE_NONE;
 
-	ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+	ipr_cmd->job_step = ipr_ioafp_cap_inquiry;
 
 	ipr_ioafp_inquiry(ipr_cmd, 1, 3,
 			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
@@ -6278,6 +6489,7 @@
 	struct ipr_hostrcb *hostrcb;
 	struct ipr_uc_sdt sdt;
 	int rc, length;
+	u32 ioasc;
 
 	mailbox = readl(ioa_cfg->ioa_mailbox);
 
@@ -6310,9 +6522,13 @@
 					(__be32 *)&hostrcb->hcam,
 					min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
 
-	if (!rc)
+	if (!rc) {
 		ipr_handle_log_data(ioa_cfg, hostrcb);
-	else
+		ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+		if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
+		    ioa_cfg->sdt_state == GET_DUMP)
+			ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+	} else
 		ipr_unit_check_no_data(ioa_cfg);
 
 	list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
@@ -6425,6 +6641,48 @@
 }
 
 /**
+ * ipr_reset_slot_reset_done - Clear PCI reset to the adapter
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This clears PCI reset to the adapter and delays two seconds.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+	ENTER;
+	pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
+	ipr_cmd->job_step = ipr_reset_bist_done;
+	ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_slot_reset - Reset the PCI slot of the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This asserts PCI reset to the adapter.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct pci_dev *pdev = ioa_cfg->pdev;
+
+	ENTER;
+	pci_block_user_cfg_access(pdev);
+	pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+	ipr_cmd->job_step = ipr_reset_slot_reset_done;
+	ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
  * ipr_reset_allowed - Query whether or not IOA can be reset
  * @ioa_cfg:	ioa config struct
  *
@@ -6463,7 +6721,7 @@
 		ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
 		ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
 	} else {
-		ipr_cmd->job_step = ipr_reset_start_bist;
+		ipr_cmd->job_step = ioa_cfg->reset;
 		rc = IPR_RC_JOB_CONTINUE;
 	}
 
@@ -6496,7 +6754,7 @@
 		writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
 		ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
 	} else {
-		ipr_cmd->job_step = ipr_reset_start_bist;
+		ipr_cmd->job_step = ioa_cfg->reset;
 	}
 
 	ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
@@ -6591,12 +6849,14 @@
 		ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
 		ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type;
 
-		if (shutdown_type == IPR_SHUTDOWN_ABBREV)
-			timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
+		if (shutdown_type == IPR_SHUTDOWN_NORMAL)
+			timeout = IPR_SHUTDOWN_TIMEOUT;
 		else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL)
 			timeout = IPR_INTERNAL_TIMEOUT;
+		else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+			timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO;
 		else
-			timeout = IPR_SHUTDOWN_TIMEOUT;
+			timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
 
 		ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout);
 
@@ -6776,8 +7036,11 @@
 	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-	_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
-	                                 IPR_SHUTDOWN_NONE);
+	if (ioa_cfg->needs_warm_reset)
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	else
+		_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+					IPR_SHUTDOWN_NONE);
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 	return PCI_ERS_RESULT_RECOVERED;
 }
@@ -7226,7 +7489,7 @@
 	unsigned long ipr_regs_pci;
 	void __iomem *ipr_regs;
 	int rc = PCIBIOS_SUCCESSFUL;
-	volatile u32 mask, uproc;
+	volatile u32 mask, uproc, interrupts;
 
 	ENTER;
 
@@ -7265,6 +7528,14 @@
 	else
 		ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
 
+	rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid);
+
+	if (rc != PCIBIOS_SUCCESSFUL) {
+		dev_err(&pdev->dev, "Failed to read PCI revision ID\n");
+		rc = -EIO;
+		goto out_scsi_host_put;
+	}
+
 	ipr_regs_pci = pci_resource_start(pdev, 0);
 
 	rc = pci_request_regions(pdev, IPR_NAME);
@@ -7333,9 +7604,14 @@
 	 * the card is in an unknown state and needs a hard reset
 	 */
 	mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+	interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
 	uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
 	if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
 		ioa_cfg->needs_hard_reset = 1;
+	if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
+		ioa_cfg->needs_hard_reset = 1;
+	if (interrupts & IPR_PCII_IOA_UNIT_CHECKED)
+		ioa_cfg->ioa_unit_checked = 1;
 
 	ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
 	rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
@@ -7346,6 +7622,13 @@
 		goto cleanup_nolog;
 	}
 
+	if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) ||
+	    (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) {
+		ioa_cfg->needs_warm_reset = 1;
+		ioa_cfg->reset = ipr_reset_slot_reset;
+	} else
+		ioa_cfg->reset = ipr_reset_start_bist;
+
 	spin_lock(&ipr_driver_lock);
 	list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
 	spin_unlock(&ipr_driver_lock);
@@ -7428,6 +7711,12 @@
 	ENTER;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+	while(ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+		spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+	}
+
 	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
@@ -7551,6 +7840,12 @@
 	unsigned long lock_flags = 0;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	while(ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	}
+
 	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
@@ -7577,19 +7872,22 @@
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
 	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT},
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
 	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
 	      IPR_USE_LONG_TRANSOP_TIMEOUT },
@@ -7597,7 +7895,7 @@
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
-	      IPR_USE_LONG_TRANSOP_TIMEOUT },
+	      IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
@@ -7627,6 +7925,7 @@
 	.remove = ipr_remove,
 	.shutdown = ipr_shutdown,
 	.err_handler = &ipr_err_handler,
+	.dynids.use_driver_data = 1
 };
 
 /**
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index bc53d7c..d931566 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.3.2"
-#define IPR_DRIVER_DATE "(March 23, 2007)"
+#define IPR_DRIVER_VERSION "2.4.1"
+#define IPR_DRIVER_DATE "(April 24, 2007)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -91,6 +91,7 @@
  * IOASCs
  */
 #define IPR_IOASC_NR_INIT_CMD_REQUIRED		0x02040200
+#define IPR_IOASC_NR_IOA_RESET_REQUIRED		0x02048000
 #define IPR_IOASC_SYNC_REQUIRED			0x023f0000
 #define IPR_IOASC_MED_DO_NOT_REALLOC		0x03110C00
 #define IPR_IOASC_HW_SEL_TIMEOUT			0x04050000
@@ -111,6 +112,7 @@
 
 /* Driver data flags */
 #define IPR_USE_LONG_TRANSOP_TIMEOUT		0x00000001
+#define IPR_USE_PCI_WARM_RESET			0x00000002
 
 #define IPR_DEFAULT_MAX_ERROR_DUMP			984
 #define IPR_NUM_LOG_HCAMS				2
@@ -179,6 +181,7 @@
 #define IPR_SHUTDOWN_TIMEOUT			(ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
 #define IPR_VSET_RW_TIMEOUT			(ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
 #define IPR_ABBREV_SHUTDOWN_TIMEOUT		(10 * HZ)
+#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO	(2 * 60 * HZ)
 #define IPR_DEVICE_RESET_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_CANCEL_ALL_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_ABORT_TASK_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
@@ -191,6 +194,7 @@
 #define IPR_WAIT_FOR_RESET_TIMEOUT		(2 * HZ)
 #define IPR_CHECK_FOR_RESET_TIMEOUT		(HZ / 10)
 #define IPR_WAIT_FOR_BIST_TIMEOUT		(2 * HZ)
+#define IPR_PCI_RESET_TIMEOUT			(HZ / 2)
 #define IPR_DUMP_TIMEOUT			(15 * HZ)
 
 /*
@@ -602,6 +606,12 @@
 	struct ipr_dev_bus_entry bus[0];
 }__attribute__((packed));
 
+struct ipr_mode_page24 {
+	struct ipr_mode_page_hdr hdr;
+	u8 flags;
+#define IPR_ENABLE_DUAL_IOA_AF 0x80
+}__attribute__((packed));
+
 struct ipr_ioa_vpd {
 	struct ipr_std_inq_data std_inq_data;
 	u8 ascii_part_num[12];
@@ -624,6 +634,19 @@
 	u8 patch_number[4];
 }__attribute__((packed));
 
+struct ipr_inquiry_cap {
+	u8 peri_qual_dev_type;
+	u8 page_code;
+	u8 reserved1;
+	u8 page_length;
+	u8 ascii_len;
+	u8 reserved2;
+	u8 sis_version[2];
+	u8 cap;
+#define IPR_CAP_DUAL_IOA_RAID		0x80
+	u8 reserved3[15];
+}__attribute__((packed));
+
 #define IPR_INQUIRY_PAGE0_ENTRIES 20
 struct ipr_inquiry_page0 {
 	u8 peri_qual_dev_type;
@@ -962,6 +985,7 @@
 	struct ipr_ioa_vpd ioa_vpd;
 	struct ipr_inquiry_page0 page0_data;
 	struct ipr_inquiry_page3 page3_data;
+	struct ipr_inquiry_cap cap;
 	struct ipr_mode_pages mode_pages;
 	struct ipr_supported_device supp_dev;
 };
@@ -1068,6 +1092,10 @@
 	u8 allow_cmds:1;
 	u8 allow_ml_add_del:1;
 	u8 needs_hard_reset:1;
+	u8 dual_raid:1;
+	u8 needs_warm_reset:1;
+
+	u8 revid;
 
 	enum ipr_cache_state cache_state;
 	u16 type; /* CCIN of the card */
@@ -1161,6 +1189,7 @@
 	struct pci_pool *ipr_cmd_pool;
 
 	struct ipr_cmnd *reset_cmd;
+	int (*reset) (struct ipr_cmnd *);
 
 	struct ata_host ata_host;
 	char ipr_cmd_label[8];
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 897a5e2..b4b5269 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -23,6 +23,8 @@
  *
  */
 
+#include <linux/kthread.h>
+
 #include "sas_internal.h"
 
 #include <scsi/scsi_host.h>
@@ -184,7 +186,7 @@
 	list_add_tail(&task->list, &core->task_queue);
 	core->task_queue_size += 1;
 	spin_unlock_irqrestore(&core->task_queue_lock, flags);
-	up(&core->queue_thread_sema);
+	wake_up_process(core->queue_thread);
 
 	return 0;
 }
@@ -819,7 +821,7 @@
 	struct sas_internal *i = to_sas_internal(core->shost->transportt);
 
 	spin_lock_irqsave(&core->task_queue_lock, flags);
-	while (!core->queue_thread_kill &&
+	while (!kthread_should_stop() &&
 	       !list_empty(&core->task_queue)) {
 
 		can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
@@ -858,8 +860,6 @@
 	spin_unlock_irqrestore(&core->task_queue_lock, flags);
 }
 
-static DECLARE_COMPLETION(queue_th_comp);
-
 /**
  * sas_queue_thread -- The Task Collector thread
  * @_sas_ha: pointer to struct sas_ha
@@ -867,40 +867,33 @@
 static int sas_queue_thread(void *_sas_ha)
 {
 	struct sas_ha_struct *sas_ha = _sas_ha;
-	struct scsi_core *core = &sas_ha->core;
 
-	daemonize("sas_queue_%d", core->shost->host_no);
 	current->flags |= PF_NOFREEZE;
 
-	complete(&queue_th_comp);
-
 	while (1) {
-		down_interruptible(&core->queue_thread_sema);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
 		sas_queue(sas_ha);
-		if (core->queue_thread_kill)
+		if (kthread_should_stop())
 			break;
 	}
 
-	complete(&queue_th_comp);
-
 	return 0;
 }
 
 int sas_init_queue(struct sas_ha_struct *sas_ha)
 {
-	int res;
 	struct scsi_core *core = &sas_ha->core;
 
 	spin_lock_init(&core->task_queue_lock);
 	core->task_queue_size = 0;
 	INIT_LIST_HEAD(&core->task_queue);
-	init_MUTEX_LOCKED(&core->queue_thread_sema);
 
-	res = kernel_thread(sas_queue_thread, sas_ha, 0);
-	if (res >= 0)
-		wait_for_completion(&queue_th_comp);
-
-	return res < 0 ? res : 0;
+	core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
+					 "sas_queue_%d", core->shost->host_no);
+	if (IS_ERR(core->queue_thread))
+		return PTR_ERR(core->queue_thread);
+	return 0;
 }
 
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
@@ -909,10 +902,7 @@
 	struct scsi_core *core = &sas_ha->core;
 	struct sas_task *task, *n;
 
-	init_completion(&queue_th_comp);
-	core->queue_thread_kill = 1;
-	up(&core->queue_thread_sema);
-	wait_for_completion(&queue_th_comp);
+	kthread_stop(core->queue_thread);
 
 	if (!list_empty(&core->task_queue))
 		SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index a7de0bc..82e8f90 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -27,10 +27,6 @@
 					   requests */
 #define LPFC_MAX_NS_RETRY	3	/* Number of retry attempts to contact
 					   the NameServer  before giving up. */
-#define LPFC_DFT_HBA_Q_DEPTH	2048	/* max cmds per hba */
-#define LPFC_LC_HBA_Q_DEPTH	1024	/* max cmds per low cost hba */
-#define LPFC_LP101_HBA_Q_DEPTH	128	/* max cmds per low cost hba */
-
 #define LPFC_CMD_PER_LUN	3	/* max outstanding cmds per lun */
 #define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
@@ -244,28 +240,23 @@
 #define FC_FABRIC               0x100	/* We are fabric attached */
 #define FC_ESTABLISH_LINK       0x200	/* Reestablish Link */
 #define FC_RSCN_DISCOVERY       0x400	/* Authenticate all devices after RSCN*/
+#define FC_BLOCK_MGMT_IO        0x800   /* Don't allow mgmt mbx or iocb cmds */
 #define FC_LOADING		0x1000	/* HBA in process of loading drvr */
 #define FC_UNLOADING		0x2000	/* HBA in process of unloading drvr */
 #define FC_SCSI_SCAN_TMO        0x4000	/* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000	/* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000	/* NPort discovery active */
 #define FC_BYPASSED_MODE        0x20000	/* NPort is in bypassed mode */
+#define FC_LOOPBACK_MODE        0x40000	/* NPort is in Loopback mode */
+					/* This flag is set while issuing */
+					/* INIT_LINK mailbox command */
+#define FC_IGNORE_ERATT         0x80000	/* intr handler should ignore ERATT */
 
 	uint32_t fc_topology;	/* link topology, from LINK INIT */
 
 	struct lpfc_stats fc_stat;
 
-	/* These are the head/tail pointers for the bind, plogi, adisc, unmap,
-	 *  and map lists.  Their counters are immediately following.
-	 */
-	struct list_head fc_plogi_list;
-	struct list_head fc_adisc_list;
-	struct list_head fc_reglogin_list;
-	struct list_head fc_prli_list;
-	struct list_head fc_nlpunmap_list;
-	struct list_head fc_nlpmap_list;
-	struct list_head fc_npr_list;
-	struct list_head fc_unused_list;
+	struct list_head fc_nodes;
 
 	/* Keep counters for the number of entries in each list. */
 	uint16_t fc_plogi_cnt;
@@ -387,13 +378,17 @@
 
 	mempool_t *mbox_mem_pool;
 	mempool_t *nlp_mem_pool;
-	struct list_head freebufList;
-	struct list_head ctrspbuflist;
-	struct list_head rnidrspbuflist;
 
 	struct fc_host_statistics link_stats;
 };
 
+static inline void
+lpfc_set_loopback_flag(struct lpfc_hba *phba) {
+	if (phba->cfg_topology == FLAGS_LOCAL_LB)
+		phba->fc_flag |= FC_LOOPBACK_MODE;
+	else
+		phba->fc_flag &= ~FC_LOOPBACK_MODE;
+}
 
 struct rnidrsp {
 	void *buf;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f247e78..95fe77e 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -20,6 +20,7 @@
  *******************************************************************/
 
 #include <linux/ctype.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -213,6 +214,7 @@
 	int mbxstatus = MBXERR_ERROR;
 
 	if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
 	    (phba->hba_state != LPFC_HBA_READY))
 		return -EPERM;
 
@@ -235,6 +237,7 @@
 						     phba->fc_ratov * 2);
 	}
 
+	lpfc_set_loopback_flag(phba);
 	if (mbxstatus == MBX_TIMEOUT)
 		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	else
@@ -247,18 +250,61 @@
 }
 
 static int
+lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
+{
+	struct completion online_compl;
+	struct lpfc_sli_ring *pring;
+	struct lpfc_sli *psli;
+	int status = 0;
+	int cnt = 0;
+	int i;
+
+	init_completion(&online_compl);
+	lpfc_workq_post_event(phba, &status, &online_compl,
+			      LPFC_EVT_OFFLINE_PREP);
+	wait_for_completion(&online_compl);
+
+	if (status != 0)
+		return -EIO;
+
+	psli = &phba->sli;
+
+	for (i = 0; i < psli->num_rings; i++) {
+		pring = &psli->ring[i];
+		/* The linkdown event takes 30 seconds to timeout. */
+		while (pring->txcmplq_cnt) {
+			msleep(10);
+			if (cnt++ > 3000) {
+				lpfc_printf_log(phba,
+					KERN_WARNING, LOG_INIT,
+					"%d:0466 Outstanding IO when "
+					"bringing Adapter offline\n",
+					phba->brd_no);
+				break;
+			}
+		}
+	}
+
+	init_completion(&online_compl);
+	lpfc_workq_post_event(phba, &status, &online_compl, type);
+	wait_for_completion(&online_compl);
+
+	if (status != 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int
 lpfc_selective_reset(struct lpfc_hba *phba)
 {
 	struct completion online_compl;
 	int status = 0;
 
-	init_completion(&online_compl);
-	lpfc_workq_post_event(phba, &status, &online_compl,
-			      LPFC_EVT_OFFLINE);
-	wait_for_completion(&online_compl);
+	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
 	if (status != 0)
-		return -EIO;
+		return status;
 
 	init_completion(&online_compl);
 	lpfc_workq_post_event(phba, &status, &online_compl,
@@ -324,23 +370,19 @@
 
 	init_completion(&online_compl);
 
-	if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
 		lpfc_workq_post_event(phba, &status, &online_compl,
 				      LPFC_EVT_ONLINE);
-	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
-		lpfc_workq_post_event(phba, &status, &online_compl,
-				      LPFC_EVT_OFFLINE);
+		wait_for_completion(&online_compl);
+	} else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+		status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 	else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
-		lpfc_workq_post_event(phba, &status, &online_compl,
-				      LPFC_EVT_WARM_START);
- 	else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
-		lpfc_workq_post_event(phba, &status, &online_compl,
-				      LPFC_EVT_KILL);
+		status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+	else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+		status = lpfc_do_offline(phba, LPFC_EVT_KILL);
 	else
 		return -EINVAL;
 
-	wait_for_completion(&online_compl);
-
 	if (!status)
 		return strlen(buf);
 	else
@@ -645,9 +687,7 @@
 	dev_printk(KERN_NOTICE, &phba->pcidev->dev,
 		   "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
 
-	init_completion(&online_compl);
-	lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
-	wait_for_completion(&online_compl);
+	stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 	if (stat1)
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
@@ -789,6 +829,18 @@
 	return -EINVAL;
 }
 
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+	struct lpfc_nodelist  *ndlp;
+
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
+		if (ndlp->rport)
+			ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+	spin_unlock_irq(phba->host->host_lock);
+}
+
 static int
 lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
 {
@@ -804,6 +856,7 @@
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -839,6 +892,7 @@
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
 		phba->dev_loss_tmo_changed = 1;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -931,9 +985,10 @@
 #       1  = 1 Gigabaud
 #       2  = 2 Gigabaud
 #       4  = 4 Gigabaud
-# Value range is [0,4]. Default value is 0.
+#       8  = 8 Gigabaud
+# Value range is [0,8]. Default value is 0.
 */
-LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed");
+LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -958,7 +1013,7 @@
 /*
 # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing
 # cr_delay (msec) or cr_count outstanding commands. cr_delay can take
-# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay
+# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay
 # is 0. Default value of cr_count is 1. The cr_count feature is disabled if
 # cr_delay is set to 0.
 */
@@ -1227,11 +1282,11 @@
 	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
 	int rc;
 
-	if (off > sizeof(MAILBOX_t))
+	if (off > MAILBOX_CMD_SIZE)
 		return -ERANGE;
 
-	if ((count + off) > sizeof(MAILBOX_t))
-		count = sizeof(MAILBOX_t) - off;
+	if ((count + off) > MAILBOX_CMD_SIZE)
+		count = MAILBOX_CMD_SIZE - off;
 
 	if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
 		return -EINVAL;
@@ -1307,6 +1362,12 @@
 			return -EPERM;
 		}
 
+		if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(host->host_lock);
+			return  -EAGAIN;
+		}
+
 		if ((phba->fc_flag & FC_OFFLINE_MODE) ||
 		    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
 
@@ -1326,6 +1387,11 @@
 		}
 
 		if (rc != MBX_SUCCESS) {
+			if (rc == MBX_TIMEOUT) {
+				phba->sysfs_mbox.mbox->mbox_cmpl =
+					lpfc_sli_def_mbox_cmpl;
+				phba->sysfs_mbox.mbox = NULL;
+			}
 			sysfs_mbox_idle(phba);
 			spin_unlock_irq(host->host_lock);
 			return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
@@ -1344,7 +1410,7 @@
 
 	phba->sysfs_mbox.offset = off + count;
 
-	if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t))
+	if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
 		sysfs_mbox_idle(phba);
 
 	spin_unlock_irq(phba->host->host_lock);
@@ -1358,7 +1424,7 @@
 		.mode = S_IRUSR | S_IWUSR,
 		.owner = THIS_MODULE,
 	},
-	.size = sizeof(MAILBOX_t),
+	.size = MAILBOX_CMD_SIZE,
 	.read = sysfs_mbox_read,
 	.write = sysfs_mbox_write,
 };
@@ -1494,6 +1560,9 @@
 			case LA_4GHZ_LINK:
 				fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
 			break;
+			case LA_8GHZ_LINK:
+				fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+			break;
 			default:
 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			break;
@@ -1546,6 +1615,9 @@
 	unsigned long seconds;
 	int rc = 0;
 
+	if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+		return NULL;
+
 	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!pmboxq)
 		return NULL;
@@ -1631,6 +1703,8 @@
 	else
 		hs->seconds_since_last_reset = seconds - psli->stats_start;
 
+	mempool_free(pmboxq, phba->mbox_mem_pool);
+
 	return hs;
 }
 
@@ -1644,6 +1718,9 @@
 	MAILBOX_t *pmb;
 	int rc = 0;
 
+	if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+		return;
+
 	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!pmboxq)
 		return;
@@ -1699,6 +1776,8 @@
 
 	psli->stats_start = get_seconds();
 
+	mempool_free(pmboxq, phba->mbox_mem_pool);
+
 	return;
 }
 
@@ -1706,67 +1785,51 @@
  * The LPFC driver treats linkdown handling as target loss events so there
  * are no sysfs handlers for link_down_tmo.
  */
-static void
-lpfc_get_starget_port_id(struct scsi_target *starget)
+
+static struct lpfc_nodelist *
+lpfc_get_node_by_target(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-	uint32_t did = -1;
-	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_nodelist *ndlp;
 
 	spin_lock_irq(shost->host_lock);
-	/* Search the mapped list for this target ID */
-	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-		if (starget->id == ndlp->nlp_sid) {
-			did = ndlp->nlp_DID;
-			break;
+	/* Search for this, mapped, target ID */
+	list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+		    starget->id == ndlp->nlp_sid) {
+			spin_unlock_irq(shost->host_lock);
+			return ndlp;
 		}
 	}
 	spin_unlock_irq(shost->host_lock);
+	return NULL;
+}
 
-	fc_starget_port_id(starget) = did;
+static void
+lpfc_get_starget_port_id(struct scsi_target *starget)
+{
+	struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
+
+	fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1;
 }
 
 static void
 lpfc_get_starget_node_name(struct scsi_target *starget)
 {
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-	u64 node_name = 0;
-	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-	spin_lock_irq(shost->host_lock);
-	/* Search the mapped list for this target ID */
-	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-		if (starget->id == ndlp->nlp_sid) {
-			node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
-			break;
-		}
-	}
-	spin_unlock_irq(shost->host_lock);
-
-	fc_starget_node_name(starget) = node_name;
+	fc_starget_node_name(starget) =
+		ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0;
 }
 
 static void
 lpfc_get_starget_port_name(struct scsi_target *starget)
 {
-	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-	struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-	u64 port_name = 0;
-	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-	spin_lock_irq(shost->host_lock);
-	/* Search the mapped list for this target ID */
-	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-		if (starget->id == ndlp->nlp_sid) {
-			port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
-			break;
-		}
-	}
-	spin_unlock_irq(shost->host_lock);
-
-	fc_starget_port_name(starget) = port_name;
+	fc_starget_port_name(starget) =
+		ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0;
 }
 
 static void
@@ -1895,25 +1958,8 @@
 			sizeof(struct fcp_rsp) +
 			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
 
-	switch (phba->pcidev->device) {
-	case PCI_DEVICE_ID_LP101:
-	case PCI_DEVICE_ID_BSMB:
-	case PCI_DEVICE_ID_ZSMB:
-		phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH;
-		break;
-	case PCI_DEVICE_ID_RFLY:
-	case PCI_DEVICE_ID_PFLY:
-	case PCI_DEVICE_ID_BMID:
-	case PCI_DEVICE_ID_ZMID:
-	case PCI_DEVICE_ID_TFLY:
-		phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH;
-		break;
-	default:
-		phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
-	}
 
-	if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth)
-		lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
 
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 1251788..b8c2a88 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,6 +18,8 @@
  * included with this package.                                     *
  *******************************************************************/
 
+typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
+
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -43,20 +45,24 @@
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_set_disctmo(struct lpfc_hba *);
 int lpfc_can_disctmo(struct lpfc_hba *);
 int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
 int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
 		    struct lpfc_iocbq *, struct lpfc_nodelist *);
-int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+int  lpfc_nlp_put(struct lpfc_nodelist *);
 struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
 void lpfc_disc_list_loopmap(struct lpfc_hba *);
 void lpfc_disc_start(struct lpfc_hba *);
 void lpfc_disc_flush_list(struct lpfc_hba *);
 void lpfc_disc_timeout(unsigned long);
 
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 
 int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -66,8 +72,7 @@
 
 int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
 		     struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
-			int);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_hba *);
 int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
@@ -113,7 +118,10 @@
 int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
-int lpfc_offline(struct lpfc_hba *);
+void lpfc_block_mgmt_io(struct lpfc_hba *);
+void lpfc_unblock_mgmt_io(struct lpfc_hba *);
+void lpfc_offline_prep(struct lpfc_hba *);
+void lpfc_offline(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -162,8 +170,8 @@
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
 					     struct lpfc_sli_ring *,
 					     dma_addr_t);
-int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
-				 struct lpfc_iocbq *);
+int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
+			       struct lpfc_iocbq *);
 int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
 			  uint64_t, lpfc_ctx_cmd);
 int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -172,9 +180,8 @@
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
-					struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
 
 int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
 			 uint32_t timeout);
@@ -193,6 +200,9 @@
 
 /* Function prototypes. */
 const char* lpfc_info(struct Scsi_Host *);
+void lpfc_scan_start(struct Scsi_Host *);
+int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
+
 void lpfc_get_cfgparam(struct lpfc_hba *);
 int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
 void lpfc_free_sysfs_attr(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index a51a41b..34a9e3b 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -334,21 +334,22 @@
 
 	lpfc_set_disctmo(phba);
 
-	Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
 
 	list_add_tail(&head, &mp->list);
 	list_for_each_entry_safe(mp, next_mp, &head, list) {
 		mlast = mp;
 
+		Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
+
 		Size -= Cnt;
 
-		if (!ctptr)
+		if (!ctptr) {
 			ctptr = (uint32_t *) mlast->virt;
-		else
+		} else
 			Cnt -= 16;	/* subtract length of CT header */
 
 		/* Loop through entire NameServer list of DIDs */
-		while (Cnt) {
+		while (Cnt >= sizeof (uint32_t)) {
 
 			/* Get next DID from NameServer List */
 			CTentry = *ctptr++;
@@ -442,10 +443,8 @@
 		if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
 			phba->fc_ns_retry++;
 			/* CT command is being retried */
-			ndlp =
-			    lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-					      NameServer_DID);
-			if (ndlp) {
+			ndlp = lpfc_findnode_did(phba, NameServer_DID);
+			if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
 				if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
 				    0) {
 					goto out;
@@ -729,7 +728,7 @@
 	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
 	uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
 
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+	ndlp = lpfc_findnode_did(phba, FDMI_DID);
 	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
 		/* FDMI rsp failed */
 		lpfc_printf_log(phba,
@@ -1039,6 +1038,9 @@
 				case LA_4GHZ_LINK:
 					ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
 				break;
+				case LA_8GHZ_LINK:
+					ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+				break;
 				default:
 					ae->un.PortSpeed =
 						HBA_PORTSPEED_UNKNOWN;
@@ -1161,7 +1163,7 @@
 {
 	struct lpfc_nodelist *ndlp;
 
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+	ndlp = lpfc_findnode_did(phba, FDMI_DID);
 	if (ndlp) {
 		if (init_utsname()->nodename[0] != '\0') {
 			lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 9766f90..498059f 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -31,6 +31,7 @@
 /* worker thread events */
 enum lpfc_work_type {
 	LPFC_EVT_ONLINE,
+	LPFC_EVT_OFFLINE_PREP,
 	LPFC_EVT_OFFLINE,
 	LPFC_EVT_WARM_START,
 	LPFC_EVT_KILL,
@@ -68,7 +69,6 @@
 	uint16_t	nlp_maxframe;		/* Max RCV frame size */
 	uint8_t		nlp_class_sup;		/* Supported Classes */
 	uint8_t         nlp_retry;		/* used for ELS retries */
-	uint8_t         nlp_disc_refcnt;	/* used for DSM */
 	uint8_t         nlp_fcp_info;	        /* class info, bits 0-3 */
 #define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */
 
@@ -79,20 +79,10 @@
 	struct lpfc_work_evt els_retry_evt;
 	unsigned long last_ramp_up_time;        /* jiffy of last ramp up */
 	unsigned long last_q_full_time;		/* jiffy of last queue full */
+	struct kref     kref;
 };
 
 /* Defines for nlp_flag (uint32) */
-#define NLP_NO_LIST        0x0		/* Indicates immediately free node */
-#define NLP_UNUSED_LIST    0x1		/* Flg to indicate node will be freed */
-#define NLP_PLOGI_LIST     0x2		/* Flg to indicate sent PLOGI */
-#define NLP_ADISC_LIST     0x3		/* Flg to indicate sent ADISC */
-#define NLP_REGLOGIN_LIST  0x4		/* Flg to indicate sent REG_LOGIN */
-#define NLP_PRLI_LIST      0x5		/* Flg to indicate sent PRLI */
-#define NLP_UNMAPPED_LIST  0x6		/* Node is now unmapped */
-#define NLP_MAPPED_LIST    0x7		/* Node is now mapped */
-#define NLP_NPR_LIST       0x8		/* Node is in NPort Recovery state */
-#define NLP_JUST_DQ        0x9		/* just deque ndlp in lpfc_nlp_list */
-#define NLP_LIST_MASK      0xf		/* mask to see what list node is on */
 #define NLP_PLOGI_SND      0x20		/* sent PLOGI request for this entry */
 #define NLP_PRLI_SND       0x40		/* sent PRLI request for this entry */
 #define NLP_ADISC_SND      0x80		/* sent ADISC request for this entry */
@@ -108,20 +98,8 @@
 					   ACC */
 #define NLP_NPR_ADISC      0x2000000	/* Issue ADISC when dq'ed from
 					   NPR list */
-#define NLP_DELAY_REMOVE   0x4000000	/* Defer removal till end of DSM */
 #define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */
 
-/* Defines for list searchs */
-#define NLP_SEARCH_MAPPED    0x1	/* search mapped */
-#define NLP_SEARCH_UNMAPPED  0x2	/* search unmapped */
-#define NLP_SEARCH_PLOGI     0x4	/* search plogi */
-#define NLP_SEARCH_ADISC     0x8	/* search adisc */
-#define NLP_SEARCH_REGLOGIN  0x10	/* search reglogin */
-#define NLP_SEARCH_PRLI      0x20	/* search prli */
-#define NLP_SEARCH_NPR       0x40	/* search npr */
-#define NLP_SEARCH_UNUSED    0x80	/* search mapped */
-#define NLP_SEARCH_ALL       0xff	/* search all lists */
-
 /* There are 4 different double linked lists nodelist entries can reside on.
  * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
  * when Link Up discovery or Registered State Change Notification (RSCN)
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index a5f33a0..638b3cd 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -182,6 +182,7 @@
 		icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
 		icmd->un.elsreq64.remoteID = did;	/* DID */
 		icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
+		icmd->ulpTimeout = phba->fc_ratov * 2;
 	} else {
 		icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
 		icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
@@ -208,9 +209,9 @@
 	}
 
 	/* Save for completion so we can release these resources */
-	elsiocb->context1 = (uint8_t *) ndlp;
-	elsiocb->context2 = (uint8_t *) pcmd;
-	elsiocb->context3 = (uint8_t *) pbuflist;
+	elsiocb->context1 = lpfc_nlp_get(ndlp);
+	elsiocb->context2 = pcmd;
+	elsiocb->context3 = pbuflist;
 	elsiocb->retry = retry;
 	elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
 
@@ -222,16 +223,16 @@
 		/* Xmit ELS command <elsCmd> to remote NPORT <did> */
 		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 				"%d:0116 Xmit ELS command x%x to remote "
-				"NPORT x%x Data: x%x x%x\n",
+				"NPORT x%x I/O tag: x%x, HBA state: x%x\n",
 				phba->brd_no, elscmd,
-				did, icmd->ulpIoTag, phba->hba_state);
+				did, elsiocb->iotag, phba->hba_state);
 	} else {
 		/* Xmit ELS response <elsCmd> to remote NPORT <did> */
 		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 				"%d:0117 Xmit ELS response x%x to remote "
-				"NPORT x%x Data: x%x x%x\n",
+				"NPORT x%x I/O tag: x%x, size: x%x\n",
 				phba->brd_no, elscmd,
-				ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
+				ndlp->nlp_DID, elsiocb->iotag, cmdSize);
 	}
 
 	return elsiocb;
@@ -304,7 +305,7 @@
 		goto fail_free_mbox;
 
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
-	mbox->context2 = ndlp;
+	mbox->context2 = lpfc_nlp_get(ndlp);
 
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
 	if (rc == MBX_NOT_FINISHED)
@@ -313,6 +314,7 @@
 	return 0;
 
  fail_issue_reg_login:
+	lpfc_nlp_put(ndlp);
 	mp = (struct lpfc_dmabuf *) mbox->context1;
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
@@ -368,9 +370,9 @@
 			mempool_free(mbox, phba->mbox_mem_pool);
 			goto fail;
 		}
-		mempool_free(ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+		ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
 		if (!ndlp) {
 			/*
 			 * Cannot find existing Fabric ndlp, so allocate a
@@ -387,12 +389,11 @@
 				sizeof(struct lpfc_name));
 		memcpy(&ndlp->nlp_nodename, &sp->nodeName,
 				sizeof(struct lpfc_name));
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
 	} else {
 		/* This side will wait for the PLOGI */
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 	}
 
 	spin_lock_irq(phba->host->host_lock);
@@ -407,8 +408,8 @@
 }
 
 static void
-lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
-		    struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		    struct lpfc_iocbq *rspiocb)
 {
 	IOCB_t *irsp = &rspiocb->iocb;
 	struct lpfc_nodelist *ndlp = cmdiocb->context1;
@@ -418,7 +419,7 @@
 
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(phba)) {
-		lpfc_nlp_remove(phba, ndlp);
+		lpfc_nlp_put(ndlp);
 		goto out;
 	}
 
@@ -433,13 +434,12 @@
 		phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
 		spin_unlock_irq(phba->host->host_lock);
 
-		/* If private loop, then allow max outstandting els to be
+		/* If private loop, then allow max outstanding els to be
 		 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
 		 * alpa map would take too long otherwise.
 		 */
 		if (phba->alpa_map[0] == 0) {
-			phba->cfg_discovery_threads =
-			    LPFC_MAX_DISC_THREADS;
+			phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
 		}
 
 		/* FLOGI failure */
@@ -484,7 +484,7 @@
 	}
 
 flogifail:
-	lpfc_nlp_remove(phba, ndlp);
+	lpfc_nlp_put(ndlp);
 
 	if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
 	    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
@@ -582,24 +582,8 @@
 		icmd = &iocb->iocb;
 		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
 			ndlp = (struct lpfc_nodelist *)(iocb->context1);
-			if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
-				list_del(&iocb->list);
-				pring->txcmplq_cnt--;
-
-				if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
-					lpfc_sli_issue_abort_iotag32
-						(phba, pring, iocb);
-				}
-				if (iocb->iocb_cmpl) {
-					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-					icmd->un.ulpWord[4] =
-					    IOERR_SLI_ABORTED;
-					spin_unlock_irq(phba->host->host_lock);
-					(iocb->iocb_cmpl) (phba, iocb, iocb);
-					spin_lock_irq(phba->host->host_lock);
-				} else
-					lpfc_sli_release_iocbq(phba, iocb);
-			}
+			if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+				lpfc_sli_issue_abort_iotag(phba, pring, iocb);
 		}
 	}
 	spin_unlock_irq(phba->host->host_lock);
@@ -608,12 +592,12 @@
 }
 
 int
-lpfc_initial_flogi(struct lpfc_hba * phba)
+lpfc_initial_flogi(struct lpfc_hba *phba)
 {
 	struct lpfc_nodelist *ndlp;
 
 	/* First look for the Fabric ndlp */
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID);
+	ndlp = lpfc_findnode_did(phba, Fabric_DID);
 	if (!ndlp) {
 		/* Cannot find existing Fabric ndlp, so allocate a new one */
 		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -621,10 +605,10 @@
 			return 0;
 		lpfc_nlp_init(phba, ndlp, Fabric_DID);
 	} else {
-		lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
+		lpfc_dequeue_node(phba, ndlp);
 	}
 	if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 	}
 	return 1;
 }
@@ -653,7 +637,7 @@
 }
 
 static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
 			 struct lpfc_nodelist *ndlp)
 {
 	struct lpfc_nodelist *new_ndlp;
@@ -670,12 +654,12 @@
 
 	lp = (uint32_t *) prsp->virt;
 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-	memset(name, 0, sizeof (struct lpfc_name));
+	memset(name, 0, sizeof(struct lpfc_name));
 
-	/* Now we to find out if the NPort we are logging into, matches the WWPN
+	/* Now we find out if the NPort we are logging into, matches the WWPN
 	 * we have for that ndlp. If not, we have some work to do.
 	 */
-	new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
+	new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
 
 	if (new_ndlp == ndlp)
 		return ndlp;
@@ -695,18 +679,15 @@
 	lpfc_unreg_rpi(phba, new_ndlp);
 	new_ndlp->nlp_DID = ndlp->nlp_DID;
 	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
-	new_ndlp->nlp_state = ndlp->nlp_state;
-	lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
+	lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
 
 	/* Move this back to NPR list */
-	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-	}
+	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+		lpfc_drop_node(phba, ndlp);
 	else {
 		lpfc_unreg_rpi(phba, ndlp);
 		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	}
 	return new_ndlp;
 }
@@ -720,13 +701,11 @@
 	struct lpfc_dmabuf *prsp;
 	int disc, rc, did, type;
 
-
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
 	irsp = &rspiocb->iocb;
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL,
-						irsp->un.elsreq64.remoteID);
+	ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
 	if (!ndlp)
 		goto out;
 
@@ -1354,7 +1333,7 @@
 	elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
 						ndlp->nlp_DID, ELS_CMD_SCR);
 	if (!elsiocb) {
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 		return 1;
 	}
 
@@ -1373,12 +1352,12 @@
 	spin_lock_irq(phba->host->host_lock);
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
 		spin_unlock_irq(phba->host->host_lock);
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
 	spin_unlock_irq(phba->host->host_lock);
-	mempool_free( ndlp, phba->nlp_mem_pool);
+	lpfc_nlp_put(ndlp);
 	return 0;
 }
 
@@ -1407,7 +1386,7 @@
 	elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
 						ndlp->nlp_DID, ELS_CMD_RNID);
 	if (!elsiocb) {
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 		return 1;
 	}
 
@@ -1428,7 +1407,7 @@
 
 	memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
 	memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
-	if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) {
+	if ((ondlp = lpfc_findnode_did(phba, nportid))) {
 		memcpy(&fp->OportName, &ondlp->nlp_portname,
 		       sizeof (struct lpfc_name));
 		memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
@@ -1440,12 +1419,12 @@
 	spin_lock_irq(phba->host->host_lock);
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
 		spin_unlock_irq(phba->host->host_lock);
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		lpfc_nlp_put(ndlp);
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
 	spin_unlock_irq(phba->host->host_lock);
-	mempool_free( ndlp, phba->nlp_mem_pool);
+	lpfc_nlp_put(ndlp);
 	return 0;
 }
 
@@ -1554,29 +1533,25 @@
 	case ELS_CMD_PLOGI:
 		if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 		}
 		break;
 	case ELS_CMD_ADISC:
 		if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
 		}
 		break;
 	case ELS_CMD_PRLI:
 		if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
 		}
 		break;
 	case ELS_CMD_LOGO:
 		if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_NPR_NODE;
-			lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		}
 		break;
 	}
@@ -1614,12 +1589,12 @@
 		cmd = *elscmd++;
 	}
 
-	if(ndlp)
+	if (ndlp)
 		did = ndlp->nlp_DID;
 	else {
 		/* We should only hit this case for retrying PLOGI */
 		did = irsp->un.elsreq64.remoteID;
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+		ndlp = lpfc_findnode_did(phba, did);
 		if (!ndlp && (cmd != ELS_CMD_PLOGI))
 			return 1;
 	}
@@ -1746,8 +1721,7 @@
 			ndlp->nlp_flag |= NLP_DELAY_TMO;
 
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_NPR_NODE;
-			lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 			ndlp->nlp_last_elscmd = cmd;
 
 			return 1;
@@ -1759,27 +1733,24 @@
 		case ELS_CMD_PLOGI:
 			if (ndlp) {
 				ndlp->nlp_prev_state = ndlp->nlp_state;
-				ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-				lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+				lpfc_nlp_set_state(phba, ndlp,
+						   NLP_STE_PLOGI_ISSUE);
 			}
 			lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
 			return 1;
 		case ELS_CMD_ADISC:
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
 			lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
 			return 1;
 		case ELS_CMD_PRLI:
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
 			lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
 			return 1;
 		case ELS_CMD_LOGO:
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_NPR_NODE;
-			lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 			lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
 			return 1;
 		}
@@ -1796,10 +1767,14 @@
 }
 
 int
-lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
+lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
 	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
 
+	if (elsiocb->context1) {
+		lpfc_nlp_put(elsiocb->context1);
+		elsiocb->context1 = NULL;
+	}
 	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
 	if (elsiocb->context2) {
 		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
@@ -1843,7 +1818,7 @@
 
 	switch (ndlp->nlp_state) {
 	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		break;
 	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
 		lpfc_unreg_rpi(phba, ndlp);
@@ -1856,8 +1831,8 @@
 }
 
 static void
-lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-		  struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		  struct lpfc_iocbq *rspiocb)
 {
 	IOCB_t *irsp;
 	struct lpfc_nodelist *ndlp;
@@ -1872,14 +1847,14 @@
 
 
 	/* Check to see if link went down during discovery */
-	if ((lpfc_els_chk_latt(phba)) || !ndlp) {
+	if (lpfc_els_chk_latt(phba) || !ndlp) {
 		if (mbox) {
 			mp = (struct lpfc_dmabuf *) mbox->context1;
 			if (mp) {
 				lpfc_mbuf_free(phba, mp->virt, mp->phys);
 				kfree(mp);
 			}
-			mempool_free( mbox, phba->mbox_mem_pool);
+			mempool_free(mbox, phba->mbox_mem_pool);
 		}
 		goto out;
 	}
@@ -1899,15 +1874,15 @@
 		    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
 			lpfc_unreg_rpi(phba, ndlp);
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-			mbox->context2 = ndlp;
+			mbox->context2 = lpfc_nlp_get(ndlp);
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
 			if (lpfc_sli_issue_mbox(phba, mbox,
 						(MBX_NOWAIT | MBX_STOP_IOCB))
 			    != MBX_NOT_FINISHED) {
 				goto out;
 			}
+			lpfc_nlp_put(ndlp);
 			/* NOTE: we should have messages for unsuccessful
 			   reglogin */
 		} else {
@@ -1917,7 +1892,7 @@
 			       (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
 			       (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
 				if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-					lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+					lpfc_drop_node(phba, ndlp);
 					ndlp = NULL;
 				}
 			}
@@ -2012,15 +1987,16 @@
 		return 1;
 	}
 
-	if (newnode)
+	if (newnode) {
+		lpfc_nlp_put(ndlp);
 		elsiocb->context1 = NULL;
+	}
 
 	/* Xmit ELS ACC response tag <ulpIoTag> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0128 Xmit ELS ACC response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
+			"%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+			"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+			phba->brd_no, elsiocb->iotag,
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2077,10 +2053,9 @@
 
 	/* Xmit ELS RJT <err> response tag <ulpIoTag> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0129 Xmit ELS RJT x%x response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			rejectError, elsiocb->iocb.ulpIoTag,
+			"%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
+			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			phba->brd_no, rejectError, elsiocb->iotag,
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2119,18 +2094,18 @@
 	if (!elsiocb)
 		return 1;
 
-	/* Xmit ADISC ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0130 Xmit ADISC ACC response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
 	icmd = &elsiocb->iocb;
 	oldcmd = &oldiocb->iocb;
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+
+	/* Xmit ADISC ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+			"x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+			phba->brd_no, elsiocb->iotag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
 	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2155,8 +2130,8 @@
 }
 
 int
-lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
-		      struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+		      struct lpfc_nodelist *ndlp)
 {
 	PRLI *npr;
 	lpfc_vpd_t *vpd;
@@ -2178,18 +2153,18 @@
 	if (!elsiocb)
 		return 1;
 
-	/* Xmit PRLI ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0131 Xmit PRLI ACC response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
 	icmd = &elsiocb->iocb;
 	oldcmd = &oldiocb->iocb;
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+
+	/* Xmit PRLI ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			phba->brd_no, elsiocb->iotag,
+			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
 	*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2232,9 +2207,8 @@
 }
 
 static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
-		      uint8_t format,
-		      struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+		      struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
 {
 	RNID *rn;
 	IOCB_t *icmd;
@@ -2259,17 +2233,17 @@
 	if (!elsiocb)
 		return 1;
 
-	/* Xmit RNID ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0132 Xmit RNID ACC response tag x%x "
-			"Data: x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
-			elsiocb->iocb.ulpContext);
-
 	icmd = &elsiocb->iocb;
 	oldcmd = &oldiocb->iocb;
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
+
+	/* Xmit RNID ACC response tag <ulpIoTag> */
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"%d:0132 Xmit RNID ACC response tag x%x "
+			"xri x%x\n",
+			phba->brd_no, elsiocb->iotag,
+			elsiocb->iocb.ulpContext);
+
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
 	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2301,6 +2275,7 @@
 
 	phba->fc_stat.elsXmitACC++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	lpfc_nlp_put(ndlp);
 	elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
 				    * it could be freed */
 
@@ -2315,32 +2290,31 @@
 }
 
 int
-lpfc_els_disc_adisc(struct lpfc_hba * phba)
+lpfc_els_disc_adisc(struct lpfc_hba *phba)
 {
 	int sentadisc;
 	struct lpfc_nodelist *ndlp, *next_ndlp;
 
 	sentadisc = 0;
-	/* go thru NPR list and issue any remaining ELS ADISCs */
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-			nlp_listp) {
-		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-			if (ndlp->nlp_flag & NLP_NPR_ADISC) {
-				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-				ndlp->nlp_prev_state = ndlp->nlp_state;
-				ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-				lpfc_nlp_list(phba, ndlp,
-					NLP_ADISC_LIST);
-				lpfc_issue_els_adisc(phba, ndlp, 0);
-				sentadisc++;
-				phba->num_disc_nodes++;
-				if (phba->num_disc_nodes >=
-				    phba->cfg_discovery_threads) {
-					spin_lock_irq(phba->host->host_lock);
-					phba->fc_flag |= FC_NLP_MORE;
-					spin_unlock_irq(phba->host->host_lock);
-					break;
-				}
+	/* go thru NPR nodes and issue any remaining ELS ADISCs */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+		    (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
+			spin_lock_irq(phba->host->host_lock);
+			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+			spin_unlock_irq(phba->host->host_lock);
+			ndlp->nlp_prev_state = ndlp->nlp_state;
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+			lpfc_issue_els_adisc(phba, ndlp, 0);
+			sentadisc++;
+			phba->num_disc_nodes++;
+			if (phba->num_disc_nodes >=
+			    phba->cfg_discovery_threads) {
+				spin_lock_irq(phba->host->host_lock);
+				phba->fc_flag |= FC_NLP_MORE;
+				spin_unlock_irq(phba->host->host_lock);
+				break;
 			}
 		}
 	}
@@ -2360,24 +2334,22 @@
 
 	sentplogi = 0;
 	/* go thru NPR list and issue any remaining ELS PLOGIs */
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-				nlp_listp) {
-		if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-		   (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
-			if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-				ndlp->nlp_prev_state = ndlp->nlp_state;
-				ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-				lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-				lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
-				sentplogi++;
-				phba->num_disc_nodes++;
-				if (phba->num_disc_nodes >=
-				    phba->cfg_discovery_threads) {
-					spin_lock_irq(phba->host->host_lock);
-					phba->fc_flag |= FC_NLP_MORE;
-					spin_unlock_irq(phba->host->host_lock);
-					break;
-				}
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+		    (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
+		    (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
+			ndlp->nlp_prev_state = ndlp->nlp_state;
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+			lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+			sentplogi++;
+			phba->num_disc_nodes++;
+			if (phba->num_disc_nodes >=
+			    phba->cfg_discovery_threads) {
+				spin_lock_irq(phba->host->host_lock);
+				phba->fc_flag |= FC_NLP_MORE;
+				spin_unlock_irq(phba->host->host_lock);
+				break;
 			}
 		}
 	}
@@ -2479,42 +2451,30 @@
 }
 
 static int
-lpfc_rscn_recovery_check(struct lpfc_hba * phba)
+lpfc_rscn_recovery_check(struct lpfc_hba *phba)
 {
-	struct lpfc_nodelist *ndlp = NULL, *next_ndlp;
-	struct list_head *listp;
-	struct list_head *node_list[7];
-	int i;
+	struct lpfc_nodelist *ndlp = NULL;
 
 	/* Look at all nodes effected by pending RSCNs and move
-	 * them to NPR list.
+	 * them to NPR state.
 	 */
-	node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-	node_list[1] = &phba->fc_nlpmap_list;
-	node_list[2] = &phba->fc_nlpunmap_list;
-	node_list[3] = &phba->fc_prli_list;
-	node_list[4] = &phba->fc_reglogin_list;
-	node_list[5] = &phba->fc_adisc_list;
-	node_list[6] = &phba->fc_plogi_list;
-	for (i = 0; i < 7; i++) {
-		listp = node_list[i];
-		if (list_empty(listp))
+
+	list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
+		    lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
 			continue;
 
-		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-			if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
-				continue;
-
-			lpfc_disc_state_machine(phba, ndlp, NULL,
+		lpfc_disc_state_machine(phba, ndlp, NULL,
 					NLP_EVT_DEVICE_RECOVERY);
 
-			/* Make sure NLP_DELAY_TMO is NOT running
-			 * after a device recovery event.
-			 */
-			if (ndlp->nlp_flag & NLP_DELAY_TMO)
-				lpfc_cancel_retry_delay_tmo(phba, ndlp);
-		}
+		/*
+		 * Make sure NLP_DELAY_TMO is NOT running after a device
+		 * recovery event.
+		 */
+		if (ndlp->nlp_flag & NLP_DELAY_TMO)
+			lpfc_cancel_retry_delay_tmo(phba, ndlp);
 	}
+
 	return 0;
 }
 
@@ -2639,8 +2599,8 @@
 
 	/* To process RSCN, first compare RSCN data with NameServer */
 	phba->fc_ns_retry = 0;
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID);
-	if (ndlp) {
+	ndlp = lpfc_findnode_did(phba, NameServer_DID);
+	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
 		/* Good ndlp, issue CT Request to NameServer */
 		if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
 			/* Wait for NameServer query cmpl before we can
@@ -2650,7 +2610,7 @@
 	} else {
 		/* If login to NameServer does not exist, issue one */
 		/* Good status, issue PLOGI to NameServer */
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+		ndlp = lpfc_findnode_did(phba, NameServer_DID);
 		if (ndlp) {
 			/* Wait for NameServer login cmpl before we can
 			   continue */
@@ -2664,8 +2624,7 @@
 			lpfc_nlp_init(phba, ndlp, NameServer_DID);
 			ndlp->nlp_type |= NLP_FABRIC;
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 			lpfc_issue_els_plogi(phba, NameServer_DID, 0);
 			/* Wait for NameServer login cmpl before we can
 			   continue */
@@ -2734,8 +2693,9 @@
 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 			rc = lpfc_sli_issue_mbox
 				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+			lpfc_set_loopback_flag(phba);
 			if (rc == MBX_NOT_FINISHED) {
-				mempool_free( mbox, phba->mbox_mem_pool);
+				mempool_free(mbox, phba->mbox_mem_pool);
 			}
 			return 1;
 		} else if (rc > 0) {	/* greater than */
@@ -2800,8 +2760,8 @@
 }
 
 static int
-lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-		 struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+		 struct lpfc_nodelist *ndlp)
 {
 	struct ls_rjt stat;
 
@@ -2815,7 +2775,7 @@
 }
 
 static void
-lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_sli *psli;
 	struct lpfc_sli_ring *pring;
@@ -2838,14 +2798,15 @@
 	pmb->context2 = NULL;
 
 	if (mb->mbxStatus) {
-		mempool_free( pmb, phba->mbox_mem_pool);
+		mempool_free(pmb, phba->mbox_mem_pool);
 		return;
 	}
 
 	cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
-	mempool_free( pmb, phba->mbox_mem_pool);
+	mempool_free(pmb, phba->mbox_mem_pool);
 	elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
 						ndlp->nlp_DID, ELS_CMD_ACC);
+	lpfc_nlp_put(ndlp);
 	if (!elsiocb)
 		return;
 
@@ -2875,15 +2836,15 @@
 
 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0118 Xmit ELS RPS ACC response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
+			"%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			phba->brd_no, elsiocb->iotag,
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
 	phba->fc_stat.elsXmitACC++;
+
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 	}
@@ -2923,13 +2884,14 @@
 			lpfc_read_lnk_stat(phba, mbox);
 			mbox->context1 =
 			    (void *)((unsigned long)cmdiocb->iocb.ulpContext);
-			mbox->context2 = ndlp;
+			mbox->context2 = lpfc_nlp_get(ndlp);
 			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
 			if (lpfc_sli_issue_mbox (phba, mbox,
 			    (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
 				/* Mbox completion will send ELS Response */
 				return 0;
 			}
+			lpfc_nlp_put(ndlp);
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
 	}
@@ -2984,10 +2946,9 @@
 
 	/* Xmit ELS RPL ACC response tag <ulpIoTag> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d:0120 Xmit ELS RPL ACC response tag x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no,
-			elsiocb->iocb.ulpIoTag,
+			"%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
+			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			phba->brd_no, elsiocb->iotag,
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -3091,8 +3052,8 @@
 			/* Log back into the node before sending the FARP. */
 			if (fp->Rflags & FARP_REQUEST_PLOGI) {
 				ndlp->nlp_prev_state = ndlp->nlp_state;
-				ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-				lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+				lpfc_nlp_set_state(phba, ndlp,
+						   NLP_STE_PLOGI_ISSUE);
 				lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 			}
 
@@ -3169,14 +3130,15 @@
 			 */
 
 			list_for_each_entry_safe(ndlp, next_ndlp,
-				&phba->fc_npr_list, nlp_listp) {
-
+						 &phba->fc_nodes, nlp_listp) {
+				if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+					continue;
 				if (ndlp->nlp_type & NLP_FABRIC) {
 					/*
 					 * Clean up old Fabric, Nameserver and
 					 * other NLP_FABRIC logins
 					 */
-					lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+					lpfc_drop_node(phba, ndlp);
 				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
 					/* Fail outstanding I/O now since this
 					 * device is marked for PLOGI
@@ -3193,20 +3155,22 @@
 		/* Discovery not needed,
 		 * move the nodes to their original state.
 		 */
-		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-			nlp_listp) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+					 nlp_listp) {
+			if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+				continue;
 
 			switch (ndlp->nlp_prev_state) {
 			case NLP_STE_UNMAPPED_NODE:
 				ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-				ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-				lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+				lpfc_nlp_set_state(phba, ndlp,
+						   NLP_STE_UNMAPPED_NODE);
 				break;
 
 			case NLP_STE_MAPPED_NODE:
 				ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-				ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-				lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+				lpfc_nlp_set_state(phba, ndlp,
+						   NLP_STE_MAPPED_NODE);
 				break;
 
 			default:
@@ -3246,9 +3210,8 @@
 	struct lpfc_iocbq *tmp_iocb, *piocb;
 	IOCB_t *cmd = NULL;
 	struct lpfc_dmabuf *pcmd;
-	struct list_head *dlp;
 	uint32_t *elscmd;
-	uint32_t els_command;
+	uint32_t els_command=0;
 	uint32_t timeout;
 	uint32_t remote_ID;
 
@@ -3263,17 +3226,20 @@
 	timeout = (uint32_t)(phba->fc_ratov << 1);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
-	dlp = &pring->txcmplq;
 
 	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
 		cmd = &piocb->iocb;
 
-		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+		if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
+			(piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
+			(piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
 			continue;
 		}
 		pcmd = (struct lpfc_dmabuf *) piocb->context2;
-		elscmd = (uint32_t *) (pcmd->virt);
-		els_command = *elscmd;
+		if (pcmd) {
+			elscmd = (uint32_t *) (pcmd->virt);
+			els_command = *elscmd;
+		}
 
 		if ((els_command == ELS_CMD_FARP)
 		    || (els_command == ELS_CMD_FARPR)) {
@@ -3289,19 +3255,10 @@
 			continue;
 		}
 
-		list_del(&piocb->list);
-		pring->txcmplq_cnt--;
-
 		if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
 			struct lpfc_nodelist *ndlp;
-			spin_unlock_irq(phba->host->host_lock);
-			ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
-			spin_lock_irq(phba->host->host_lock);
+			ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
 			remote_ID = ndlp->nlp_DID;
-			if (cmd->un.elsreq64.bdl.ulpIoTag32) {
-				lpfc_sli_issue_abort_iotag32(phba,
-					pring, piocb);
-			}
 		} else {
 			remote_ID = cmd->un.elsreq64.remoteID;
 		}
@@ -3313,17 +3270,7 @@
 				phba->brd_no, els_command,
 				remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
 
-		/*
-		 * The iocb has timed out; abort it.
-		 */
-		if (piocb->iocb_cmpl) {
-			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-			spin_unlock_irq(phba->host->host_lock);
-			(piocb->iocb_cmpl) (phba, piocb, piocb);
-			spin_lock_irq(phba->host->host_lock);
-		} else
-			lpfc_sli_release_iocbq(phba, piocb);
+		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
 	}
 	if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
 		mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
@@ -3332,16 +3279,13 @@
 }
 
 void
-lpfc_els_flush_cmd(struct lpfc_hba * phba)
+lpfc_els_flush_cmd(struct lpfc_hba *phba)
 {
-	struct lpfc_sli_ring *pring;
+	LIST_HEAD(completions);
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	struct lpfc_iocbq *tmp_iocb, *piocb;
 	IOCB_t *cmd = NULL;
-	struct lpfc_dmabuf *pcmd;
-	uint32_t *elscmd;
-	uint32_t els_command;
 
-	pring = &phba->sli.ring[LPFC_ELS_RING];
 	spin_lock_irq(phba->host->host_lock);
 	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
 		cmd = &piocb->iocb;
@@ -3351,29 +3295,15 @@
 		}
 
 		/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
-		if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) ||
-		    (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) ||
-		    (cmd->ulpCommand == CMD_CLOSE_XRI_CN) ||
-		    (cmd->ulpCommand == CMD_ABORT_XRI_CN)) {
+		if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+		    cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+		    cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+		    cmd->ulpCommand == CMD_ABORT_XRI_CN)
 			continue;
-		}
 
-		pcmd = (struct lpfc_dmabuf *) piocb->context2;
-		elscmd = (uint32_t *) (pcmd->virt);
-		els_command = *elscmd;
+		list_move_tail(&piocb->list, &completions);
+		pring->txq_cnt--;
 
-		list_del(&piocb->list);
-		pring->txcmplq_cnt--;
-
-		cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-		cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-
-		if (piocb->iocb_cmpl) {
-			spin_unlock_irq(phba->host->host_lock);
-			(piocb->iocb_cmpl) (phba, piocb, piocb);
-			spin_lock_irq(phba->host->host_lock);
-		} else
-			lpfc_sli_release_iocbq(phba, piocb);
 	}
 
 	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3382,24 +3312,24 @@
 		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
 			continue;
 		}
-		pcmd = (struct lpfc_dmabuf *) piocb->context2;
-		elscmd = (uint32_t *) (pcmd->virt);
-		els_command = *elscmd;
 
+		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	while(!list_empty(&completions)) {
+		piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		cmd = &piocb->iocb;
 		list_del(&piocb->list);
-		pring->txcmplq_cnt--;
-
-		cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-		cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
 
 		if (piocb->iocb_cmpl) {
-			spin_unlock_irq(phba->host->host_lock);
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
 			(piocb->iocb_cmpl) (phba, piocb, piocb);
-			spin_lock_irq(phba->host->host_lock);
 		} else
 			lpfc_sli_release_iocbq(phba, piocb);
 	}
-	spin_unlock_irq(phba->host->host_lock);
+
 	return;
 }
 
@@ -3468,7 +3398,7 @@
 	}
 
 	did = icmd->un.rcvels.remoteID;
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+	ndlp = lpfc_findnode_did(phba, did);
 	if (!ndlp) {
 		/* Cannot find existing Fabric ndlp, so allocate a new one */
 		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -3484,12 +3414,13 @@
 		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
 			ndlp->nlp_type |= NLP_FABRIC;
 		}
-		ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 	}
 
 	phba->fc_stat.elsRcvFrame++;
-	elsiocb->context1 = ndlp;
+	if (elsiocb->context1)
+		lpfc_nlp_put(elsiocb->context1);
+	elsiocb->context1 = lpfc_nlp_get(ndlp);
 	elsiocb->context2 = mp;
 
 	if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
@@ -3513,9 +3444,8 @@
 	case ELS_CMD_FLOGI:
 		phba->fc_stat.elsRcvFLOGI++;
 		lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	case ELS_CMD_LOGO:
 		phba->fc_stat.elsRcvLOGO++;
@@ -3536,9 +3466,8 @@
 	case ELS_CMD_RSCN:
 		phba->fc_stat.elsRcvRSCN++;
 		lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	case ELS_CMD_ADISC:
 		phba->fc_stat.elsRcvADISC++;
@@ -3579,30 +3508,26 @@
 	case ELS_CMD_LIRR:
 		phba->fc_stat.elsRcvLIRR++;
 		lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	case ELS_CMD_RPS:
 		phba->fc_stat.elsRcvRPS++;
 		lpfc_els_rcv_rps(phba, elsiocb, ndlp);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	case ELS_CMD_RPL:
 		phba->fc_stat.elsRcvRPL++;
 		lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	case ELS_CMD_RNID:
 		phba->fc_stat.elsRcvRNID++;
 		lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	default:
 		/* Unsupported ELS command, reject */
@@ -3612,9 +3537,8 @@
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
 				"%d:0115 Unknown ELS command x%x received from "
 				"NPORT x%x\n", phba->brd_no, cmd, did);
-		if (newnode) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-		}
+		if (newnode)
+			lpfc_drop_node(phba, ndlp);
 		break;
 	}
 
@@ -3627,6 +3551,8 @@
 		lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
 	}
 
+	lpfc_nlp_put(elsiocb->context1);
+	elsiocb->context1 = NULL;
 	if (elsiocb->context2) {
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c39564e..61caa8d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -109,6 +109,9 @@
 		return;
 	}
 
+	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+		return;
+
 	name = (uint8_t *)&ndlp->nlp_portname;
 	phba = ndlp->nlp_phba;
 
@@ -147,11 +150,17 @@
 				ndlp->nlp_state, ndlp->nlp_rpi);
 	}
 
-	ndlp->rport = NULL;
-	rdata->pnode = NULL;
-
-	if (!(phba->fc_flag & FC_UNLOADING))
+	if (!(phba->fc_flag & FC_UNLOADING) &&
+	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
 		lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+	else {
+		rdata->pnode = NULL;
+		ndlp->rport = NULL;
+		lpfc_nlp_put(ndlp);
+		put_device(&rport->dev);
+	}
 
 	return;
 }
@@ -182,29 +191,35 @@
 				*(int *)(evtp->evt_arg1)  = 0;
 			complete((struct completion *)(evtp->evt_arg2));
 			break;
-		case LPFC_EVT_OFFLINE:
+		case LPFC_EVT_OFFLINE_PREP:
 			if (phba->hba_state >= LPFC_LINK_DOWN)
-				lpfc_offline(phba);
+				lpfc_offline_prep(phba);
+			*(int *)(evtp->evt_arg1) = 0;
+			complete((struct completion *)(evtp->evt_arg2));
+			break;
+		case LPFC_EVT_OFFLINE:
+			lpfc_offline(phba);
 			lpfc_sli_brdrestart(phba);
 			*(int *)(evtp->evt_arg1) =
-				lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY);
+				lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
+			lpfc_unblock_mgmt_io(phba);
 			complete((struct completion *)(evtp->evt_arg2));
 			break;
 		case LPFC_EVT_WARM_START:
-			if (phba->hba_state >= LPFC_LINK_DOWN)
-				lpfc_offline(phba);
+			lpfc_offline(phba);
 			lpfc_reset_barrier(phba);
 			lpfc_sli_brdreset(phba);
 			lpfc_hba_down_post(phba);
 			*(int *)(evtp->evt_arg1) =
 				lpfc_sli_brdready(phba, HS_MBRDY);
+			lpfc_unblock_mgmt_io(phba);
 			complete((struct completion *)(evtp->evt_arg2));
 			break;
 		case LPFC_EVT_KILL:
-			if (phba->hba_state >= LPFC_LINK_DOWN)
-				lpfc_offline(phba);
+			lpfc_offline(phba);
 			*(int *)(evtp->evt_arg1)
 				= (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+			lpfc_unblock_mgmt_io(phba);
 			complete((struct completion *)(evtp->evt_arg2));
 			break;
 		}
@@ -359,13 +374,12 @@
 }
 
 int
-lpfc_linkdown(struct lpfc_hba * phba)
+lpfc_linkdown(struct lpfc_hba *phba)
 {
 	struct lpfc_sli       *psli;
 	struct lpfc_nodelist  *ndlp, *next_ndlp;
-	struct list_head *listp, *node_list[7];
-	LPFC_MBOXQ_t     *mb;
-	int               rc, i;
+	LPFC_MBOXQ_t          *mb;
+	int                   rc;
 
 	psli = &phba->sli;
 	/* sysfs or selective reset may call this routine to clean up */
@@ -397,31 +411,16 @@
 	/* Cleanup any outstanding ELS commands */
 	lpfc_els_flush_cmd(phba);
 
-	/* Issue a LINK DOWN event to all nodes */
-	node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-	node_list[1] = &phba->fc_nlpmap_list;
-	node_list[2] = &phba->fc_nlpunmap_list;
-	node_list[3] = &phba->fc_prli_list;
-	node_list[4] = &phba->fc_reglogin_list;
-	node_list[5] = &phba->fc_adisc_list;
-	node_list[6] = &phba->fc_plogi_list;
-	for (i = 0; i < 7; i++) {
-		listp = node_list[i];
-		if (list_empty(listp))
-			continue;
-
-		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-
+	/*
+	 * Issue a LINK DOWN event to all nodes.
+	 */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+				/* free any ndlp's on unused list */
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+			lpfc_drop_node(phba, ndlp);
+		else		/* otherwise, force node recovery. */
 			rc = lpfc_disc_state_machine(phba, ndlp, NULL,
-					     NLP_EVT_DEVICE_RECOVERY);
-
-		}
-	}
-
-	/* free any ndlp's on unused list */
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-				nlp_listp) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+						     NLP_EVT_DEVICE_RECOVERY);
 	}
 
 	/* Setup myDID for link up if we are in pt2pt mode */
@@ -452,11 +451,9 @@
 }
 
 static int
-lpfc_linkup(struct lpfc_hba * phba)
+lpfc_linkup(struct lpfc_hba *phba)
 {
 	struct lpfc_nodelist *ndlp, *next_ndlp;
-	struct list_head *listp, *node_list[7];
-	int i;
 
 	fc_host_post_event(phba->host, fc_get_event_number(),
 			FCH_EVT_LINKUP, 0);
@@ -470,29 +467,20 @@
 	spin_unlock_irq(phba->host->host_lock);
 
 
-	node_list[0] = &phba->fc_plogi_list;
-	node_list[1] = &phba->fc_adisc_list;
-	node_list[2] = &phba->fc_reglogin_list;
-	node_list[3] = &phba->fc_prli_list;
-	node_list[4] = &phba->fc_nlpunmap_list;
-	node_list[5] = &phba->fc_nlpmap_list;
-	node_list[6] = &phba->fc_npr_list;
-	for (i = 0; i < 7; i++) {
-		listp = node_list[i];
-		if (list_empty(listp))
-			continue;
-
-		list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-			if (phba->fc_flag & FC_LBIT) {
+	if (phba->fc_flag & FC_LBIT) {
+		list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+			if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
 				if (ndlp->nlp_type & NLP_FABRIC) {
-					/* On Linkup its safe to clean up the
+					/*
+					 * On Linkup its safe to clean up the
 					 * ndlp from Fabric connections.
 					 */
-					lpfc_nlp_list(phba, ndlp,
-							NLP_UNUSED_LIST);
+					lpfc_nlp_set_state(phba, ndlp,
+							   NLP_STE_UNUSED_NODE);
 				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-					/* Fail outstanding IO now since device
-					 * is marked for PLOGI.
+					/*
+					 * Fail outstanding IO now since
+					 * device is marked for PLOGI.
 					 */
 					lpfc_unreg_rpi(phba, ndlp);
 				}
@@ -501,9 +489,10 @@
 	}
 
 	/* free any ndlp's on unused list */
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-				nlp_listp) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+				 nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+			lpfc_drop_node(phba, ndlp);
 	}
 
 	return 0;
@@ -734,6 +723,9 @@
 		case LA_4GHZ_LINK:
 			phba->fc_linkspeed = LA_4GHZ_LINK;
 			break;
+		case LA_8GHZ_LINK:
+			phba->fc_linkspeed = LA_8GHZ_LINK;
+			break;
 		default:
 			phba->fc_linkspeed = LA_UNKNW_LINK;
 			break;
@@ -889,12 +881,21 @@
 
 	if (la->attType == AT_LINK_UP) {
 		phba->fc_stat.LinkUp++;
-		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+		if (phba->fc_flag & FC_LOOPBACK_MODE) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
+				"%d:1306 Link Up Event in loop back mode "
+				"x%x received Data: x%x x%x x%x x%x\n",
+				phba->brd_no, la->eventTag, phba->fc_eventTag,
+				la->granted_AL_PA, la->UlnkSpeed,
+				phba->alpa_map[0]);
+		} else {
+			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
 				"%d:1303 Link Up Event x%x received "
 				"Data: x%x x%x x%x x%x\n",
 				phba->brd_no, la->eventTag, phba->fc_eventTag,
 				la->granted_AL_PA, la->UlnkSpeed,
 				phba->alpa_map[0]);
+		}
 		lpfc_mbx_process_link_up(phba, la);
 	} else {
 		phba->fc_stat.LinkDown++;
@@ -940,6 +941,7 @@
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
 	mempool_free( pmb, phba->mbox_mem_pool);
+	lpfc_nlp_put(ndlp);
 
 	return;
 }
@@ -966,11 +968,14 @@
 	ndlp = (struct lpfc_nodelist *) pmb->context2;
 	mp = (struct lpfc_dmabuf *) (pmb->context1);
 
+	pmb->context1 = NULL;
+	pmb->context2 = NULL;
+
 	if (mb->mbxStatus) {
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
-		mempool_free( pmb, phba->mbox_mem_pool);
-		mempool_free( ndlp, phba->nlp_mem_pool);
+		mempool_free(pmb, phba->mbox_mem_pool);
+		lpfc_nlp_put(ndlp);
 
 		/* FLOGI failed, so just use loop map to make discovery list */
 		lpfc_disc_list_loopmap(phba);
@@ -980,12 +985,11 @@
 		return;
 	}
 
-	pmb->context1 = NULL;
-
 	ndlp->nlp_rpi = mb->un.varWords[0];
 	ndlp->nlp_type |= NLP_FABRIC;
-	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+
+	lpfc_nlp_put(ndlp);	/* Drop the reference from the mbox */
 
 	if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
 		/* This NPort has been assigned an NPort_ID by the fabric as a
@@ -996,7 +1000,7 @@
 		 */
 		lpfc_issue_els_scr(phba, SCR_DID, 0);
 
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+		ndlp = lpfc_findnode_did(phba, NameServer_DID);
 		if (!ndlp) {
 			/* Allocate a new node instance. If the pool is empty,
 			 * start the discovery process and skip the Nameserver
@@ -1008,15 +1012,14 @@
 				lpfc_disc_start(phba);
 				lpfc_mbuf_free(phba, mp->virt, mp->phys);
 				kfree(mp);
-				mempool_free( pmb, phba->mbox_mem_pool);
+				mempool_free(pmb, phba->mbox_mem_pool);
 				return;
 			} else {
 				lpfc_nlp_init(phba, ndlp, NameServer_DID);
 				ndlp->nlp_type |= NLP_FABRIC;
 			}
 		}
-		ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-		lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 		lpfc_issue_els_plogi(phba, NameServer_DID, 0);
 		if (phba->cfg_fdmi_on) {
 			ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
@@ -1032,7 +1035,7 @@
 
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
-	mempool_free( pmb, phba->mbox_mem_pool);
+	mempool_free(pmb, phba->mbox_mem_pool);
 	return;
 }
 
@@ -1057,10 +1060,11 @@
 	mp = (struct lpfc_dmabuf *) (pmb->context1);
 
 	if (mb->mbxStatus) {
+		lpfc_nlp_put(ndlp);
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
-		mempool_free( pmb, phba->mbox_mem_pool);
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		mempool_free(pmb, phba->mbox_mem_pool);
+		lpfc_drop_node(phba, ndlp);
 
 		/* RegLogin failed, so just use loop map to make discovery
 		   list */
@@ -1075,8 +1079,7 @@
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
 	ndlp->nlp_type |= NLP_FABRIC;
-	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
 	if (phba->hba_state < LPFC_HBA_READY) {
 		/* Link up discovery requires Fabrib registration. */
@@ -1093,6 +1096,7 @@
 		lpfc_disc_start(phba);
 	}
 
+	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
 	mempool_free( pmb, phba->mbox_mem_pool);
@@ -1101,8 +1105,7 @@
 }
 
 static void
-lpfc_register_remote_port(struct lpfc_hba * phba,
-			    struct lpfc_nodelist * ndlp)
+lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
 	struct fc_rport *rport;
 	struct lpfc_rport_data *rdata;
@@ -1114,8 +1117,19 @@
 	rport_ids.port_id = ndlp->nlp_DID;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
+	/*
+	 * We leave our node pointer in rport->dd_data when we unregister a
+	 * FCP target port.  But fc_remote_port_add zeros the space to which
+	 * rport->dd_data points.  So, if we're reusing a previously
+	 * registered port, drop the reference that we took the last time we
+	 * registered the port.
+	 */
+	if (ndlp->rport && ndlp->rport->dd_data &&
+	    *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+		lpfc_nlp_put(ndlp);
+	}
 	ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
-	if (!rport) {
+	if (!rport || !get_device(&rport->dev)) {
 		dev_printk(KERN_WARNING, &phba->pcidev->dev,
 			   "Warning: fc_remote_port_add failed\n");
 		return;
@@ -1125,7 +1139,7 @@
 	rport->maxframe_size = ndlp->nlp_maxframe;
 	rport->supported_classes = ndlp->nlp_class_sup;
 	rdata = rport->dd_data;
-	rdata->pnode = ndlp;
+	rdata->pnode = lpfc_nlp_get(ndlp);
 
 	if (ndlp->nlp_type & NLP_FCP_TARGET)
 		rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
@@ -1145,8 +1159,7 @@
 }
 
 static void
-lpfc_unregister_remote_port(struct lpfc_hba * phba,
-			    struct lpfc_nodelist * ndlp)
+lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
 	struct fc_rport *rport = ndlp->rport;
 	struct lpfc_rport_data *rdata = rport->dd_data;
@@ -1154,6 +1167,8 @@
 	if (rport->scsi_target_id == -1) {
 		ndlp->rport = NULL;
 		rdata->pnode = NULL;
+		lpfc_nlp_put(ndlp);
+		put_device(&rport->dev);
 	}
 
 	fc_remote_port_delete(rport);
@@ -1161,178 +1176,70 @@
 	return;
 }
 
-int
-lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
+static void
+lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
 {
-	enum { none, unmapped, mapped } rport_add = none, rport_del = none;
-	struct lpfc_sli      *psli;
-
-	psli = &phba->sli;
-	/* Sanity check to ensure we are not moving to / from the same list */
-	if ((nlp->nlp_flag & NLP_LIST_MASK) == list)
-		if (list != NLP_NO_LIST)
-			return 0;
-
 	spin_lock_irq(phba->host->host_lock);
-	switch (nlp->nlp_flag & NLP_LIST_MASK) {
-	case NLP_NO_LIST: /* Not on any list */
+	switch (state) {
+	case NLP_STE_UNUSED_NODE:
+		phba->fc_unused_cnt += count;
 		break;
-	case NLP_UNUSED_LIST:
-		phba->fc_unused_cnt--;
-		list_del(&nlp->nlp_listp);
+	case NLP_STE_PLOGI_ISSUE:
+		phba->fc_plogi_cnt += count;
 		break;
-	case NLP_PLOGI_LIST:
-		phba->fc_plogi_cnt--;
-		list_del(&nlp->nlp_listp);
+	case NLP_STE_ADISC_ISSUE:
+		phba->fc_adisc_cnt += count;
 		break;
-	case NLP_ADISC_LIST:
-		phba->fc_adisc_cnt--;
-		list_del(&nlp->nlp_listp);
+	case NLP_STE_REG_LOGIN_ISSUE:
+		phba->fc_reglogin_cnt += count;
 		break;
-	case NLP_REGLOGIN_LIST:
-		phba->fc_reglogin_cnt--;
-		list_del(&nlp->nlp_listp);
+	case NLP_STE_PRLI_ISSUE:
+		phba->fc_prli_cnt += count;
 		break;
-	case NLP_PRLI_LIST:
-		phba->fc_prli_cnt--;
-		list_del(&nlp->nlp_listp);
+	case NLP_STE_UNMAPPED_NODE:
+		phba->fc_unmap_cnt += count;
 		break;
-	case NLP_UNMAPPED_LIST:
-		phba->fc_unmap_cnt--;
-		list_del(&nlp->nlp_listp);
-		nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
-		nlp->nlp_type &= ~NLP_FC_NODE;
-		phba->nport_event_cnt++;
-		if (nlp->rport)
-			rport_del = unmapped;
+	case NLP_STE_MAPPED_NODE:
+		phba->fc_map_cnt += count;
 		break;
-	case NLP_MAPPED_LIST:
-		phba->fc_map_cnt--;
-		list_del(&nlp->nlp_listp);
-		phba->nport_event_cnt++;
-		if (nlp->rport)
-			rport_del = mapped;
-		break;
-	case NLP_NPR_LIST:
-		phba->fc_npr_cnt--;
-		list_del(&nlp->nlp_listp);
-		/* Stop delay tmo if taking node off NPR list */
-		if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
-		   (list != NLP_NPR_LIST)) {
-			spin_unlock_irq(phba->host->host_lock);
-			lpfc_cancel_retry_delay_tmo(phba, nlp);
-			spin_lock_irq(phba->host->host_lock);
-		}
+	case NLP_STE_NPR_NODE:
+		phba->fc_npr_cnt += count;
 		break;
 	}
-
-	nlp->nlp_flag &= ~NLP_LIST_MASK;
-
-	/* Add NPort <did> to <num> list */
-	lpfc_printf_log(phba,
-			KERN_INFO,
-			LOG_NODE,
-			"%d:0904 Add NPort x%x to %d list Data: x%x\n",
-			phba->brd_no,
-			nlp->nlp_DID, list, nlp->nlp_flag);
-
-	switch (list) {
-	case NLP_NO_LIST: /* No list, just remove it */
-		spin_unlock_irq(phba->host->host_lock);
-		lpfc_nlp_remove(phba, nlp);
-		spin_lock_irq(phba->host->host_lock);
-		/* as node removed - stop further transport calls */
-		rport_del = none;
-		break;
-	case NLP_UNUSED_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the unused list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list);
-		phba->fc_unused_cnt++;
-		break;
-	case NLP_PLOGI_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the plogi list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list);
-		phba->fc_plogi_cnt++;
-		break;
-	case NLP_ADISC_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the adisc list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list);
-		phba->fc_adisc_cnt++;
-		break;
-	case NLP_REGLOGIN_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the reglogin list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list);
-		phba->fc_reglogin_cnt++;
-		break;
-	case NLP_PRLI_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the prli list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list);
-		phba->fc_prli_cnt++;
-		break;
-	case NLP_UNMAPPED_LIST:
-		rport_add = unmapped;
-		/* ensure all vestiges of "mapped" significance are gone */
-		nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the unmap list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
-		phba->fc_unmap_cnt++;
-		phba->nport_event_cnt++;
-		nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-		nlp->nlp_type |= NLP_FC_NODE;
-		break;
-	case NLP_MAPPED_LIST:
-		rport_add = mapped;
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the map list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
-		phba->fc_map_cnt++;
-		phba->nport_event_cnt++;
-		nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-		break;
-	case NLP_NPR_LIST:
-		nlp->nlp_flag |= list;
-		/* Put it at the end of the npr list */
-		list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
-		phba->fc_npr_cnt++;
-
-		nlp->nlp_flag &= ~NLP_RCV_PLOGI;
-		break;
-	case NLP_JUST_DQ:
-		break;
-	}
-
 	spin_unlock_irq(phba->host->host_lock);
+}
 
-	/*
-	 * We make all the calls into the transport after we have
-	 * moved the node between lists. This so that we don't
-	 * release the lock while in-between lists.
-	 */
+static void
+lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+		       int old_state, int new_state)
+{
+	if (new_state == NLP_STE_UNMAPPED_NODE) {
+		ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+		ndlp->nlp_type |= NLP_FC_NODE;
+	}
+	if (new_state == NLP_STE_MAPPED_NODE)
+		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+	if (new_state == NLP_STE_NPR_NODE)
+		ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
 
-	/* Don't upcall midlayer if we're unloading */
-	if (!(phba->fc_flag & FC_UNLOADING)) {
-		/*
-		 * We revalidate the rport pointer as the "add" function
-		 * may have removed the remote port.
-		 */
-		if ((rport_del != none) && nlp->rport)
-			lpfc_unregister_remote_port(phba, nlp);
+	/* Transport interface */
+	if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
+			    old_state == NLP_STE_UNMAPPED_NODE)) {
+		phba->nport_event_cnt++;
+		lpfc_unregister_remote_port(phba, ndlp);
+	}
 
-		if (rport_add != none) {
+	if (new_state ==  NLP_STE_MAPPED_NODE ||
+	    new_state == NLP_STE_UNMAPPED_NODE) {
+		phba->nport_event_cnt++;
 			/*
 			 * Tell the fc transport about the port, if we haven't
 			 * already. If we have, and it's a scsi entity, be
 			 * sure to unblock any attached scsi devices
 			 */
-			if ((!nlp->rport) || (nlp->rport->port_state ==
-					FC_PORTSTATE_BLOCKED))
-				lpfc_register_remote_port(phba, nlp);
+			lpfc_register_remote_port(phba, ndlp);
+	}
 
 			/*
 			 * if we added to Mapped list, but the remote port
@@ -1340,19 +1247,95 @@
 			 * our presentable range - move the node to the
 			 * Unmapped List
 			 */
-			if ((rport_add == mapped) &&
-			    ((!nlp->rport) ||
-			     (nlp->rport->scsi_target_id == -1) ||
-			     (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
-				nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-				spin_lock_irq(phba->host->host_lock);
-				nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
-				spin_unlock_irq(phba->host->host_lock);
-				lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST);
-			}
-		}
+	if (new_state == NLP_STE_MAPPED_NODE &&
+	    (!ndlp->rport ||
+	     ndlp->rport->scsi_target_id == -1 ||
+	     ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
+		spin_lock_irq(phba->host->host_lock);
+		ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
+		spin_unlock_irq(phba->host->host_lock);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 	}
-	return 0;
+}
+
+static char *
+lpfc_nlp_state_name(char *buffer, size_t size, int state)
+{
+	static char *states[] = {
+		[NLP_STE_UNUSED_NODE] = "UNUSED",
+		[NLP_STE_PLOGI_ISSUE] = "PLOGI",
+		[NLP_STE_ADISC_ISSUE] = "ADISC",
+		[NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN",
+		[NLP_STE_PRLI_ISSUE] = "PRLI",
+		[NLP_STE_UNMAPPED_NODE] = "UNMAPPED",
+		[NLP_STE_MAPPED_NODE] = "MAPPED",
+		[NLP_STE_NPR_NODE] = "NPR",
+	};
+
+	if (state < ARRAY_SIZE(states) && states[state])
+		strlcpy(buffer, states[state], size);
+	else
+		snprintf(buffer, size, "unknown (%d)", state);
+	return buffer;
+}
+
+void
+lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+{
+	int  old_state = ndlp->nlp_state;
+	char name1[16], name2[16];
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+			"%d:0904 NPort state transition x%06x, %s -> %s\n",
+			phba->brd_no,
+			ndlp->nlp_DID,
+			lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+			lpfc_nlp_state_name(name2, sizeof(name2), state));
+	if (old_state == NLP_STE_NPR_NODE &&
+	    (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
+	    state != NLP_STE_NPR_NODE)
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
+	if (old_state == NLP_STE_UNMAPPED_NODE) {
+		ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
+		ndlp->nlp_type &= ~NLP_FC_NODE;
+	}
+
+	if (list_empty(&ndlp->nlp_listp)) {
+		spin_lock_irq(phba->host->host_lock);
+		list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
+		spin_unlock_irq(phba->host->host_lock);
+	} else if (old_state)
+		lpfc_nlp_counters(phba, old_state, -1);
+
+	ndlp->nlp_state = state;
+	lpfc_nlp_counters(phba, state, 1);
+	lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+}
+
+void
+lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+	if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
+	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+		lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+	spin_lock_irq(phba->host->host_lock);
+	list_del_init(&ndlp->nlp_listp);
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+}
+
+void
+lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+	if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
+	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+		lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+	spin_lock_irq(phba->host->host_lock);
+	list_del_init(&ndlp->nlp_listp);
+	spin_unlock_irq(phba->host->host_lock);
+	lpfc_nlp_put(ndlp);
 }
 
 /*
@@ -1464,6 +1447,7 @@
 static int
 lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+	LIST_HEAD(completions);
 	struct lpfc_sli *psli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_iocbq *iocb, *next_iocb;
@@ -1492,29 +1476,29 @@
 				     (phba, pring, iocb, ndlp))) {
 					/* It matches, so deque and call compl
 					   with an error */
-					list_del(&iocb->list);
+					list_move_tail(&iocb->list,
+						       &completions);
 					pring->txq_cnt--;
-					if (iocb->iocb_cmpl) {
-						icmd = &iocb->iocb;
-						icmd->ulpStatus =
-						    IOSTAT_LOCAL_REJECT;
-						icmd->un.ulpWord[4] =
-						    IOERR_SLI_ABORTED;
-						spin_unlock_irq(phba->host->
-								host_lock);
-						(iocb->iocb_cmpl) (phba,
-								   iocb, iocb);
-						spin_lock_irq(phba->host->
-							      host_lock);
-					} else
-						lpfc_sli_release_iocbq(phba,
-								       iocb);
 				}
 			}
 			spin_unlock_irq(phba->host->host_lock);
 
 		}
 	}
+
+	while (!list_empty(&completions)) {
+		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		list_del(&iocb->list);
+
+		if (iocb->iocb_cmpl) {
+			icmd = &iocb->iocb;
+			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+		} else
+			lpfc_sli_release_iocbq(phba, iocb);
+	}
+
 	return 0;
 }
 
@@ -1554,7 +1538,7 @@
  * so it can be freed.
  */
 static int
-lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
 	LPFC_MBOXQ_t       *mb;
 	LPFC_MBOXQ_t       *nextmb;
@@ -1567,17 +1551,7 @@
 			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
 			ndlp->nlp_state, ndlp->nlp_rpi);
 
-	lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
-
-	/*
-	 * if unloading the driver - just leave the remote port in place.
-	 * The driver unload will force the attached devices to detach
-	 * and flush cache's w/o generating flush errors.
-	 */
-	if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
-		lpfc_unregister_remote_port(phba, ndlp);
-		ndlp->nlp_sid = NLP_NO_SID;
-	}
+	lpfc_dequeue_node(phba, ndlp);
 
 	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
 	if ((mb = phba->sli.mbox_active)) {
@@ -1599,11 +1573,12 @@
 			}
 			list_del(&mb->list);
 			mempool_free(mb, phba->mbox_mem_pool);
+			lpfc_nlp_put(ndlp);
 		}
 	}
 	spin_unlock_irq(phba->host->host_lock);
 
-	lpfc_els_abort(phba,ndlp,0);
+	lpfc_els_abort(phba,ndlp);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~NLP_DELAY_TMO;
 	spin_unlock_irq(phba->host->host_lock);
@@ -1624,27 +1599,27 @@
  * If we are in the middle of using the nlp in the discovery state
  * machine, defer the free till we reach the end of the state machine.
  */
-int
-lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+static void
+lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
+	struct lpfc_rport_data *rdata;
 
 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
 		lpfc_cancel_retry_delay_tmo(phba, ndlp);
 	}
 
-	if (ndlp->nlp_disc_refcnt) {
-		spin_lock_irq(phba->host->host_lock);
-		ndlp->nlp_flag |= NLP_DELAY_REMOVE;
-		spin_unlock_irq(phba->host->host_lock);
-	} else {
-		lpfc_freenode(phba, ndlp);
-		mempool_free( ndlp, phba->nlp_mem_pool);
+	lpfc_cleanup_node(phba, ndlp);
+
+	if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
+		put_device(&ndlp->rport->dev);
+		rdata = ndlp->rport->dd_data;
+		rdata->pnode = NULL;
+		ndlp->rport = NULL;
 	}
-	return 0;
 }
 
 static int
-lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
 	D_ID mydid;
 	D_ID ndlpdid;
@@ -1693,57 +1668,36 @@
 	return 0;
 }
 
-/* Search for a nodelist entry on a specific list */
+/* Search for a nodelist entry */
 struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
+lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
 {
 	struct lpfc_nodelist *ndlp;
-	struct list_head *lists[]={&phba->fc_nlpunmap_list,
-				   &phba->fc_nlpmap_list,
-				   &phba->fc_plogi_list,
-				   &phba->fc_adisc_list,
-				   &phba->fc_reglogin_list,
-				   &phba->fc_prli_list,
-				   &phba->fc_npr_list,
-				   &phba->fc_unused_list};
-	uint32_t search[]={NLP_SEARCH_UNMAPPED,
-			   NLP_SEARCH_MAPPED,
-			   NLP_SEARCH_PLOGI,
-			   NLP_SEARCH_ADISC,
-			   NLP_SEARCH_REGLOGIN,
-			   NLP_SEARCH_PRLI,
-			   NLP_SEARCH_NPR,
-			   NLP_SEARCH_UNUSED};
-	int i;
 	uint32_t data1;
 
 	spin_lock_irq(phba->host->host_lock);
-	for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-		if (!(order & search[i]))
-			continue;
-		list_for_each_entry(ndlp, lists[i], nlp_listp) {
-			if (lpfc_matchdid(phba, ndlp, did)) {
-				data1 = (((uint32_t) ndlp->nlp_state << 24) |
-					 ((uint32_t) ndlp->nlp_xri << 16) |
-					 ((uint32_t) ndlp->nlp_type << 8) |
-					 ((uint32_t) ndlp->nlp_rpi & 0xff));
-				lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-						"%d:0929 FIND node DID "
-						" Data: x%p x%x x%x x%x\n",
-						phba->brd_no,
-						ndlp, ndlp->nlp_DID,
-						ndlp->nlp_flag, data1);
-				spin_unlock_irq(phba->host->host_lock);
-				return ndlp;
-			}
+	list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+		if (lpfc_matchdid(phba, ndlp, did)) {
+			data1 = (((uint32_t) ndlp->nlp_state << 24) |
+				 ((uint32_t) ndlp->nlp_xri << 16) |
+				 ((uint32_t) ndlp->nlp_type << 8) |
+				 ((uint32_t) ndlp->nlp_rpi & 0xff));
+			lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+					"%d:0929 FIND node DID "
+					" Data: x%p x%x x%x x%x\n",
+					phba->brd_no,
+					ndlp, ndlp->nlp_DID,
+					ndlp->nlp_flag, data1);
+			spin_unlock_irq(phba->host->host_lock);
+			return ndlp;
 		}
 	}
 	spin_unlock_irq(phba->host->host_lock);
 
 	/* FIND node did <did> NOT FOUND */
 	lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-			"%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
-			phba->brd_no, did, order);
+			"%d:0932 FIND node did x%x NOT FOUND.\n",
+			phba->brd_no, did);
 	return NULL;
 }
 
@@ -1751,9 +1705,8 @@
 lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
 {
 	struct lpfc_nodelist *ndlp;
-	uint32_t flg;
 
-	ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+	ndlp = lpfc_findnode_did(phba, did);
 	if (!ndlp) {
 		if ((phba->fc_flag & FC_RSCN_MODE) &&
 		   ((lpfc_rscn_payload_check(phba, did) == 0)))
@@ -1763,8 +1716,7 @@
 		if (!ndlp)
 			return NULL;
 		lpfc_nlp_init(phba, ndlp, did);
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
 		return ndlp;
 	}
@@ -1780,11 +1732,10 @@
 		} else
 			ndlp = NULL;
 	} else {
-		flg = ndlp->nlp_flag & NLP_LIST_MASK;
-		if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST))
+		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
+		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
 			return NULL;
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
 	}
 	return ndlp;
@@ -1842,8 +1793,9 @@
 	struct lpfc_sli *psli;
 	LPFC_MBOXQ_t *mbox;
 	struct lpfc_nodelist *ndlp, *next_ndlp;
-	uint32_t did_changed, num_sent;
+	uint32_t num_sent;
 	uint32_t clear_la_pending;
+	int did_changed;
 	int rc;
 
 	psli = &phba->sli;
@@ -1877,14 +1829,13 @@
 			phba->fc_plogi_cnt, phba->fc_adisc_cnt);
 
 	/* If our did changed, we MUST do PLOGI */
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-				nlp_listp) {
-		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-			if (did_changed) {
-				spin_lock_irq(phba->host->host_lock);
-				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-				spin_unlock_irq(phba->host->host_lock);
-			}
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+		    did_changed) {
+			spin_lock_irq(phba->host->host_lock);
+			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+			spin_unlock_irq(phba->host->host_lock);
 		}
 	}
 
@@ -1944,11 +1895,11 @@
 static void
 lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+	LIST_HEAD(completions);
 	struct lpfc_sli *psli;
 	IOCB_t     *icmd;
 	struct lpfc_iocbq    *iocb, *next_iocb;
 	struct lpfc_sli_ring *pring;
-	struct lpfc_dmabuf   *mp;
 
 	psli = &phba->sli;
 	pring = &psli->ring[LPFC_ELS_RING];
@@ -1956,6 +1907,7 @@
 	/* Error matching iocb on txq or txcmplq
 	 * First check the txq.
 	 */
+	spin_lock_irq(phba->host->host_lock);
 	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
 		if (iocb->context1 != ndlp) {
 			continue;
@@ -1964,9 +1916,8 @@
 		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
 		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
 
-			list_del(&iocb->list);
+			list_move_tail(&iocb->list, &completions);
 			pring->txq_cnt--;
-			lpfc_els_free_iocb(phba, iocb);
 		}
 	}
 
@@ -1978,44 +1929,23 @@
 		icmd = &iocb->iocb;
 		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
 		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
-
-			iocb->iocb_cmpl = NULL;
-			/* context2 = cmd, context2->next = rsp, context3 =
-			   bpl */
-			if (iocb->context2) {
-				/* Free the response IOCB before handling the
-				   command. */
-
-				mp = (struct lpfc_dmabuf *) (iocb->context2);
-				mp = list_get_first(&mp->list,
-						    struct lpfc_dmabuf,
-						    list);
-				if (mp) {
-					/* Delay before releasing rsp buffer to
-					 * give UNREG mbox a chance to take
-					 * effect.
-					 */
-					list_add(&mp->list,
-						&phba->freebufList);
-				}
-				lpfc_mbuf_free(phba,
-					       ((struct lpfc_dmabuf *)
-						iocb->context2)->virt,
-					       ((struct lpfc_dmabuf *)
-						iocb->context2)->phys);
-				kfree(iocb->context2);
-			}
-
-			if (iocb->context3) {
-				lpfc_mbuf_free(phba,
-					       ((struct lpfc_dmabuf *)
-						iocb->context3)->virt,
-					       ((struct lpfc_dmabuf *)
-						iocb->context3)->phys);
-				kfree(iocb->context3);
-			}
+			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
 		}
 	}
+	spin_unlock_irq(phba->host->host_lock);
+
+	while (!list_empty(&completions)) {
+		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		list_del(&iocb->list);
+
+		if (iocb->iocb_cmpl) {
+			icmd = &iocb->iocb;
+			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+		} else
+			lpfc_sli_release_iocbq(phba, iocb);
+	}
 
 	return;
 }
@@ -2025,21 +1955,16 @@
 {
 	struct lpfc_nodelist *ndlp, *next_ndlp;
 
-	if (phba->fc_plogi_cnt) {
-		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-					nlp_listp) {
-			lpfc_free_tx(phba, ndlp);
-			lpfc_nlp_remove(phba, ndlp);
+	if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+					 nlp_listp) {
+			if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+			    ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
+				lpfc_free_tx(phba, ndlp);
+				lpfc_nlp_put(ndlp);
+			}
 		}
 	}
-	if (phba->fc_adisc_cnt) {
-		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-					nlp_listp) {
-			lpfc_free_tx(phba, ndlp);
-			lpfc_nlp_remove(phba, ndlp);
-		}
-	}
-	return;
 }
 
 /*****************************************************************************/
@@ -2108,11 +2033,13 @@
 				 phba->brd_no);
 
 		/* Start discovery by sending FLOGI, clean up old rpis */
-		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-					nlp_listp) {
+		list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+					 nlp_listp) {
+			if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+				continue;
 			if (ndlp->nlp_type & NLP_FABRIC) {
 				/* Clean up the ndlp on Fabric connections */
-				lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+				lpfc_drop_node(phba, ndlp);
 			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
 				/* Fail outstanding IO now since device
 				 * is marked for PLOGI.
@@ -2153,9 +2080,9 @@
 				"login\n", phba->brd_no);
 
 		/* Next look for NameServer ndlp */
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+		ndlp = lpfc_findnode_did(phba, NameServer_DID);
 		if (ndlp)
-			lpfc_nlp_remove(phba, ndlp);
+			lpfc_nlp_put(ndlp);
 		/* Start discovery */
 		lpfc_disc_start(phba);
 		break;
@@ -2168,9 +2095,8 @@
 				phba->brd_no,
 				phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
 
-		ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-								NameServer_DID);
-		if (ndlp) {
+		ndlp = lpfc_findnode_did(phba, NameServer_DID);
+		if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
 			if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
 				/* Try it one more time */
 				rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
@@ -2220,6 +2146,7 @@
 		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
 		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
 					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		lpfc_set_loopback_flag(phba);
 		if (rc == MBX_NOT_FINISHED)
 			mempool_free(initlinkmbox, phba->mbox_mem_pool);
 
@@ -2317,8 +2244,7 @@
 
 	ndlp->nlp_rpi = mb->un.varWords[0];
 	ndlp->nlp_type |= NLP_FABRIC;
-	ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
 	/* Start issuing Fabric-Device Management Interface (FDMI)
 	 * command to 0xfffffa (FDMI well known port)
@@ -2333,87 +2259,100 @@
 		mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
 	}
 
+				/* Mailbox took a reference to the node */
+	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
-	mempool_free( pmb, phba->mbox_mem_pool);
+	mempool_free(pmb, phba->mbox_mem_pool);
 
 	return;
 }
 
+static int
+lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
+{
+	uint16_t *rpi = param;
+
+	return ndlp->nlp_rpi == *rpi;
+}
+
+static int
+lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
+{
+	return memcmp(&ndlp->nlp_portname, param,
+		      sizeof(ndlp->nlp_portname)) == 0;
+}
+
 /*
- * This routine looks up the ndlp  lists
- * for the given RPI. If rpi found
- * it return the node list pointer
- * else return NULL.
+ * Search node lists for a remote port matching filter criteria
+ * Caller needs to hold host_lock before calling this routine.
  */
 struct lpfc_nodelist *
-lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
+__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
 {
 	struct lpfc_nodelist *ndlp;
-	struct list_head * lists[]={&phba->fc_nlpunmap_list,
-				    &phba->fc_nlpmap_list,
-				    &phba->fc_plogi_list,
-				    &phba->fc_adisc_list,
-				    &phba->fc_reglogin_list};
-	int i;
 
-	spin_lock_irq(phba->host->host_lock);
-	for (i = 0; i < ARRAY_SIZE(lists); i++ )
-		list_for_each_entry(ndlp, lists[i], nlp_listp)
-			if (ndlp->nlp_rpi == rpi) {
-				spin_unlock_irq(phba->host->host_lock);
-				return ndlp;
-			}
-	spin_unlock_irq(phba->host->host_lock);
+	list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
+		    filter(ndlp, param))
+			return ndlp;
+	}
 	return NULL;
 }
 
 /*
- * This routine looks up the ndlp  lists
- * for the given WWPN. If WWPN found
- * it return the node list pointer
- * else return NULL.
+ * Search node lists for a remote port matching filter criteria
+ * This routine is used when the caller does NOT have host_lock.
  */
 struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order,
-		   struct lpfc_name * wwpn)
+lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
 {
 	struct lpfc_nodelist *ndlp;
-	struct list_head * lists[]={&phba->fc_nlpunmap_list,
-				    &phba->fc_nlpmap_list,
-				    &phba->fc_npr_list,
-				    &phba->fc_plogi_list,
-				    &phba->fc_adisc_list,
-				    &phba->fc_reglogin_list,
-				    &phba->fc_prli_list};
-	uint32_t search[]={NLP_SEARCH_UNMAPPED,
-			   NLP_SEARCH_MAPPED,
-			   NLP_SEARCH_NPR,
-			   NLP_SEARCH_PLOGI,
-			   NLP_SEARCH_ADISC,
-			   NLP_SEARCH_REGLOGIN,
-			   NLP_SEARCH_PRLI};
-	int i;
 
 	spin_lock_irq(phba->host->host_lock);
-	for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-		if (!(order & search[i]))
-			continue;
-		list_for_each_entry(ndlp, lists[i], nlp_listp) {
-			if (memcmp(&ndlp->nlp_portname, wwpn,
-				   sizeof(struct lpfc_name)) == 0) {
-				spin_unlock_irq(phba->host->host_lock);
-				return ndlp;
-			}
-		}
-	}
+	ndlp = __lpfc_find_node(phba, filter, param);
+	spin_unlock_irq(phba->host->host_lock);
+	return ndlp;
+}
+
+/*
+ * This routine looks up the ndlp lists for the given RPI. If rpi found it
+ * returns the node list pointer else return NULL.
+ */
+struct lpfc_nodelist *
+__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+{
+	return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+}
+
+struct lpfc_nodelist *
+lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
+{
+	struct lpfc_nodelist *ndlp;
+
+	spin_lock_irq(phba->host->host_lock);
+	ndlp = __lpfc_findnode_rpi(phba, rpi);
+	spin_unlock_irq(phba->host->host_lock);
+	return ndlp;
+}
+
+/*
+ * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
+ * returns the node list pointer else return NULL.
+ */
+struct lpfc_nodelist *
+lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
+{
+	struct lpfc_nodelist *ndlp;
+
+	spin_lock_irq(phba->host->host_lock);
+	ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
 	spin_unlock_irq(phba->host->host_lock);
 	return NULL;
 }
 
 void
-lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-		 uint32_t did)
+lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
 	memset(ndlp, 0, sizeof (struct lpfc_nodelist));
 	INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
@@ -2423,5 +2362,30 @@
 	ndlp->nlp_DID = did;
 	ndlp->nlp_phba = phba;
 	ndlp->nlp_sid = NLP_NO_SID;
+	INIT_LIST_HEAD(&ndlp->nlp_listp);
+	kref_init(&ndlp->kref);
 	return;
 }
+
+void
+lpfc_nlp_release(struct kref *kref)
+{
+	struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
+						  kref);
+	lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
+	mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+}
+
+struct lpfc_nodelist *
+lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+{
+	if (ndlp)
+		kref_get(&ndlp->kref);
+	return ndlp;
+}
+
+int
+lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+{
+	return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
+}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index f79cb61..2623a9b 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -1078,6 +1078,8 @@
 /* Start FireFly Register definitions */
 #define PCI_VENDOR_ID_EMULEX        0x10df
 #define PCI_DEVICE_ID_FIREFLY       0x1ae5
+#define PCI_DEVICE_ID_SAT_SMB       0xf011
+#define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_RFLY          0xf095
 #define PCI_DEVICE_ID_PFLY          0xf098
 #define PCI_DEVICE_ID_LP101         0xf0a1
@@ -1089,6 +1091,9 @@
 #define PCI_DEVICE_ID_NEPTUNE       0xf0f5
 #define PCI_DEVICE_ID_NEPTUNE_SCSP  0xf0f6
 #define PCI_DEVICE_ID_NEPTUNE_DCSP  0xf0f7
+#define PCI_DEVICE_ID_SAT           0xf100
+#define PCI_DEVICE_ID_SAT_SCSP      0xf111
+#define PCI_DEVICE_ID_SAT_DCSP      0xf112
 #define PCI_DEVICE_ID_SUPERFLY      0xf700
 #define PCI_DEVICE_ID_DRAGONFLY     0xf800
 #define PCI_DEVICE_ID_CENTAUR       0xf900
@@ -1098,6 +1103,7 @@
 #define PCI_DEVICE_ID_LP10000S      0xfc00
 #define PCI_DEVICE_ID_LP11000S      0xfc10
 #define PCI_DEVICE_ID_LPE11000S     0xfc20
+#define PCI_DEVICE_ID_SAT_S         0xfc40
 #define PCI_DEVICE_ID_HELIOS        0xfd00
 #define PCI_DEVICE_ID_HELIOS_SCSP   0xfd11
 #define PCI_DEVICE_ID_HELIOS_DCSP   0xfd12
@@ -1118,6 +1124,7 @@
 #define HELIOS_JEDEC_ID             0x0364
 #define ZEPHYR_JEDEC_ID             0x0577
 #define VIPER_JEDEC_ID              0x4838
+#define SATURN_JEDEC_ID             0x1004
 
 #define JEDEC_ID_MASK               0x0FFFF000
 #define JEDEC_ID_SHIFT              12
@@ -1565,7 +1572,7 @@
 #define LINK_SPEED_1G   1       /* 1 Gigabaud */
 #define LINK_SPEED_2G   2       /* 2 Gigabaud */
 #define LINK_SPEED_4G   4       /* 4 Gigabaud */
-#define LINK_SPEED_8G   8       /* 4 Gigabaud */
+#define LINK_SPEED_8G   8       /* 8 Gigabaud */
 #define LINK_SPEED_10G   16      /* 10 Gigabaud */
 
 } INIT_LINK_VAR;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index dcf6106f..dcb4ba0 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -386,12 +386,12 @@
 	 * Setup the ring 0 (els)  timeout handler
 	 */
 	timeout = phba->fc_ratov << 1;
-	phba->els_tmofunc.expires = jiffies + HZ * timeout;
-	add_timer(&phba->els_tmofunc);
+	mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
 
 	lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
 	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+	lpfc_set_loopback_flag(phba);
 	if (rc != MBX_SUCCESS) {
 		lpfc_printf_log(phba,
 				KERN_ERR,
@@ -418,33 +418,6 @@
 	return (0);
 }
 
-static int
-lpfc_discovery_wait(struct lpfc_hba *phba)
-{
-	int i = 0;
-
-	while ((phba->hba_state != LPFC_HBA_READY) ||
-	       (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
-	       ((phba->fc_map_cnt == 0) && (i<2)) ||
-	       (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
-		/* Check every second for 30 retries. */
-		i++;
-		if (i > 30) {
-			return -ETIMEDOUT;
-		}
-		if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
-			/* The link is down.  Set linkdown timeout */
-			return -ETIMEDOUT;
-		}
-
-		/* Delay for 1 second to give discovery time to complete. */
-		msleep(1000);
-
-	}
-
-	return 0;
-}
-
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_hba_down_prep                                                */
@@ -550,12 +523,15 @@
 		 * There was a firmware error.  Take the hba offline and then
 		 * attempt to restart it.
 		 */
+		lpfc_offline_prep(phba);
 		lpfc_offline(phba);
 		lpfc_sli_brdrestart(phba);
 		if (lpfc_online(phba) == 0) {	/* Initialize the HBA */
 			mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+			lpfc_unblock_mgmt_io(phba);
 			return;
 		}
+		lpfc_unblock_mgmt_io(phba);
 	} else {
 		/* The if clause above forces this code path when the status
 		 * failure is a value other than FFER6.  Do not call the offline
@@ -573,7 +549,9 @@
 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+		lpfc_offline_prep(phba);
 		lpfc_offline(phba);
+		lpfc_unblock_mgmt_io(phba);
 		phba->hba_state = LPFC_HBA_ERROR;
 		lpfc_hba_down_post(phba);
 	}
@@ -633,7 +611,7 @@
 lpfc_handle_latt_free_mp:
 	kfree(mp);
 lpfc_handle_latt_free_pmb:
-	kfree(pmb);
+	mempool_free(pmb, phba->mbox_mem_pool);
 lpfc_handle_latt_err_exit:
 	/* Enable Link attention interrupts */
 	spin_lock_irq(phba->host->host_lock);
@@ -925,6 +903,24 @@
 		m = (typeof(m)){"LPe11000-S", max_speed,
 			"PCIe"};
 		break;
+	case PCI_DEVICE_ID_SAT:
+		m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_SAT_MID:
+		m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_SAT_SMB:
+		m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_SAT_DCSP:
+		m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_SAT_SCSP:
+		m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+		break;
+	case PCI_DEVICE_ID_SAT_S:
+		m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+		break;
 	default:
 		m = (typeof(m)){ NULL };
 		break;
@@ -1174,69 +1170,17 @@
 }
 
 static void
-lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind)
+lpfc_cleanup(struct lpfc_hba * phba)
 {
 	struct lpfc_nodelist *ndlp, *next_ndlp;
 
 	/* clean up phba - lpfc specific */
 	lpfc_can_disctmo(phba);
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+		lpfc_nlp_put(ndlp);
 
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
-				 nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
+	INIT_LIST_HEAD(&phba->fc_nodes);
 
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-				nlp_listp) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-	}
-
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
-
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
-
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
-
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
-
-	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-				nlp_listp) {
-		lpfc_nlp_remove(phba, ndlp);
-	}
-
-	INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-	INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-	INIT_LIST_HEAD(&phba->fc_unused_list);
-	INIT_LIST_HEAD(&phba->fc_plogi_list);
-	INIT_LIST_HEAD(&phba->fc_adisc_list);
-	INIT_LIST_HEAD(&phba->fc_reglogin_list);
-	INIT_LIST_HEAD(&phba->fc_prli_list);
-	INIT_LIST_HEAD(&phba->fc_npr_list);
-
-	phba->fc_map_cnt   = 0;
-	phba->fc_unmap_cnt = 0;
-	phba->fc_plogi_cnt = 0;
-	phba->fc_adisc_cnt = 0;
-	phba->fc_reglogin_cnt = 0;
-	phba->fc_prli_cnt  = 0;
-	phba->fc_npr_cnt   = 0;
-	phba->fc_unused_cnt= 0;
 	return;
 }
 
@@ -1262,21 +1206,6 @@
 {
 	struct lpfc_sli *psli = &phba->sli;
 
-	/* Instead of a timer, this has been converted to a
-	 * deferred procedding list.
-	 */
-	while (!list_empty(&phba->freebufList)) {
-
-		struct lpfc_dmabuf *mp = NULL;
-
-		list_remove_head((&phba->freebufList), mp,
-				 struct lpfc_dmabuf, list);
-		if (mp) {
-			lpfc_mbuf_free(phba, mp->virt, mp->phys);
-			kfree(mp);
-		}
-	}
-
 	del_timer_sync(&phba->fcp_poll_timer);
 	del_timer_sync(&phba->fc_estabtmo);
 	del_timer_sync(&phba->fc_disctmo);
@@ -1302,60 +1231,76 @@
 		       "%d:0458 Bring Adapter online\n",
 		       phba->brd_no);
 
-	if (!lpfc_sli_queue_setup(phba))
-		return 1;
+	lpfc_block_mgmt_io(phba);
 
-	if (lpfc_sli_hba_setup(phba))	/* Initialize the HBA */
+	if (!lpfc_sli_queue_setup(phba)) {
+		lpfc_unblock_mgmt_io(phba);
 		return 1;
+	}
+
+	if (lpfc_sli_hba_setup(phba)) {	/* Initialize the HBA */
+		lpfc_unblock_mgmt_io(phba);
+		return 1;
+	}
 
 	spin_lock_irq(phba->host->host_lock);
 	phba->fc_flag &= ~FC_OFFLINE_MODE;
 	spin_unlock_irq(phba->host->host_lock);
 
+	lpfc_unblock_mgmt_io(phba);
 	return 0;
 }
 
-int
-lpfc_offline(struct lpfc_hba * phba)
+void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
 {
-	struct lpfc_sli_ring *pring;
-	struct lpfc_sli *psli;
 	unsigned long iflag;
-	int i;
-	int cnt = 0;
 
-	if (!phba)
-		return 0;
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag |= FC_BLOCK_MGMT_IO;
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+{
+	unsigned long iflag;
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_offline_prep(struct lpfc_hba * phba)
+{
+	struct lpfc_nodelist  *ndlp, *next_ndlp;
 
 	if (phba->fc_flag & FC_OFFLINE_MODE)
-		return 0;
+		return;
 
-	psli = &phba->sli;
+	lpfc_block_mgmt_io(phba);
 
 	lpfc_linkdown(phba);
+
+	/* Issue an unreg_login to all nodes */
+	list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+			lpfc_unreg_rpi(phba, ndlp);
+
 	lpfc_sli_flush_mbox_queue(phba);
+}
 
-	for (i = 0; i < psli->num_rings; i++) {
-		pring = &psli->ring[i];
-		/* The linkdown event takes 30 seconds to timeout. */
-		while (pring->txcmplq_cnt) {
-			mdelay(10);
-			if (cnt++ > 3000) {
-				lpfc_printf_log(phba,
-					KERN_WARNING, LOG_INIT,
-					"%d:0466 Outstanding IO when "
-					"bringing Adapter offline\n",
-					phba->brd_no);
-				break;
-			}
-		}
-	}
+void
+lpfc_offline(struct lpfc_hba * phba)
+{
+	unsigned long iflag;
 
+	if (phba->fc_flag & FC_OFFLINE_MODE)
+		return;
 
 	/* stop all timers associated with this hba */
 	lpfc_stop_timer(phba);
-	phba->work_hba_events = 0;
-	phba->work_ha = 0;
 
 	lpfc_printf_log(phba,
 		       KERN_WARNING,
@@ -1366,11 +1311,12 @@
 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
 	   now.  */
 	lpfc_sli_hba_down(phba);
-	lpfc_cleanup(phba, 1);
+	lpfc_cleanup(phba);
 	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->work_hba_events = 0;
+	phba->work_ha = 0;
 	phba->fc_flag |= FC_OFFLINE_MODE;
 	spin_unlock_irqrestore(phba->host->host_lock, iflag);
-	return 0;
 }
 
 /******************************************************************************
@@ -1407,6 +1353,156 @@
 	return 0;
 }
 
+void lpfc_remove_device(struct lpfc_hba *phba)
+{
+	unsigned long iflag;
+
+	lpfc_free_sysfs_attr(phba);
+
+	spin_lock_irqsave(phba->host->host_lock, iflag);
+	phba->fc_flag |= FC_UNLOADING;
+
+	spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+	fc_remove_host(phba->host);
+	scsi_remove_host(phba->host);
+
+	kthread_stop(phba->worker_thread);
+
+	/*
+	 * Bring down the SLI Layer. This step disable all interrupts,
+	 * clears the rings, discards all mailbox commands, and resets
+	 * the HBA.
+	 */
+	lpfc_sli_hba_down(phba);
+	lpfc_sli_brdrestart(phba);
+
+	/* Release the irq reservation */
+	free_irq(phba->pcidev->irq, phba);
+	pci_disable_msi(phba->pcidev);
+
+	lpfc_cleanup(phba);
+	lpfc_stop_timer(phba);
+	phba->work_hba_events = 0;
+
+	/*
+	 * Call scsi_free before mem_free since scsi bufs are released to their
+	 * corresponding pools here.
+	 */
+	lpfc_scsi_free(phba);
+	lpfc_mem_free(phba);
+
+	/* Free resources associated with SLI2 interface */
+	dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
+			  phba->slim2p, phba->slim2p_mapping);
+
+	/* unmap adapter SLIM and Control Registers */
+	iounmap(phba->ctrl_regs_memmap_p);
+	iounmap(phba->slim_memmap_p);
+
+	pci_release_regions(phba->pcidev);
+	pci_disable_device(phba->pcidev);
+
+	idr_remove(&lpfc_hba_index, phba->brd_no);
+	scsi_host_put(phba->host);
+}
+
+void lpfc_scan_start(struct Scsi_Host *host)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+
+	if (lpfc_alloc_sysfs_attr(phba))
+		goto error;
+
+	phba->MBslimaddr = phba->slim_memmap_p;
+	phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+	phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+	if (lpfc_sli_hba_setup(phba))
+		goto error;
+
+	/*
+	 * hba setup may have changed the hba_queue_depth so we need to adjust
+	 * the value of can_queue.
+	 */
+	host->can_queue = phba->cfg_hba_queue_depth - 10;
+	return;
+
+error:
+	lpfc_remove_device(phba);
+}
+
+int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+
+	if (!phba->host)
+		return 1;
+	if (time >= 30 * HZ)
+		goto finished;
+
+	if (phba->hba_state != LPFC_HBA_READY)
+		return 0;
+	if (phba->num_disc_nodes || phba->fc_prli_sent)
+		return 0;
+	if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
+		return 0;
+	if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
+		return 0;
+	if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
+		return 0;
+
+finished:
+	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+		spin_lock_irq(shost->host_lock);
+		lpfc_poll_start_timer(phba);
+		spin_unlock_irq(shost->host_lock);
+	}
+
+	/*
+	 * set fixed host attributes
+	 * Must done after lpfc_sli_hba_setup()
+	 */
+
+	fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
+	fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+	fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+	memset(fc_host_supported_fc4s(shost), 0,
+		sizeof(fc_host_supported_fc4s(shost)));
+	fc_host_supported_fc4s(shost)[2] = 1;
+	fc_host_supported_fc4s(shost)[7] = 1;
+
+	lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+
+	fc_host_supported_speeds(shost) = 0;
+	if (phba->lmt & LMT_10Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+	if (phba->lmt & LMT_4Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
+	if (phba->lmt & LMT_2Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT;
+	if (phba->lmt & LMT_1Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
+
+	fc_host_maxframe_size(shost) =
+		((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+		 (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+
+	/* This value is also unchanging */
+	memset(fc_host_active_fc4s(shost), 0,
+		sizeof(fc_host_active_fc4s(shost)));
+	fc_host_active_fc4s(shost)[2] = 1;
+	fc_host_active_fc4s(shost)[7] = 1;
+
+	spin_lock_irq(shost->host_lock);
+	phba->fc_flag &= ~FC_LOADING;
+	spin_unlock_irq(shost->host_lock);
+
+	return 1;
+}
 
 static int __devinit
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
@@ -1445,9 +1541,6 @@
 		goto out_put_host;
 
 	host->unique_id = phba->brd_no;
-	INIT_LIST_HEAD(&phba->ctrspbuflist);
-	INIT_LIST_HEAD(&phba->rnidrspbuflist);
-	INIT_LIST_HEAD(&phba->freebufList);
 
 	/* Initialize timers used by driver */
 	init_timer(&phba->fc_estabtmo);
@@ -1482,16 +1575,7 @@
 	host->max_lun = phba->cfg_max_luns;
 	host->this_id = -1;
 
-	/* Initialize all internally managed lists. */
-	INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-	INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-	INIT_LIST_HEAD(&phba->fc_unused_list);
-	INIT_LIST_HEAD(&phba->fc_plogi_list);
-	INIT_LIST_HEAD(&phba->fc_adisc_list);
-	INIT_LIST_HEAD(&phba->fc_reglogin_list);
-	INIT_LIST_HEAD(&phba->fc_prli_list);
-	INIT_LIST_HEAD(&phba->fc_npr_list);
-
+	INIT_LIST_HEAD(&phba->fc_nodes);
 
 	pci_set_master(pdev);
 	retval = pci_set_mwi(pdev);
@@ -1609,13 +1693,6 @@
 
 	host->transportt = lpfc_transport_template;
 	pci_set_drvdata(pdev, host);
-	error = scsi_add_host(host, &pdev->dev);
-	if (error)
-		goto out_kthread_stop;
-
-	error = lpfc_alloc_sysfs_attr(phba);
-	if (error)
-		goto out_remove_host;
 
 	if (phba->cfg_use_msi) {
 		error = pci_enable_msi(phba->pcidev);
@@ -1631,73 +1708,15 @@
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"%d:0451 Enable interrupt handler failed\n",
 			phba->brd_no);
-		goto out_free_sysfs_attr;
+		goto out_kthread_stop;
 	}
-	phba->MBslimaddr = phba->slim_memmap_p;
-	phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
-	phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
-	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
-	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-	error = lpfc_sli_hba_setup(phba);
-	if (error) {
-		error = -ENODEV;
+	error = scsi_add_host(host, &pdev->dev);
+	if (error)
 		goto out_free_irq;
-	}
 
-	/*
-	 * hba setup may have changed the hba_queue_depth so we need to adjust
-	 * the value of can_queue.
-	 */
-	host->can_queue = phba->cfg_hba_queue_depth - 10;
+	scsi_scan_host(host);
 
-	lpfc_discovery_wait(phba);
-
-	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
-		spin_lock_irq(phba->host->host_lock);
-		lpfc_poll_start_timer(phba);
-		spin_unlock_irq(phba->host->host_lock);
-	}
-
-	/*
-	 * set fixed host attributes
-	 * Must done after lpfc_sli_hba_setup()
-	 */
-
-	fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
-	fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
-	fc_host_supported_classes(host) = FC_COS_CLASS3;
-
-	memset(fc_host_supported_fc4s(host), 0,
-		sizeof(fc_host_supported_fc4s(host)));
-	fc_host_supported_fc4s(host)[2] = 1;
-	fc_host_supported_fc4s(host)[7] = 1;
-
-	lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
-
-	fc_host_supported_speeds(host) = 0;
-	if (phba->lmt & LMT_10Gb)
-		fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
-	if (phba->lmt & LMT_4Gb)
-		fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
-	if (phba->lmt & LMT_2Gb)
-		fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
-	if (phba->lmt & LMT_1Gb)
-		fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT;
-
-	fc_host_maxframe_size(host) =
-		((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
-		 (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
-
-	/* This value is also unchanging */
-	memset(fc_host_active_fc4s(host), 0,
-		sizeof(fc_host_active_fc4s(host)));
-	fc_host_active_fc4s(host)[2] = 1;
-	fc_host_active_fc4s(host)[7] = 1;
-
-	spin_lock_irq(phba->host->host_lock);
-	phba->fc_flag &= ~FC_LOADING;
-	spin_unlock_irq(phba->host->host_lock);
 	return 0;
 
 out_free_irq:
@@ -1705,11 +1724,6 @@
 	phba->work_hba_events = 0;
 	free_irq(phba->pcidev->irq, phba);
 	pci_disable_msi(phba->pcidev);
-out_free_sysfs_attr:
-	lpfc_free_sysfs_attr(phba);
-out_remove_host:
-	fc_remove_host(phba->host);
-	scsi_remove_host(phba->host);
 out_kthread_stop:
 	kthread_stop(phba->worker_thread);
 out_free_iocbq:
@@ -1747,56 +1761,8 @@
 {
 	struct Scsi_Host   *host = pci_get_drvdata(pdev);
 	struct lpfc_hba    *phba = (struct lpfc_hba *)host->hostdata;
-	unsigned long iflag;
 
-	lpfc_free_sysfs_attr(phba);
-
-	spin_lock_irqsave(phba->host->host_lock, iflag);
-	phba->fc_flag |= FC_UNLOADING;
-
-	spin_unlock_irqrestore(phba->host->host_lock, iflag);
-
-	fc_remove_host(phba->host);
-	scsi_remove_host(phba->host);
-
-	kthread_stop(phba->worker_thread);
-
-	/*
-	 * Bring down the SLI Layer. This step disable all interrupts,
-	 * clears the rings, discards all mailbox commands, and resets
-	 * the HBA.
-	 */
-	lpfc_sli_hba_down(phba);
-	lpfc_sli_brdrestart(phba);
-
-	/* Release the irq reservation */
-	free_irq(phba->pcidev->irq, phba);
-	pci_disable_msi(phba->pcidev);
-
-	lpfc_cleanup(phba, 0);
-	lpfc_stop_timer(phba);
-	phba->work_hba_events = 0;
-
-	/*
-	 * Call scsi_free before mem_free since scsi bufs are released to their
-	 * corresponding pools here.
-	 */
-	lpfc_scsi_free(phba);
-	lpfc_mem_free(phba);
-
-	/* Free resources associated with SLI2 interface */
-	dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
-			  phba->slim2p, phba->slim2p_mapping);
-
-	/* unmap adapter SLIM and Control Registers */
-	iounmap(phba->ctrl_regs_memmap_p);
-	iounmap(phba->slim_memmap_p);
-
-	pci_release_regions(phba->pcidev);
-	pci_disable_device(phba->pcidev);
-
-	idr_remove(&lpfc_hba_index, phba->brd_no);
-	scsi_host_put(phba->host);
+	lpfc_remove_device(phba);
 
 	pci_set_drvdata(pdev, NULL);
 }
@@ -1941,6 +1907,18 @@
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0 }
 };
 
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 4d016c2..8041c3f 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -212,6 +212,7 @@
 			case LINK_SPEED_1G:
 			case LINK_SPEED_2G:
 			case LINK_SPEED_4G:
+			case LINK_SPEED_8G:
 				mb->un.varInitLnk.link_flags |=
 							FLAGS_LINK_SPEED;
 				mb->un.varInitLnk.link_speed = linkspeed;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 0c7e731..b309841 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -168,14 +168,13 @@
  * routine effectively results in a "software abort".
  */
 int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-	int send_abts)
+lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+	LIST_HEAD(completions);
 	struct lpfc_sli *psli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_iocbq *iocb, *next_iocb;
-	IOCB_t *icmd;
-	int    found = 0;
+	IOCB_t *cmd;
 
 	/* Abort outstanding I/O on NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
@@ -188,75 +187,39 @@
 	pring = &psli->ring[LPFC_ELS_RING];
 
 	/* First check the txq */
-	do {
-		found = 0;
-		spin_lock_irq(phba->host->host_lock);
-		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-			/* Check to see if iocb matches the nport we are looking
-			   for */
-			if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
-				found = 1;
-				/* It matches, so deque and call compl with an
-				   error */
-				list_del(&iocb->list);
-				pring->txq_cnt--;
-				if (iocb->iocb_cmpl) {
-					icmd = &iocb->iocb;
-					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-					icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-					spin_unlock_irq(phba->host->host_lock);
-					(iocb->iocb_cmpl) (phba, iocb, iocb);
-					spin_lock_irq(phba->host->host_lock);
-				} else
-					lpfc_sli_release_iocbq(phba, iocb);
-				break;
-			}
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+		/* Check to see if iocb matches the nport we are looking
+		   for */
+		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+			/* It matches, so deque and call compl with an
+			   error */
+			list_move_tail(&iocb->list, &completions);
+			pring->txq_cnt--;
 		}
-		spin_unlock_irq(phba->host->host_lock);
-	} while (found);
+	}
 
-	/* Everything on txcmplq will be returned by firmware
-	 * with a no rpi / linkdown / abort error.  For ring 0,
-	 * ELS discovery, we want to get rid of it right here.
-	 */
 	/* Next check the txcmplq */
-	do {
-		found = 0;
-		spin_lock_irq(phba->host->host_lock);
-		list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
-					 list) {
-			/* Check to see if iocb matches the nport we are looking
-			   for */
-			if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
-				found = 1;
-				/* It matches, so deque and call compl with an
-				   error */
-				list_del(&iocb->list);
-				pring->txcmplq_cnt--;
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+		/* Check to see if iocb matches the nport we are looking
+		   for */
+		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+	}
+	spin_unlock_irq(phba->host->host_lock);
 
-				icmd = &iocb->iocb;
-				/* If the driver is completing an ELS
-				 * command early, flush it out of the firmware.
-				 */
-				if (send_abts &&
-				   (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) &&
-				   (icmd->un.elsreq64.bdl.ulpIoTag32)) {
-					lpfc_sli_issue_abort_iotag32(phba,
-							     pring, iocb);
-				}
-				if (iocb->iocb_cmpl) {
-					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-					icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-					spin_unlock_irq(phba->host->host_lock);
-					(iocb->iocb_cmpl) (phba, iocb, iocb);
-					spin_lock_irq(phba->host->host_lock);
-				} else
-					lpfc_sli_release_iocbq(phba, iocb);
-				break;
-			}
-		}
-		spin_unlock_irq(phba->host->host_lock);
-	} while(found);
+	while (!list_empty(&completions)) {
+		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		cmd = &iocb->iocb;
+		list_del(&iocb->list);
+
+		if (iocb->iocb_cmpl) {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+		} else
+			lpfc_sli_release_iocbq(phba, iocb);
+	}
 
 	/* If we are delaying issuing an ELS command, cancel it */
 	if (ndlp->nlp_flag & NLP_DELAY_TMO)
@@ -390,7 +353,10 @@
 	 * queue this mbox command to be processed later.
 	 */
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-	mbox->context2  = ndlp;
+	/*
+	 * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
+	 * command issued in lpfc_cmpl_els_acc().
+	 */
 	ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
 
 	/*
@@ -404,7 +370,7 @@
 	 */
 	if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
 		/* software abort outstanding PLOGI */
-		lpfc_els_abort(phba, ndlp, 1);
+		lpfc_els_abort(phba, ndlp);
 	}
 
 	lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
@@ -471,8 +437,7 @@
 	spin_unlock_irq(phba->host->host_lock);
 	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
 	ndlp->nlp_prev_state = ndlp->nlp_state;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	return 0;
 }
 
@@ -502,12 +467,10 @@
 
 		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
 		ndlp->nlp_prev_state = ndlp->nlp_state;
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	} else {
 		ndlp->nlp_prev_state = ndlp->nlp_state;
-		ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 	}
 
 	spin_lock_irq(phba->host->host_lock);
@@ -601,11 +564,10 @@
 
 	if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
 		ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-		ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 		return ndlp->nlp_state;
 	}
-	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	lpfc_drop_node(phba, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -614,7 +576,7 @@
 			 struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
 	lpfc_issue_els_logo(phba, ndlp, 0);
-	lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 	return ndlp->nlp_state;
 }
 
@@ -630,7 +592,7 @@
 	ndlp->nlp_flag |= NLP_LOGO_ACC;
 	spin_unlock_irq(phba->host->host_lock);
 	lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
-	lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 
 	return ndlp->nlp_state;
 }
@@ -639,7 +601,7 @@
 lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
 			  struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	lpfc_drop_node(phba, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -647,7 +609,7 @@
 lpfc_device_rm_unused_node(struct lpfc_hba * phba,
 			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	lpfc_drop_node(phba, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -697,7 +659,7 @@
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* software abort outstanding PLOGI */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
 	return ndlp->nlp_state;
@@ -712,7 +674,7 @@
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* software abort outstanding PLOGI */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	if (evt == NLP_EVT_RCV_LOGO) {
 		lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
@@ -727,8 +689,7 @@
 	spin_unlock_irq(phba->host->host_lock);
 	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
 	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 
 	return ndlp->nlp_state;
 }
@@ -803,32 +764,26 @@
 		goto out;
 
 	lpfc_unreg_rpi(phba, ndlp);
-	if (lpfc_reg_login
-	    (phba, irsp->un.elsreq64.remoteID,
-	     (uint8_t *) sp, mbox, 0) == 0) {
+	if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
+			   mbox, 0) == 0) {
 		switch (ndlp->nlp_DID) {
 		case NameServer_DID:
-			mbox->mbox_cmpl =
-				lpfc_mbx_cmpl_ns_reg_login;
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
 			break;
 		case FDMI_DID:
-			mbox->mbox_cmpl =
-				lpfc_mbx_cmpl_fdmi_reg_login;
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
 			break;
 		default:
-			mbox->mbox_cmpl =
-				lpfc_mbx_cmpl_reg_login;
+			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
 		}
-		mbox->context2 = ndlp;
+		mbox->context2 = lpfc_nlp_get(ndlp);
 		if (lpfc_sli_issue_mbox(phba, mbox,
 					(MBX_NOWAIT | MBX_STOP_IOCB))
 		    != MBX_NOT_FINISHED) {
-			ndlp->nlp_state =
-				NLP_STE_REG_LOGIN_ISSUE;
-			lpfc_nlp_list(phba, ndlp,
-				      NLP_REGLOGIN_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
 			return ndlp->nlp_state;
 		}
+		lpfc_nlp_put(ndlp);
 		mp = (struct lpfc_dmabuf *)mbox->context1;
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
@@ -841,7 +796,7 @@
  out:
 	/* Free this node since the driver cannot login or has the wrong
 	   sparm */
-	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	lpfc_drop_node(phba, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -855,9 +810,9 @@
 	}
 	else {
 		/* software abort outstanding PLOGI */
-		lpfc_els_abort(phba, ndlp, 1);
+		lpfc_els_abort(phba, ndlp);
 
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 }
@@ -868,11 +823,10 @@
 			    uint32_t evt)
 {
 	/* software abort outstanding PLOGI */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(phba->host->host_lock);
@@ -888,7 +842,7 @@
 	struct lpfc_iocbq *cmdiocb;
 
 	/* software abort outstanding ADISC */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
@@ -896,8 +850,7 @@
 		return ndlp->nlp_state;
 	}
 	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-	ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-	lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 	lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 
 	return ndlp->nlp_state;
@@ -926,7 +879,7 @@
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* software abort outstanding ADISC */
-	lpfc_els_abort(phba, ndlp, 0);
+	lpfc_els_abort(phba, ndlp);
 
 	lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
 	return ndlp->nlp_state;
@@ -987,20 +940,17 @@
 		memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
 
 		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		lpfc_unreg_rpi(phba, ndlp);
 		return ndlp->nlp_state;
 	}
 
 	if (ndlp->nlp_type & NLP_FCP_TARGET) {
 		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-		ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
 	} else {
 		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-		ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 	}
 	return ndlp->nlp_state;
 }
@@ -1016,9 +966,9 @@
 	}
 	else {
 		/* software abort outstanding ADISC */
-		lpfc_els_abort(phba, ndlp, 1);
+		lpfc_els_abort(phba, ndlp);
 
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 }
@@ -1029,11 +979,10 @@
 			    uint32_t evt)
 {
 	/* software abort outstanding ADISC */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -1074,9 +1023,36 @@
 			     uint32_t evt)
 {
 	struct lpfc_iocbq *cmdiocb;
+	LPFC_MBOXQ_t	  *mb;
+	LPFC_MBOXQ_t	  *nextmb;
+	struct lpfc_dmabuf *mp;
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
+	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
+	if ((mb = phba->sli.mbox_active)) {
+		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+			mb->context2 = NULL;
+			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		}
+	}
+
+	spin_lock_irq(phba->host->host_lock);
+	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+		if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+			mp = (struct lpfc_dmabuf *) (mb->context1);
+			if (mp) {
+				lpfc_mbuf_free(phba, mp->virt, mp->phys);
+				kfree(mp);
+			}
+			list_del(&mb->list);
+			mempool_free(mb, phba->mbox_mem_pool);
+		}
+	}
+	spin_unlock_irq(phba->host->host_lock);
+
 	lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
 	return ndlp->nlp_state;
 }
@@ -1133,8 +1109,7 @@
 		 */
 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
 			ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-			ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-			lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 			return ndlp->nlp_state;
 		}
 
@@ -1147,8 +1122,7 @@
 
 		lpfc_issue_els_logo(phba, ndlp, 0);
 		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-		ndlp->nlp_state = NLP_STE_NPR_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 		return ndlp->nlp_state;
 	}
 
@@ -1157,13 +1131,11 @@
 	/* Only if we are not a fabric nport do we issue PRLI */
 	if (!(ndlp->nlp_type & NLP_FABRIC)) {
 		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-		ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-		lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
 		lpfc_issue_els_prli(phba, ndlp, 0);
 	} else {
 		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-		ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 	}
 	return ndlp->nlp_state;
 }
@@ -1178,7 +1150,7 @@
 		return ndlp->nlp_state;
 	}
 	else {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 }
@@ -1189,8 +1161,7 @@
 			       uint32_t evt)
 {
 	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(phba->host->host_lock);
@@ -1230,7 +1201,7 @@
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* Software abort outstanding PRLI before sending acc */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
 	return ndlp->nlp_state;
@@ -1279,8 +1250,7 @@
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus) {
 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-		ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-		lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 		return ndlp->nlp_state;
 	}
 
@@ -1298,8 +1268,7 @@
 	}
 
 	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-	ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
 	return ndlp->nlp_state;
 }
 
@@ -1330,9 +1299,9 @@
 	}
 	else {
 		/* software abort outstanding PLOGI */
-		lpfc_els_abort(phba, ndlp, 1);
+		lpfc_els_abort(phba, ndlp);
 
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 }
@@ -1359,11 +1328,10 @@
 			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
 	/* software abort outstanding PRLI */
-	lpfc_els_abort(phba, ndlp, 1);
+	lpfc_els_abort(phba, ndlp);
 
 	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(phba->host->host_lock);
@@ -1436,8 +1404,7 @@
 			   struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
 	ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	lpfc_disc_set_adisc(phba, ndlp);
 
@@ -1518,8 +1485,7 @@
 			    uint32_t evt)
 {
 	ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
-	ndlp->nlp_state = NLP_STE_NPR_NODE;
-	lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+	lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(phba->host->host_lock);
@@ -1551,8 +1517,7 @@
 	/* send PLOGI immediately, move to PLOGI issue state */
 	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
 		ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-		ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-		lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+		lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 		lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 	}
 
@@ -1580,16 +1545,13 @@
 			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 			spin_unlock_irq(phba->host->host_lock);
 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
 			lpfc_issue_els_adisc(phba, ndlp, 0);
 		} else {
 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 			lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 		}
-
 	}
 	return ndlp->nlp_state;
 }
@@ -1627,13 +1589,11 @@
 		!(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
 		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-			ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
 			lpfc_issue_els_adisc(phba, ndlp, 0);
 		} else {
 			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-			ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-			lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+			lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
 			lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 		}
 	}
@@ -1682,7 +1642,7 @@
 
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 	return ndlp->nlp_state;
@@ -1700,7 +1660,7 @@
 
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 	return ndlp->nlp_state;
@@ -1728,7 +1688,7 @@
 
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-		lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+		lpfc_drop_node(phba, ndlp);
 		return NLP_STE_FREED_NODE;
 	}
 	return ndlp->nlp_state;
@@ -1749,7 +1709,7 @@
 		ndlp->nlp_rpi = mb->un.varWords[0];
 	else {
 		if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
-			lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+			lpfc_drop_node(phba, ndlp);
 			return NLP_STE_FREED_NODE;
 		}
 	}
@@ -1765,7 +1725,7 @@
 		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
 		return ndlp->nlp_state;
 	}
-	lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+	lpfc_drop_node(phba, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -1964,7 +1924,7 @@
 	uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
 			 uint32_t);
 
-	ndlp->nlp_disc_refcnt++;
+	lpfc_nlp_get(ndlp);
 	cur_state = ndlp->nlp_state;
 
 	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
@@ -1987,18 +1947,7 @@
 		       phba->brd_no,
 		       rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
-	ndlp->nlp_disc_refcnt--;
+	lpfc_nlp_put(ndlp);
 
-	/* Check to see if ndlp removal is deferred */
-	if ((ndlp->nlp_disc_refcnt == 0)
-	    && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) {
-		spin_lock_irq(phba->host->host_lock);
-		ndlp->nlp_flag &= ~NLP_DELAY_REMOVE;
-		spin_unlock_irq(phba->host->host_lock);
-		lpfc_nlp_remove(phba, ndlp);
-		return NLP_STE_FREED_NODE;
-	}
-	if (rc == NLP_STE_FREED_NODE)
-		return NLP_STE_FREED_NODE;
 	return rc;
 }
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c3e68e0..9a12d05 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -146,6 +146,10 @@
 
 	spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
 	list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+	if (lpfc_cmd) {
+		lpfc_cmd->seg_cnt = 0;
+		lpfc_cmd->nonsg_phys = 0;
+	}
 	spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
 	return  lpfc_cmd;
 }
@@ -288,13 +292,13 @@
 }
 
 static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
 {
 	struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
 	struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
 	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
 	struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
-	uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
+	uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
 	uint32_t resp_info = fcprsp->rspStatus2;
 	uint32_t scsi_status = fcprsp->rspStatus3;
 	uint32_t *lp;
@@ -356,6 +360,24 @@
 				fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
 
 		/*
+		 * If there is an under run check if under run reported by
+		 * storage array is same as the under run reported by HBA.
+		 * If this is not same, there is a dropped frame.
+		 */
+		if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
+			fcpi_parm &&
+			(cmnd->resid != fcpi_parm)) {
+			lpfc_printf_log(phba, KERN_WARNING,
+				LOG_FCP | LOG_FCP_ERROR,
+				"%d:0735 FCP Read Check Error and Underrun "
+				"Data: x%x x%x x%x x%x\n", phba->brd_no,
+				be32_to_cpu(fcpcmd->fcpDl),
+				cmnd->resid,
+				fcpi_parm, cmnd->cmnd[0]);
+			cmnd->resid = cmnd->request_bufflen;
+			host_status = DID_ERROR;
+		}
+		/*
 		 * The cmnd->underflow is the minimum number of bytes that must
 		 * be transfered for this command.  Provided a sense condition
 		 * is not present, make sure the actual amount transferred is at
@@ -435,7 +457,7 @@
 		switch (lpfc_cmd->status) {
 		case IOSTAT_FCP_RSP_ERROR:
 			/* Call FCP RSP handler to determine result */
-			lpfc_handle_fcp_err(lpfc_cmd);
+			lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
 			break;
 		case IOSTAT_NPORT_BSY:
 		case IOSTAT_FABRIC_BSY:
@@ -466,10 +488,10 @@
 
 	result = cmd->result;
 	sdev = cmd->device;
+	lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
 	cmd->scsi_done(cmd);
 
 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
-		lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return;
 	}
@@ -527,7 +549,6 @@
 		}
 	}
 
-	lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
 	lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -670,6 +691,18 @@
 	return (1);
 }
 
+static void
+lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
+			struct lpfc_iocbq *cmdiocbq,
+			struct lpfc_iocbq *rspiocbq)
+{
+	struct lpfc_scsi_buf *lpfc_cmd =
+		(struct lpfc_scsi_buf *) cmdiocbq->context1;
+	if (lpfc_cmd)
+		lpfc_release_scsi_buf(phba, lpfc_cmd);
+	return;
+}
+
 static int
 lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
 		    unsigned  tgt_id, unsigned int lun,
@@ -706,8 +739,9 @@
 				       &phba->sli.ring[phba->sli.fcp_ring],
 				       iocbq, iocbqrsp, lpfc_cmd->timeout);
 	if (ret != IOCB_SUCCESS) {
+		if (ret == IOCB_TIMEDOUT)
+			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
 		lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
-		ret = FAILED;
 	} else {
 		ret = SUCCESS;
 		lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
@@ -974,7 +1008,7 @@
 }
 
 static int
-lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
+lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 {
 	struct Scsi_Host *shost = cmnd->device->host;
 	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -984,6 +1018,7 @@
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	uint32_t cmd_result = 0, cmd_status = 0;
 	int ret = FAILED;
+	int iocb_status = IOCB_SUCCESS;
 	int cnt, loopcnt;
 
 	lpfc_block_error_handler(cmnd);
@@ -995,7 +1030,7 @@
 	 */
 	while ( 1 ) {
 		if (!pnode)
-			return FAILED;
+			goto out;
 
 		if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
 			spin_unlock_irq(phba->host->host_lock);
@@ -1013,7 +1048,7 @@
 			}
 			pnode = rdata->pnode;
 			if (!pnode)
-				return FAILED;
+				goto out;
 		}
 		if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
 			break;
@@ -1028,7 +1063,7 @@
 	lpfc_cmd->rdata = rdata;
 
 	ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
-					   FCP_LUN_RESET);
+					   FCP_TARGET_RESET);
 	if (!ret)
 		goto out_free_scsi_buf;
 
@@ -1040,16 +1075,21 @@
 		goto out_free_scsi_buf;
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-			"%d:0703 Issue LUN Reset to TGT %d LUN %d "
-			"Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
+			"%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
+			"nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
 			cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
 
-	ret = lpfc_sli_issue_iocb_wait(phba,
+	iocb_status = lpfc_sli_issue_iocb_wait(phba,
 				       &phba->sli.ring[phba->sli.fcp_ring],
 				       iocbq, iocbqrsp, lpfc_cmd->timeout);
-	if (ret == IOCB_SUCCESS)
-		ret = SUCCESS;
 
+	if (iocb_status == IOCB_TIMEDOUT)
+		iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+
+	if (iocb_status == IOCB_SUCCESS)
+		ret = SUCCESS;
+	else
+		ret = iocb_status;
 
 	cmd_result = iocbqrsp->iocb.un.ulpWord[4];
 	cmd_status = iocbqrsp->iocb.ulpStatus;
@@ -1087,18 +1127,19 @@
 
 	if (cnt) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
+			"%d:0719 device reset I/O flush failure: cnt x%x\n",
 			phba->brd_no, cnt);
 		ret = FAILED;
 	}
 
 out_free_scsi_buf:
-	lpfc_release_scsi_buf(phba, lpfc_cmd);
-
+	if (iocb_status != IOCB_TIMEDOUT) {
+		lpfc_release_scsi_buf(phba, lpfc_cmd);
+	}
 	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d:0713 SCSI layer issued LUN reset (%d, %d) "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, cmnd->device->id,cmnd->device->lun,
+			"%d:0713 SCSI layer issued device reset (%d, %d) "
+			"return x%x status x%x result x%x\n",
+			phba->brd_no, cmnd->device->id, cmnd->device->lun,
 			ret, cmd_status, cmd_result);
 
 out:
@@ -1107,7 +1148,7 @@
 }
 
 static int
-lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 {
 	struct Scsi_Host *shost = cmnd->device->host;
 	struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -1134,10 +1175,12 @@
 	 * fail, this routine returns failure to the midlayer.
 	 */
 	for (i = 0; i < LPFC_MAX_TARGET; i++) {
-		/* Search the mapped list for this target ID */
+		/* Search for mapped node by target ID */
 		match = 0;
-		list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-			if ((i == ndlp->nlp_sid) && ndlp->rport) {
+		list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+			if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+			    i == ndlp->nlp_sid &&
+			    ndlp->rport) {
 				match = 1;
 				break;
 			}
@@ -1152,13 +1195,17 @@
 				"%d:0700 Bus Reset on target %d failed\n",
 				phba->brd_no, i);
 			err_count++;
+			break;
 		}
 	}
 
+	if (ret != IOCB_TIMEDOUT)
+		lpfc_release_scsi_buf(phba, lpfc_cmd);
+
 	if (err_count == 0)
 		ret = SUCCESS;
-
-	lpfc_release_scsi_buf(phba, lpfc_cmd);
+	else
+		ret = FAILED;
 
 	/*
 	 * All outstanding txcmplq I/Os should have been aborted by
@@ -1299,11 +1346,13 @@
 	.info			= lpfc_info,
 	.queuecommand		= lpfc_queuecommand,
 	.eh_abort_handler	= lpfc_abort_handler,
-	.eh_device_reset_handler= lpfc_reset_lun_handler,
-	.eh_bus_reset_handler	= lpfc_reset_bus_handler,
+	.eh_device_reset_handler= lpfc_device_reset_handler,
+	.eh_bus_reset_handler	= lpfc_bus_reset_handler,
 	.slave_alloc		= lpfc_slave_alloc,
 	.slave_configure	= lpfc_slave_configure,
 	.slave_destroy		= lpfc_slave_destroy,
+	.scan_finished		= lpfc_scan_finished,
+	.scan_start		= lpfc_scan_start,
 	.this_id		= -1,
 	.sg_tablesize		= LPFC_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 9fb6960..a1e7214 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -528,6 +528,7 @@
 	 * If pdone_q is empty, the driver thread gave up waiting and
 	 * continued running.
 	 */
+	pmboxq->mbox_flag |= LPFC_MBX_WAKE;
 	pdone_q = (wait_queue_head_t *) pmboxq->context1;
 	if (pdone_q)
 		wake_up_interruptible(pdone_q);
@@ -538,11 +539,32 @@
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
 	struct lpfc_dmabuf *mp;
+	uint16_t rpi;
+	int rc;
+
 	mp = (struct lpfc_dmabuf *) (pmb->context1);
+
 	if (mp) {
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
 	}
+
+	/*
+	 * If a REG_LOGIN succeeded  after node is destroyed or node
+	 * is in re-discovery driver need to cleanup the RPI.
+	 */
+	if (!(phba->fc_flag & FC_UNLOADING) &&
+		(pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+		(!pmb->mb.mbxStatus)) {
+
+		rpi = pmb->mb.un.varWords[0];
+		lpfc_unreg_login(phba, rpi, pmb);
+		pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+		if (rc != MBX_NOT_FINISHED)
+			return;
+	}
+
 	mempool_free( pmb, phba->mbox_mem_pool);
 	return;
 }
@@ -693,25 +715,8 @@
 		} else {
 			spin_unlock_irq(phba->host->host_lock);
 			/* Turn on IOCB processing */
-			for (i = 0; i < phba->sli.num_rings; i++) {
+			for (i = 0; i < phba->sli.num_rings; i++)
 				lpfc_sli_turn_on_ring(phba, i);
-			}
-
-			/* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */
-			while (!list_empty(&phba->freebufList)) {
-				struct lpfc_dmabuf *mp;
-
-				mp = NULL;
-				list_remove_head((&phba->freebufList),
-						 mp,
-						 struct lpfc_dmabuf,
-						 list);
-				if (mp) {
-					lpfc_mbuf_free(phba, mp->virt,
-						       mp->phys);
-					kfree(mp);
-				}
-			}
 		}
 
 	} while (process_next);
@@ -833,6 +838,14 @@
 			 * All other are passed to the completion callback.
 			 */
 			if (pring->ringno == LPFC_ELS_RING) {
+				if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+					cmdiocbp->iocb_flag &=
+						~LPFC_DRIVER_ABORTED;
+					saveq->iocb.ulpStatus =
+						IOSTAT_LOCAL_REJECT;
+					saveq->iocb.un.ulpWord[4] =
+						IOERR_SLI_ABORTED;
+				}
 				spin_unlock_irqrestore(phba->host->host_lock,
 						       iflag);
 				(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1464,8 +1477,9 @@
 int
 lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
+	LIST_HEAD(completions);
 	struct lpfc_iocbq *iocb, *next_iocb;
-	IOCB_t *icmd = NULL, *cmd = NULL;
+	IOCB_t *cmd = NULL;
 	int errcnt;
 
 	errcnt = 0;
@@ -1474,46 +1488,28 @@
 	 * First do the txq.
 	 */
 	spin_lock_irq(phba->host->host_lock);
-	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-		list_del_init(&iocb->list);
-		if (iocb->iocb_cmpl) {
-			icmd = &iocb->iocb;
-			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-			spin_unlock_irq(phba->host->host_lock);
-			(iocb->iocb_cmpl) (phba, iocb, iocb);
-			spin_lock_irq(phba->host->host_lock);
-		} else
-			lpfc_sli_release_iocbq(phba, iocb);
-	}
+	list_splice_init(&pring->txq, &completions);
 	pring->txq_cnt = 0;
-	INIT_LIST_HEAD(&(pring->txq));
 
 	/* Next issue ABTS for everything on the txcmplq */
-	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+		lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+
+	spin_unlock_irq(phba->host->host_lock);
+
+	while (!list_empty(&completions)) {
+		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
 		cmd = &iocb->iocb;
-
-		/*
-		 * Imediate abort of IOCB, deque and call compl
-		 */
-
-		list_del_init(&iocb->list);
-		pring->txcmplq_cnt--;
+		list_del(&iocb->list);
 
 		if (iocb->iocb_cmpl) {
 			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
 			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-			spin_unlock_irq(phba->host->host_lock);
 			(iocb->iocb_cmpl) (phba, iocb, iocb);
-			spin_lock_irq(phba->host->host_lock);
 		} else
 			lpfc_sli_release_iocbq(phba, iocb);
 	}
 
-	INIT_LIST_HEAD(&pring->txcmplq);
-	pring->txcmplq_cnt = 0;
-	spin_unlock_irq(phba->host->host_lock);
-
 	return errcnt;
 }
 
@@ -1588,6 +1584,7 @@
 	hc_copy = readl(phba->HCregaddr);
 	writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
 	readl(phba->HCregaddr); /* flush */
+	phba->fc_flag |= FC_IGNORE_ERATT;
 
 	if (readl(phba->HAregaddr) & HA_ERATT) {
 		/* Clear Chip error bit */
@@ -1630,6 +1627,7 @@
 	}
 
 restore_hc:
+	phba->fc_flag &= ~FC_IGNORE_ERATT;
 	writel(hc_copy, phba->HCregaddr);
 	readl(phba->HCregaddr); /* flush */
 }
@@ -1665,6 +1663,7 @@
 	status &= ~HC_ERINT_ENA;
 	writel(status, phba->HCregaddr);
 	readl(phba->HCregaddr); /* flush */
+	phba->fc_flag |= FC_IGNORE_ERATT;
 	spin_unlock_irq(phba->host->host_lock);
 
 	lpfc_kill_board(phba, pmb);
@@ -1674,6 +1673,9 @@
 	if (retval != MBX_SUCCESS) {
 		if (retval != MBX_BUSY)
 			mempool_free(pmb, phba->mbox_mem_pool);
+		spin_lock_irq(phba->host->host_lock);
+		phba->fc_flag &= ~FC_IGNORE_ERATT;
+		spin_unlock_irq(phba->host->host_lock);
 		return 1;
 	}
 
@@ -1700,6 +1702,7 @@
 	}
 	spin_lock_irq(phba->host->host_lock);
 	psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+	phba->fc_flag &= ~FC_IGNORE_ERATT;
 	spin_unlock_irq(phba->host->host_lock);
 
 	psli->mbox_active = NULL;
@@ -1985,42 +1988,6 @@
 	return rc;
 }
 
-static void
-lpfc_mbox_abort(struct lpfc_hba * phba)
-{
-	LPFC_MBOXQ_t *pmbox;
-	MAILBOX_t *mb;
-
-	if (phba->sli.mbox_active) {
-		del_timer_sync(&phba->sli.mbox_tmo);
-		phba->work_hba_events &= ~WORKER_MBOX_TMO;
-		pmbox = phba->sli.mbox_active;
-		mb = &pmbox->mb;
-		phba->sli.mbox_active = NULL;
-		if (pmbox->mbox_cmpl) {
-			mb->mbxStatus = MBX_NOT_FINISHED;
-			(pmbox->mbox_cmpl) (phba, pmbox);
-		}
-		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-	}
-
-	/* Abort all the non active mailbox commands. */
-	spin_lock_irq(phba->host->host_lock);
-	pmbox = lpfc_mbox_get(phba);
-	while (pmbox) {
-		mb = &pmbox->mb;
-		if (pmbox->mbox_cmpl) {
-			mb->mbxStatus = MBX_NOT_FINISHED;
-			spin_unlock_irq(phba->host->host_lock);
-			(pmbox->mbox_cmpl) (phba, pmbox);
-			spin_lock_irq(phba->host->host_lock);
-		}
-		pmbox = lpfc_mbox_get(phba);
-	}
-	spin_unlock_irq(phba->host->host_lock);
-	return;
-}
-
 /*! lpfc_mbox_timeout
  *
  * \pre
@@ -2055,6 +2022,8 @@
 {
 	LPFC_MBOXQ_t *pmbox;
 	MAILBOX_t *mb;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring *pring;
 
 	spin_lock_irq(phba->host->host_lock);
 	if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
@@ -2062,8 +2031,6 @@
 		return;
 	}
 
-	phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
 	pmbox = phba->sli.mbox_active;
 	mb = &pmbox->mb;
 
@@ -2078,17 +2045,32 @@
 		phba->sli.sli_flag,
 		phba->sli.mbox_active);
 
-	phba->sli.mbox_active = NULL;
-	if (pmbox->mbox_cmpl) {
-		mb->mbxStatus = MBX_NOT_FINISHED;
-		spin_unlock_irq(phba->host->host_lock);
-		(pmbox->mbox_cmpl) (phba, pmbox);
-		spin_lock_irq(phba->host->host_lock);
-	}
-	phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
+	/* Setting state unknown so lpfc_sli_abort_iocb_ring
+	 * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
+	 * it to fail all oustanding SCSI IO.
+	 */
+	phba->hba_state = LPFC_STATE_UNKNOWN;
+	phba->work_hba_events &= ~WORKER_MBOX_TMO;
+	phba->fc_flag |= FC_ESTABLISH_LINK;
+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
 	spin_unlock_irq(phba->host->host_lock);
-	lpfc_mbox_abort(phba);
+
+	pring = &psli->ring[psli->fcp_ring];
+	lpfc_sli_abort_iocb_ring(phba, pring);
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+			"%d:0316 Resetting board due to mailbox timeout\n",
+			phba->brd_no);
+	/*
+	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
+	 * on oustanding mailbox commands.
+	 */
+	lpfc_offline_prep(phba);
+	lpfc_offline(phba);
+	lpfc_sli_brdrestart(phba);
+	if (lpfc_online(phba) == 0)		/* Initialize the HBA */
+		mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+	lpfc_unblock_mgmt_io(phba);
 	return;
 }
 
@@ -2320,9 +2302,7 @@
 			spin_unlock_irqrestore(phba->host->host_lock,
 					       drvr_flag);
 
-			/* Can be in interrupt context, do not sleep */
-			/* (or might be called with interrupts disabled) */
-			mdelay(1);
+			msleep(1);
 
 			spin_lock_irqsave(phba->host->host_lock, drvr_flag);
 
@@ -2430,7 +2410,7 @@
 
 	if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
 		/*
-		 * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+		 * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
 		 * can be issued if the link is not up.
 		 */
 		switch (piocb->iocb.ulpCommand) {
@@ -2444,6 +2424,8 @@
 				piocb->iocb_cmpl = NULL;
 			/*FALLTHROUGH*/
 		case CMD_CREATE_XRI_CR:
+		case CMD_CLOSE_XRI_CN:
+		case CMD_CLOSE_XRI_CX:
 			break;
 		default:
 			goto iocb_busy;
@@ -2637,11 +2619,12 @@
 int
 lpfc_sli_hba_down(struct lpfc_hba * phba)
 {
+	LIST_HEAD(completions);
 	struct lpfc_sli *psli;
 	struct lpfc_sli_ring *pring;
 	LPFC_MBOXQ_t *pmb;
-	struct lpfc_iocbq *iocb, *next_iocb;
-	IOCB_t *icmd = NULL;
+	struct lpfc_iocbq *iocb;
+	IOCB_t *cmd = NULL;
 	int i;
 	unsigned long flags = 0;
 
@@ -2649,7 +2632,6 @@
 	lpfc_hba_down_prep(phba);
 
 	spin_lock_irqsave(phba->host->host_lock, flags);
-
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
 		pring->flag |= LPFC_DEFERRED_RING_EVENT;
@@ -2658,28 +2640,25 @@
 		 * Error everything on the txq since these iocbs have not been
 		 * given to the FW yet.
 		 */
+		list_splice_init(&pring->txq, &completions);
 		pring->txq_cnt = 0;
 
-		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-			list_del_init(&iocb->list);
-			if (iocb->iocb_cmpl) {
-				icmd = &iocb->iocb;
-				icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-				icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
-				spin_unlock_irqrestore(phba->host->host_lock,
-						       flags);
-				(iocb->iocb_cmpl) (phba, iocb, iocb);
-				spin_lock_irqsave(phba->host->host_lock, flags);
-			} else
-				lpfc_sli_release_iocbq(phba, iocb);
-		}
-
-		INIT_LIST_HEAD(&(pring->txq));
-
 	}
-
 	spin_unlock_irqrestore(phba->host->host_lock, flags);
 
+	while (!list_empty(&completions)) {
+		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		cmd = &iocb->iocb;
+		list_del(&iocb->list);
+
+		if (iocb->iocb_cmpl) {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+		} else
+			lpfc_sli_release_iocbq(phba, iocb);
+	}
+
 	/* Return any active mbox cmds */
 	del_timer_sync(&psli->mbox_tmo);
 	spin_lock_irqsave(phba->host->host_lock, flags);
@@ -2768,85 +2747,138 @@
 }
 
 static void
-lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-			   struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+			struct lpfc_iocbq * rspiocb)
 {
-	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
-	/* Free the resources associated with the ELS_REQUEST64 IOCB the driver
-	 * just aborted.
-	 * In this case, context2  = cmd,  context2->next = rsp, context3 = bpl
-	 */
-	if (cmdiocb->context2) {
-		buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
+	IOCB_t *irsp;
+	uint16_t abort_iotag, abort_context;
+	struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 
-		/* Free the response IOCB before completing the abort
-		   command.  */
-		buf_ptr = NULL;
-		list_remove_head((&buf_ptr1->list), buf_ptr,
-				 struct lpfc_dmabuf, list);
-		if (buf_ptr) {
-			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-			kfree(buf_ptr);
+	abort_iocb = NULL;
+	irsp = &rspiocb->iocb;
+
+	spin_lock_irq(phba->host->host_lock);
+
+	if (irsp->ulpStatus) {
+		abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
+		abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+
+		if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
+			abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+
+		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+				"%d:0327 Cannot abort els iocb %p"
+				" with tag %x context %x\n",
+				phba->brd_no, abort_iocb,
+				abort_iotag, abort_context);
+
+		/*
+		 * make sure we have the right iocbq before taking it
+		 * off the txcmplq and try to call completion routine.
+		 */
+		if (abort_iocb &&
+		    abort_iocb->iocb.ulpContext == abort_context &&
+		    abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
+			list_del(&abort_iocb->list);
+			pring->txcmplq_cnt--;
+
+			rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
+			if (rsp_ab_iocb == NULL)
+				lpfc_sli_release_iocbq(phba, abort_iocb);
+			else {
+				abort_iocb->iocb_flag &=
+					~LPFC_DRIVER_ABORTED;
+				rsp_ab_iocb->iocb.ulpStatus =
+					IOSTAT_LOCAL_REJECT;
+				rsp_ab_iocb->iocb.un.ulpWord[4] =
+					IOERR_SLI_ABORTED;
+				spin_unlock_irq(phba->host->host_lock);
+				(abort_iocb->iocb_cmpl)
+					(phba, abort_iocb, rsp_ab_iocb);
+				spin_lock_irq(phba->host->host_lock);
+				lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
+			}
 		}
-		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-		kfree(buf_ptr1);
-	}
-
-	if (cmdiocb->context3) {
-		buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
-		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-		kfree(buf_ptr);
 	}
 
 	lpfc_sli_release_iocbq(phba, cmdiocb);
+	spin_unlock_irq(phba->host->host_lock);
 	return;
 }
 
 int
-lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
-			     struct lpfc_sli_ring * pring,
-			     struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
+			   struct lpfc_sli_ring * pring,
+			   struct lpfc_iocbq * cmdiocb)
 {
 	struct lpfc_iocbq *abtsiocbp;
 	IOCB_t *icmd = NULL;
 	IOCB_t *iabt = NULL;
+	int retval = IOCB_ERROR;
+
+	/* There are certain command types we don't want
+	 * to abort.
+	 */
+	icmd = &cmdiocb->iocb;
+	if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
+	    (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+		return 0;
+
+	/* If we're unloading, interrupts are disabled so we
+	 * need to cleanup the iocb here.
+	 */
+	if (phba->fc_flag & FC_UNLOADING)
+		goto abort_iotag_exit;
 
 	/* issue ABTS for this IOCB based on iotag */
 	abtsiocbp = lpfc_sli_get_iocbq(phba);
 	if (abtsiocbp == NULL)
 		return 0;
 
+	/* This signals the response to set the correct status
+	 * before calling the completion handler.
+	 */
+	cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
+
 	iabt = &abtsiocbp->iocb;
-	icmd = &cmdiocb->iocb;
-	switch (icmd->ulpCommand) {
-	case CMD_ELS_REQUEST64_CR:
-		/* Even though we abort the ELS command, the firmware may access
-		 * the BPL or other resources before it processes our
-		 * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
-		 * resources till the actual abort request completes.
-		 */
-		abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
-		abtsiocbp->context2 = cmdiocb->context2;
-		abtsiocbp->context3 = cmdiocb->context3;
-		cmdiocb->context2 = NULL;
-		cmdiocb->context3 = NULL;
-		abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
-		break;
-	default:
-		lpfc_sli_release_iocbq(phba, abtsiocbp);
-		return 0;
-	}
-
-	iabt->un.amxri.abortType = ABORT_TYPE_ABTS;
-	iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32;
-
+	iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
+	iabt->un.acxri.abortContextTag = icmd->ulpContext;
+	iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
 	iabt->ulpLe = 1;
-	iabt->ulpClass = CLASS3;
-	iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
+	iabt->ulpClass = icmd->ulpClass;
 
-	if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
-		lpfc_sli_release_iocbq(phba, abtsiocbp);
-		return 0;
+	if (phba->hba_state >= LPFC_LINK_UP)
+		iabt->ulpCommand = CMD_ABORT_XRI_CN;
+	else
+		iabt->ulpCommand = CMD_CLOSE_XRI_CN;
+
+	abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
+
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"%d:0339 Abort xri x%x, original iotag x%x, abort "
+			"cmd iotag x%x\n",
+			phba->brd_no, iabt->un.acxri.abortContextTag,
+			iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+	retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+
+abort_iotag_exit:
+
+	/* If we could not issue an abort dequeue the iocb and handle
+	 * the completion here.
+	 */
+	if (retval == IOCB_ERROR) {
+		list_del(&cmdiocb->list);
+		pring->txcmplq_cnt--;
+
+		if (cmdiocb->iocb_cmpl) {
+			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			spin_unlock_irq(phba->host->host_lock);
+			(cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
+			spin_lock_irq(phba->host->host_lock);
+		} else
+			lpfc_sli_release_iocbq(phba, cmdiocb);
 	}
 
 	return 1;
@@ -2918,9 +2950,11 @@
 lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 			   struct lpfc_iocbq * rspiocb)
 {
-	spin_lock_irq(phba->host->host_lock);
+	unsigned long iflags;
+
+	spin_lock_irqsave(phba->host->host_lock, iflags);
 	lpfc_sli_release_iocbq(phba, cmdiocb);
-	spin_unlock_irq(phba->host->host_lock);
+	spin_unlock_irqrestore(phba->host->host_lock, iflags);
 	return;
 }
 
@@ -3043,22 +3077,22 @@
 				timeout_req);
 		spin_lock_irq(phba->host->host_lock);
 
-		if (timeleft == 0) {
+		if (piocb->iocb_flag & LPFC_IO_WAKE) {
+			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+					"%d:0331 IOCB wake signaled\n",
+					phba->brd_no);
+		} else if (timeleft == 0) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"%d:0338 IOCB wait timeout error - no "
 					"wake response Data x%x\n",
 					phba->brd_no, timeout);
 			retval = IOCB_TIMEDOUT;
-		} else if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
+		} else {
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"%d:0330 IOCB wake NOT set, "
 					"Data x%x x%lx\n", phba->brd_no,
 					timeout, (timeleft / jiffies));
 			retval = IOCB_TIMEDOUT;
-		} else {
-			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-					"%d:0331 IOCB wake signaled\n",
-					phba->brd_no);
 		}
 	} else {
 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3087,8 +3121,6 @@
 			 uint32_t timeout)
 {
 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
-	DECLARE_WAITQUEUE(wq_entry, current);
-	uint32_t timeleft = 0;
 	int retval;
 
 	/* The caller must leave context1 empty. */
@@ -3101,27 +3133,25 @@
 	/* setup context field to pass wait_queue pointer to wake function  */
 	pmboxq->context1 = &done_q;
 
-	/* start to sleep before we wait, to avoid races */
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&done_q, &wq_entry);
-
 	/* now issue the command */
 	retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 
 	if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
-		timeleft = schedule_timeout(timeout * HZ);
+		wait_event_interruptible_timeout(done_q,
+				pmboxq->mbox_flag & LPFC_MBX_WAKE,
+				timeout * HZ);
+
 		pmboxq->context1 = NULL;
-		/* if schedule_timeout returns 0, we timed out and were not
-		   woken up */
-		if ((timeleft == 0) || signal_pending(current))
-			retval = MBX_TIMEOUT;
-		else
+		/*
+		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
+		 * else do not free the resources.
+		 */
+		if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
 			retval = MBX_SUCCESS;
+		else
+			retval = MBX_TIMEOUT;
 	}
 
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&done_q, &wq_entry);
 	return retval;
 }
 
@@ -3184,6 +3214,11 @@
 	 */
 	spin_lock(phba->host->host_lock);
 	ha_copy = readl(phba->HAregaddr);
+	/* If somebody is waiting to handle an eratt don't process it
+	 * here.  The brdkill function will do this.
+	 */
+	if (phba->fc_flag & FC_IGNORE_ERATT)
+		ha_copy &= ~HA_ERATT;
 	writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
 	readl(phba->HAregaddr); /* flush */
 	spin_unlock(phba->host->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a435499..41c38d3 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -39,9 +39,10 @@
 	IOCB_t iocb;		/* IOCB cmd */
 	uint8_t retry;		/* retry counter for IOCB cmd - if needed */
 	uint8_t iocb_flag;
-#define LPFC_IO_LIBDFC	1	/* libdfc iocb */
-#define LPFC_IO_WAKE	2	/* High Priority Queue signal flag */
-#define LPFC_IO_FCP	4	/* FCP command -- iocbq in scsi_buf */
+#define LPFC_IO_LIBDFC		1	/* libdfc iocb */
+#define LPFC_IO_WAKE		2	/* High Priority Queue signal flag */
+#define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
+#define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
 
 	uint8_t abort_count;
 	uint8_t rsvd2;
@@ -67,6 +68,8 @@
 #define IOCB_ERROR          2
 #define IOCB_TIMEDOUT       3
 
+#define LPFC_MBX_WAKE	1
+
 typedef struct lpfcMboxq {
 	/* MBOXQs are used in single linked lists */
 	struct list_head list;	/* ptr to next mailbox command */
@@ -75,6 +78,7 @@
 	void *context2;		/* caller context information */
 
 	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
+	uint8_t mbox_flag;
 
 } LPFC_MBOXQ_t;
 
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index a61ef3d1..92a9107 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,12 +18,12 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.11"
+#define LPFC_DRIVER_VERSION "8.1.12"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 		LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2006 Emulex.  All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
 
 #define DFC_API_VERSION "0.0.0"
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 7fc6e06..3cce75d 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1754,7 +1754,8 @@
 	for (counter = 0; counter < 10000; counter++) {
 		if (!mbox->m_in.busy)
 			return 0;
-		udelay(100); yield();
+		udelay(100);
+		cond_resched();
 	}
 	return -1;		/* give up after 1 second */
 }
@@ -3177,7 +3178,10 @@
 
 	return len;
 }
-
+#else
+static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+}
 #endif
 
 
@@ -4342,7 +4346,7 @@
 	return 0;
 }
 
-
+#ifdef CONFIG_PROC_FS
 /**
  * mega_adapinq()
  * @adapter - pointer to our soft state
@@ -4447,7 +4451,7 @@
 
 	return rval;
 }
-
+#endif
 
 /**
  * mega_internal_command()
@@ -4965,7 +4969,6 @@
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	adapter_t *adapter = (adapter_t *)host->hostdata;
-	char	buf[12] = { 0 };
 
 	scsi_remove_host(host);
 
@@ -5011,8 +5014,11 @@
 		remove_proc_entry("raiddrives-30-39",
 				adapter->controller_proc_dir_entry);
 #endif
-		sprintf(buf, "hba%d", adapter->host->host_no);
-		remove_proc_entry(buf, mega_proc_dir_entry);
+		{
+			char	buf[12] = { 0 };
+			sprintf(buf, "hba%d", adapter->host->host_no);
+			remove_proc_entry(buf, mega_proc_dir_entry);
+		}
 	}
 #endif
 
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index c6e7464..ee70bd4 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -1002,7 +1002,6 @@
 static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
 static int megaraid_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int []);
-static int mega_print_inquiry(char *, char *);
 
 static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
 			      u32 *buffer, u32 *length);
@@ -1024,6 +1023,7 @@
 static int mega_is_bios_enabled (adapter_t *);
 
 #ifdef CONFIG_PROC_FS
+static int mega_print_inquiry(char *, char *);
 static void mega_create_proc_entry(int, struct proc_dir_entry *);
 static int proc_read_config(char *, char **, off_t, int, int *, void *);
 static int proc_read_stat(char *, char **, off_t, int, int *, void *);
@@ -1040,10 +1040,10 @@
 static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv(adapter_t *, char *, int, int);
-#endif
 
 static int mega_adapinq(adapter_t *, dma_addr_t);
 static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
+#endif
 
 static int mega_support_ext_cdb(adapter_t *);
 static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *,
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index f33a678..e075a52 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -60,7 +60,7 @@
 EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
 
 static int majorno;
-static uint32_t drvr_ver	= 0x02200206;
+static uint32_t drvr_ver	= 0x02200207;
 
 static int adapters_count_g;
 static struct list_head adapters_list_g;
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index cf3666d..e64d1a1 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -185,7 +185,7 @@
  * Driver is too messy, we need a few prototypes...
  */
 static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id);
+static void mesh_interrupt(struct mesh_state *ms);
 static void cmd_complete(struct mesh_state *ms);
 static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
 static void halt_dma(struct mesh_state *ms);
@@ -466,7 +466,7 @@
 				dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
 				     MKWORD(mr->interrupt, mr->exception,
 					    mr->error, mr->fifo_count));
-				mesh_interrupt(0, (void *)ms);
+				mesh_interrupt(ms);
 				if (ms->phase != arbitrating)
 					return;
 			}
@@ -504,7 +504,7 @@
 		dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
 		     MKWORD(mr->interrupt, mr->exception,
 			    mr->error, mr->fifo_count));
-		mesh_interrupt(0, (void *)ms);
+		mesh_interrupt(ms);
 		if (ms->phase != arbitrating)
 			return;
 		dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1018,10 +1018,11 @@
 static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
 {
 	unsigned long flags;
-	struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+	struct mesh_state *ms = dev_id;
+	struct Scsi_Host *dev = ms->host;
 	
 	spin_lock_irqsave(dev->host_lock, flags);
-	mesh_interrupt(irq, dev_id);
+	mesh_interrupt(ms);
 	spin_unlock_irqrestore(dev->host_lock, flags);
 	return IRQ_HANDLED;
 }
@@ -1661,9 +1662,8 @@
  * handler (do_mesh_interrupt) or by other functions in
  * exceptional circumstances
  */
-static void mesh_interrupt(int irq, void *dev_id)
+static void mesh_interrupt(struct mesh_state *ms)
 {
-	struct mesh_state *ms = (struct mesh_state *) dev_id;
 	volatile struct mesh_regs __iomem *mr = ms->mesh;
 	int intr;
 
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6777e8a..54d8bdf 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4293,7 +4293,7 @@
 	ha->devnum = devnum;	/* specifies microcode load address */
 
 #ifdef QLA_64BIT_PTR
-	if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
+	if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
 		if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
 			printk(KERN_WARNING "scsi(%li): Unable to set a "
 			       "suitable DMA mask - aborting\n", ha->host_no);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 3e296ab..2a45aec 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -13,7 +13,6 @@
 
 #ifdef CONFIG_SPARC
 #include <asm/prom.h>
-#include <asm/pbm.h>
 #endif
 
 /* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
@@ -130,18 +129,17 @@
 int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
-	uint16_t w, mwi;
+	int ret;
+	uint16_t w;
 	uint32_t d;
 	unsigned long flags;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	pci_set_master(ha->pdev);
-	mwi = 0;
-	if (pci_set_mwi(ha->pdev))
-		mwi = PCI_COMMAND_INVALIDATE;
+	ret = pci_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-	w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
 	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
 	/* Reset expansion ROM address decode enable */
@@ -166,22 +164,22 @@
 int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
-	uint16_t	w, mwi;
+	int		ret;
+	uint16_t	w;
 	uint32_t	d;
 	unsigned long   flags = 0;
 	uint32_t	cnt;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	pci_set_master(ha->pdev);
-	mwi = 0;
-	if (pci_set_mwi(ha->pdev))
-		mwi = PCI_COMMAND_INVALIDATE;
+	ret = pci_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-	w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
 
 	if (IS_QLA2322(ha) || IS_QLA6322(ha))
 		w &= ~PCI_COMMAND_INTX_DISABLE;
+	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
 	/*
 	 * If this is a 2300 card and not 2312, reset the
@@ -210,7 +208,7 @@
 		ha->fb_rev = RD_FB_CMD_REG(ha, reg);
 
 		if (ha->fb_rev == FPM_2300)
-			w &= ~PCI_COMMAND_INVALIDATE;
+			pci_clear_mwi(ha->pdev);
 
 		/* Deselect FPM registers. */
 		WRT_REG_WORD(&reg->ctrl_status, 0x0);
@@ -227,7 +225,6 @@
 
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	}
-	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
 	pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
@@ -253,19 +250,18 @@
 int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
-	uint16_t w, mwi;
+	int ret;
+	uint16_t w;
 	uint32_t d;
 	unsigned long flags = 0;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	int pcix_cmd_reg, pcie_dctl_reg;
 
 	pci_set_master(ha->pdev);
-	mwi = 0;
-	if (pci_set_mwi(ha->pdev))
-		mwi = PCI_COMMAND_INVALIDATE;
+	ret = pci_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-	w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
 	w &= ~PCI_COMMAND_INTX_DISABLE;
 	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
@@ -1400,9 +1396,8 @@
 {
 #ifdef CONFIG_SPARC
 	struct pci_dev *pdev = ha->pdev;
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct device_node *dp = pcp->prom_node;
-	u8 *val;
+	struct device_node *dp = pci_device_to_OF_node(pdev);
+	const u8 *val;
 	int len;
 
 	val = of_get_property(dp, "port-wwn", &len);
@@ -3373,9 +3368,8 @@
 {
 #ifdef CONFIG_SPARC
 	struct pci_dev *pdev = ha->pdev;
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct device_node *dp = pcp->prom_node;
-	u8 *val;
+	struct device_node *dp = pci_device_to_OF_node(pdev);
+	const u8 *val;
 	int len;
 
 	val = of_get_property(dp, "port-wwn", &len);
@@ -3931,6 +3925,8 @@
 
 	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
 		return;
+	if (!ha->fw_major_version)
+		return;
 
 	ret = qla2x00_stop_firmware(ha);
 	for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d488561..ca46346 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1726,6 +1726,17 @@
 	qla_printk(KERN_WARNING, ha,
 	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
+
+	if (!IS_QLA24XX(ha))
+		goto skip_msi;
+
+	ret = pci_enable_msi(ha->pdev);
+	if (!ret) {
+		DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+		ha->flags.msi_enabled = 1;
+	}
+skip_msi:
+
 	ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
 	    IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
 	if (!ret) {
@@ -1746,6 +1757,8 @@
 
 	if (ha->flags.msix_enabled)
 		qla24xx_disable_msix(ha);
-	else if (ha->flags.inta_enabled)
+	else if (ha->flags.inta_enabled) {
 		free_irq(ha->host->irq, ha);
+		pci_disable_msi(ha->pdev);
+	}
 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b78919a..dd076da 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -36,7 +36,7 @@
 MODULE_PARM_DESC(ql2xlogintimeout,
 		"Login timeout value in seconds.");
 
-int qlport_down_retry = 30;
+int qlport_down_retry;
 module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(qlport_down_retry,
 		"Maximum number of command retries to a port that returns "
@@ -1577,9 +1577,7 @@
 		goto probe_failed;
 	}
 
-	if (qla2x00_initialize_adapter(ha) &&
-	    !(ha->device_flags & DFLG_NO_CABLE)) {
-
+	if (qla2x00_initialize_adapter(ha)) {
 		qla_printk(KERN_WARNING, ha,
 		    "Failed to initialize adapter\n");
 
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index dc85495..c375a4e 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.07-k6"
+#define QLA2XXX_VERSION      "8.01.07-k7"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	1
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 7b4e077..6437d024 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -8,6 +8,8 @@
 #include "ql4_def.h"
 #include <scsi/scsi_dbg.h>
 
+#if 0
+
 static void qla4xxx_print_srb_info(struct srb * srb)
 {
 	printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
@@ -195,3 +197,5 @@
 	if (cnt % 16)
 		printk(KERN_DEBUG "\n");
 }
+
+#endif  /*  0  */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index e021eb5..5b00cb0 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -43,8 +43,6 @@
 			    uint16_t *tcp_source_port_num,
 			    uint16_t *connection_id);
 
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
-				     uint32_t fw_ddb_index);
 int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
 			  dma_addr_t fw_ddb_entry_dma);
 
@@ -55,18 +53,11 @@
 struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
 int qla4xxx_add_sess(struct ddb_entry *);
 void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
-				   uint16_t fw_ddb_index,
-				   uint16_t connection_id,
-				   uint16_t option);
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
-				 uint16_t fw_ddb_index);
 int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
 int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
 void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
 				       uint32_t intr_status);
 int qla4xxx_init_rings(struct scsi_qla_host * ha);
-void qla4xxx_dump_buffer(void *b, uint32_t size);
 struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
 void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
 int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index b907b06..6365df2 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -7,9 +7,8 @@
 
 #include "ql4_def.h"
 
-/*
- * QLogic ISP4xxx Hardware Support Function Prototypes.
- */
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+					    uint32_t fw_ddb_index);
 
 static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
 {
@@ -48,7 +47,8 @@
  * This routine deallocates and unlinks the specified ddb_entry from the
  * adapter's
  **/
-void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
+static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+			     struct ddb_entry *ddb_entry)
 {
 	/* Remove device entry from list */
 	list_del_init(&ddb_entry->list);
@@ -370,9 +370,9 @@
  * must be initialized prior to	calling this routine
  *
  **/
-int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
-			     struct ddb_entry *ddb_entry,
-			     uint32_t fw_ddb_index)
+static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+				    struct ddb_entry *ddb_entry,
+				    uint32_t fw_ddb_index)
 {
 	struct dev_db_entry *fw_ddb_entry = NULL;
 	dma_addr_t fw_ddb_entry_dma;
@@ -450,8 +450,8 @@
  * This routine allocates a ddb_entry, ititializes some values, and
  * inserts it into the ddb list.
  **/
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
-				     uint32_t fw_ddb_index)
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+					    uint32_t fw_ddb_index)
 {
 	struct ddb_entry *ddb_entry;
 
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index d41ce38..a216a17 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -19,8 +19,8 @@
  *	- advances the request_in pointer
  *	- checks for queue full
  **/
-int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
-			struct queue_entry **queue_entry)
+static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+			       struct queue_entry **queue_entry)
 {
 	uint16_t request_in;
 	uint8_t status = QLA_SUCCESS;
@@ -62,8 +62,8 @@
  *
  * This routine issues a marker IOCB.
  **/
-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
-			     struct ddb_entry *ddb_entry, int lun)
+static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+				    struct ddb_entry *ddb_entry, int lun)
 {
 	struct marker_entry *marker_entry;
 	unsigned long flags = 0;
@@ -96,7 +96,7 @@
 	return status;
 }
 
-struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
 	struct scsi_qla_host *ha)
 {
 	struct continuation_t1_entry *cont_entry;
@@ -120,7 +120,7 @@
 	return cont_entry;
 }
 
-uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+static uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
 {
 	uint16_t iocbs;
 
@@ -133,9 +133,9 @@
 	return iocbs;
 }
 
-void qla4xxx_build_scsi_iocbs(struct srb *srb,
-			      struct command_t3_entry *cmd_entry,
-			      uint16_t tot_dsds)
+static void qla4xxx_build_scsi_iocbs(struct srb *srb,
+				     struct command_t3_entry *cmd_entry,
+				     uint16_t tot_dsds)
 {
 	struct scsi_qla_host *ha;
 	uint16_t avail_dsds;
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 7f28657..f116ff9 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -20,9 +20,9 @@
  * If outCount is 0, this routine completes successfully WITHOUT waiting
  * for the mailbox command to complete.
  **/
-int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
-			    uint8_t outCount, uint32_t *mbx_cmd,
-			    uint32_t *mbx_sts)
+static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+				   uint8_t outCount, uint32_t *mbx_cmd,
+				   uint32_t *mbx_sts)
 {
 	int status = QLA_ERROR;
 	uint8_t i;
@@ -170,6 +170,8 @@
 }
 
 
+#if 0
+
 /**
  * qla4xxx_issue_iocb - issue mailbox iocb command
  * @ha: adapter state pointer.
@@ -243,6 +245,8 @@
 	return QLA_SUCCESS;
 }
 
+#endif  /*  0  */
+
 /**
  * qla4xxx_initialize_fw_cb - initializes firmware control block.
  * @ha: Pointer to host adapter structure.
@@ -570,6 +574,7 @@
 	return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
 }
 
+#if 0
 int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
 				    uint16_t fw_ddb_index)
 {
@@ -594,6 +599,7 @@
 
 		return status;
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_get_crash_record - retrieves crash record.
@@ -649,6 +655,7 @@
 				  crash_record, crash_record_dma);
 }
 
+#if 0
 /**
  * qla4xxx_get_conn_event_log - retrieves connection event log
  * @ha: Pointer to host adapter structure.
@@ -738,6 +745,7 @@
 		dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
 				  event_log_dma);
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_reset_lun - issues LUN Reset
@@ -834,7 +842,8 @@
 	return QLA_SUCCESS;
 }
 
-int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
+static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+				   dma_addr_t dma_addr)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -855,7 +864,7 @@
 	return QLA_SUCCESS;
 }
 
-int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 0bfddf8..da21f5f 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -14,7 +14,7 @@
 /*
  * Driver version
  */
-char qla4xxx_version_str[40];
+static char qla4xxx_version_str[40];
 
 /*
  * SRB allocation cache
@@ -45,8 +45,7 @@
 /*
  * SCSI host template entry points
  */
-
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
 
 /*
  * iSCSI template entry points
@@ -1352,7 +1351,7 @@
  * At exit, the @ha's flags.enable_64bit_addressing set to indicated
  * supported addressing method.
  */
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
 {
 	int retval;
 
@@ -1627,7 +1626,7 @@
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
 
-struct pci_driver qla4xxx_pci_driver = {
+static struct pci_driver qla4xxx_pci_driver = {
 	.name		= DRIVER_NAME,
 	.id_table	= qla4xxx_pci_tbl,
 	.probe		= qla4xxx_probe_adapter,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 3963e70..e8350c5 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -38,7 +38,6 @@
 #include "scsi_logging.h"
 
 #define SENSE_TIMEOUT		(10*HZ)
-#define START_UNIT_TIMEOUT	(30*HZ)
 
 /*
  * These should *probably* be handled by the host itself.
@@ -936,7 +935,7 @@
 
 		for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
 			rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
-						START_UNIT_TIMEOUT, 0);
+						scmd->device->timeout, 0);
 
 		if (rtn == SUCCESS)
 			return 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 61fbcdcb..1f5a07b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -173,7 +173,7 @@
  * @retries:	number of times to retry request
  * @flags:	or into request flags;
  *
- * returns the req->errors value which is the the scsi_cmnd result
+ * returns the req->errors value which is the scsi_cmnd result
  * field.
  **/
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 14c4f06..b4d1ece 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1718,31 +1718,12 @@
 	struct fc_rport *rport =
 		container_of(work, struct fc_rport, stgt_delete_work);
 	struct Scsi_Host *shost = rport_to_shost(rport);
-	unsigned long flags;
 	struct fc_internal *i = to_fc_internal(shost->transportt);
 
-	/*
-	 * Involve the LLDD if possible. All io on the rport is to
-	 * be terminated, either as part of the dev_loss_tmo callback
-	 * processing, or via the terminate_rport_io function.
-	 */
-	if (i->f->dev_loss_tmo_callbk)
-		i->f->dev_loss_tmo_callbk(rport);
-	else if (i->f->terminate_rport_io)
+	/* Involve the LLDD if possible to terminate all io on the rport. */
+	if (i->f->terminate_rport_io)
 		i->f->terminate_rport_io(rport);
 
-	spin_lock_irqsave(shost->host_lock, flags);
-	if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
-		spin_unlock_irqrestore(shost->host_lock, flags);
-		if (!cancel_delayed_work(&rport->fail_io_work))
-			fc_flush_devloss(shost);
-		if (!cancel_delayed_work(&rport->dev_loss_work))
-			fc_flush_devloss(shost);
-		spin_lock_irqsave(shost->host_lock, flags);
-		rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
-	}
-	spin_unlock_irqrestore(shost->host_lock, flags);
-
 	scsi_remove_target(&rport->dev);
 }
 
@@ -1760,6 +1741,7 @@
 	struct device *dev = &rport->dev;
 	struct Scsi_Host *shost = rport_to_shost(rport);
 	struct fc_internal *i = to_fc_internal(shost->transportt);
+	unsigned long flags;
 
 	/*
 	 * if a scan is pending, flush the SCSI Host work_q so that 
@@ -1768,13 +1750,37 @@
 	if (rport->flags & FC_RPORT_SCAN_PENDING)
 		scsi_flush_work(shost);
 
+	/* involve the LLDD to terminate all pending i/o */
+	if (i->f->terminate_rport_io)
+		i->f->terminate_rport_io(rport);
+
+	/*
+	 * Cancel any outstanding timers. These should really exist
+	 * only when rmmod'ing the LLDD and we're asking for
+	 * immediate termination of the rports
+	 */
+	spin_lock_irqsave(shost->host_lock, flags);
+	if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		if (!cancel_delayed_work(&rport->fail_io_work))
+			fc_flush_devloss(shost);
+		if (!cancel_delayed_work(&rport->dev_loss_work))
+			fc_flush_devloss(shost);
+		spin_lock_irqsave(shost->host_lock, flags);
+		rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
 	/* Delete SCSI target and sdevs */
 	if (rport->scsi_target_id != -1)
 		fc_starget_delete(&rport->stgt_delete_work);
-	else if (i->f->dev_loss_tmo_callbk)
+
+	/*
+	 * Notify the driver that the rport is now dead. The LLDD will
+	 * also guarantee that any communication to the rport is terminated
+	 */
+	if (i->f->dev_loss_tmo_callbk)
 		i->f->dev_loss_tmo_callbk(rport);
-	else if (i->f->terminate_rport_io)
-		i->f->terminate_rport_io(rport);
 
 	transport_remove_device(dev);
 	device_del(dev);
@@ -1963,8 +1969,6 @@
 			}
 
 			if (match) {
-				struct delayed_work *work =
-							&rport->dev_loss_work;
 
 				memcpy(&rport->node_name, &ids->node_name,
 					sizeof(rport->node_name));
@@ -1982,46 +1986,61 @@
 						fci->f->dd_fcrport_size);
 
 				/*
-				 * If we were blocked, we were a target.
-				 * If no longer a target, we leave the timer
-				 * running in case the port changes roles
-				 * prior to the timer expiring. If the timer
-				 * fires, the target will be torn down.
+				 * If we were not a target, cancel the
+				 * io terminate and rport timers, and
+				 * we're done.
+				 *
+				 * If we were a target, but our new role
+				 * doesn't indicate a target, leave the
+				 * timers running expecting the role to
+				 * change as the target fully logs in. If
+				 * it doesn't, the target will be torn down.
+				 *
+				 * If we were a target, and our role shows
+				 * we're still a target, cancel the timers
+				 * and kick off a scan.
 				 */
-				if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))
+
+				/* was a target, not in roles */
+				if ((rport->scsi_target_id != -1) &&
+				    (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
 					return rport;
 
-				/* restart the target */
-
 				/*
-				 * Stop the target timers first. Take no action
-				 * on the del_timer failure as the state
-				 * machine state change will validate the
-				 * transaction.
+				 * Stop the fail io and dev_loss timers.
+				 * If they flush, the port_state will
+				 * be checked and will NOOP the function.
 				 */
 				if (!cancel_delayed_work(&rport->fail_io_work))
 					fc_flush_devloss(shost);
-				if (!cancel_delayed_work(work))
+				if (!cancel_delayed_work(&rport->dev_loss_work))
 					fc_flush_devloss(shost);
 
 				spin_lock_irqsave(shost->host_lock, flags);
 
 				rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
-				/* initiate a scan of the target */
-				rport->flags |= FC_RPORT_SCAN_PENDING;
-				scsi_queue_work(shost, &rport->scan_work);
-
-				spin_unlock_irqrestore(shost->host_lock, flags);
-
-				scsi_target_unblock(&rport->dev);
+				/* if target, initiate a scan */
+				if (rport->scsi_target_id != -1) {
+					rport->flags |= FC_RPORT_SCAN_PENDING;
+					scsi_queue_work(shost,
+							&rport->scan_work);
+					spin_unlock_irqrestore(shost->host_lock,
+							flags);
+					scsi_target_unblock(&rport->dev);
+				} else
+					spin_unlock_irqrestore(shost->host_lock,
+							flags);
 
 				return rport;
 			}
 		}
 	}
 
-	/* Search the bindings array */
+	/*
+	 * Search the bindings array
+	 * Note: if never a FCP target, you won't be on this list
+	 */
 	if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
 
 		/* search for a matching consistent binding */
@@ -2158,15 +2177,24 @@
 
 	spin_lock_irqsave(shost->host_lock, flags);
 
-	/* If no scsi target id mapping, delete it */
-	if (rport->scsi_target_id == -1) {
-		list_del(&rport->peers);
-		rport->port_state = FC_PORTSTATE_DELETED;
-		fc_queue_work(shost, &rport->rport_delete_work);
+	if (rport->port_state != FC_PORTSTATE_ONLINE) {
 		spin_unlock_irqrestore(shost->host_lock, flags);
 		return;
 	}
 
+	/*
+	 * In the past, we if this was not an FCP-Target, we would
+	 * unconditionally just jump to deleting the rport.
+	 * However, rports can be used as node containers by the LLDD,
+	 * and its not appropriate to just terminate the rport at the
+	 * first sign of a loss in connectivity. The LLDD may want to
+	 * send ELS traffic to re-validate the login. If the rport is
+	 * immediately deleted, it makes it inappropriate for a node
+	 * container.
+	 * So... we now unconditionally wait dev_loss_tmo before
+	 * destroying an rport.
+	 */
+
 	rport->port_state = FC_PORTSTATE_BLOCKED;
 
 	rport->flags |= FC_RPORT_DEVLOSS_PENDING;
@@ -2263,11 +2291,11 @@
 EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that
- *                       was a SCSI target (thus was blocked), and failed
- *                       to return in the alloted time.
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
+ * 			which we blocked, and has now failed to return
+ * 			in the allotted time.
  * 
- * @work:	rport target that failed to reappear in the alloted time.
+ * @work:	rport target that failed to reappear in the allotted time.
  **/
 static void
 fc_timeout_deleted_rport(struct work_struct *work)
@@ -2283,10 +2311,12 @@
 	rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
 	/*
-	 * If the port is ONLINE, then it came back. Validate it's still an
-	 * FCP target. If not, tear down the scsi_target on it.
+	 * If the port is ONLINE, then it came back. If it was a SCSI
+	 * target, validate it still is. If not, tear down the
+	 * scsi_target on it.
 	 */
 	if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
+	    (rport->scsi_target_id != -1) &&
 	    !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
 		dev_printk(KERN_ERR, &rport->dev,
 			"blocked FC remote port time out: no longer"
@@ -2297,18 +2327,24 @@
 		return;
 	}
 
+	/* NOOP state - we're flushing workq's */
 	if (rport->port_state != FC_PORTSTATE_BLOCKED) {
 		spin_unlock_irqrestore(shost->host_lock, flags);
 		dev_printk(KERN_ERR, &rport->dev,
-			"blocked FC remote port time out: leaving target alone\n");
+			"blocked FC remote port time out: leaving"
+			" rport%s alone\n",
+			(rport->scsi_target_id != -1) ?  " and starget" : "");
 		return;
 	}
 
-	if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
+	if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) ||
+	    (rport->scsi_target_id == -1)) {
 		list_del(&rport->peers);
 		rport->port_state = FC_PORTSTATE_DELETED;
 		dev_printk(KERN_ERR, &rport->dev,
-			"blocked FC remote port time out: removing target\n");
+			"blocked FC remote port time out: removing"
+			" rport%s\n",
+			(rport->scsi_target_id != -1) ?  " and starget" : "");
 		fc_queue_work(shost, &rport->rport_delete_work);
 		spin_unlock_irqrestore(shost->host_lock, flags);
 		return;
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 3158949..e7b85e8 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -351,6 +351,27 @@
  * (DCBs, SRBs, Queueing)
  *
  **********************************************************************/
+static void inline dc390_start_segment(struct dc390_srb* pSRB)
+{
+	struct scatterlist *psgl = pSRB->pSegmentList;
+
+	/* start new sg segment */
+	pSRB->SGBusAddr = sg_dma_address(psgl);
+	pSRB->SGToBeXferLen = sg_dma_len(psgl);
+}
+
+static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue)
+{
+	unsigned long xfer = pSRB->SGToBeXferLen - residue;
+
+	/* xfer more bytes transferred */
+	pSRB->SGBusAddr += xfer;
+	pSRB->TotalXferredLen += xfer;
+	pSRB->SGToBeXferLen = residue;
+
+	return xfer;
+}
+
 static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
 {
    struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
@@ -625,70 +646,6 @@
     return 0;
 }
 
-//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
-#define DMA_INT 0
-
-#if DMA_INT
-/* This is similar to AM53C974.c ... */
-static u8 
-dc390_dma_intr (struct dc390_acb* pACB)
-{
-  struct dc390_srb* pSRB;
-  u8 dstate;
-  DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);
-  
-  DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate));
-  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-	{ printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
-	  pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));});
-
-  dstate = DC390_read8 (DMA_Status); 
-
-  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
-  else pSRB  = pACB->pActiveDCB->pActiveSRB;
-  
-  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
-    {
-	printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
-	return dstate;
-    }
-  if (dstate & DMA_XFER_DONE)
-    {
-	u32 residual, xferCnt; int ctr = 6000000;
-	if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
-	  {
-	    do
-	      {
-		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n"));
-		dstate = DC390_read8 (DMA_Status);
-		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
-		  DC390_read8 (CtcReg_High) << 16;
-		residual += DC390_read8 (Current_Fifo) & 0x1f;
-	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    /* residual =  ... */
-	  }
-	else
-	    residual = 0;
-	
-	/* ??? */
-	
-	xferCnt = pSRB->SGToBeXferLen - residual;
-	pSRB->SGBusAddr += xferCnt;
-	pSRB->TotalXferredLen += xferCnt;
-	pSRB->SGToBeXferLen = residual;
-# ifdef DC390_DEBUG0
-	printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
-		(unsigned int)residual, (unsigned int)xferCnt);
-# endif
-	
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    }
-  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-  return dstate;
-}
-#endif
-
 
 static void __inline__
 dc390_InvalidCmd(struct dc390_acb* pACB)
@@ -708,9 +665,6 @@
     u8  phase;
     void   (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
     u8  istate, istatus;
-#if DMA_INT
-    u8  dstatus;
-#endif
 
     sstatus = DC390_read8 (Scsi_Status);
     if( !(sstatus & INTERRUPT) )
@@ -718,22 +672,9 @@
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
 
-#if DMA_INT
-    spin_lock_irq(pACB->pScsiHost->host_lock);
-    dstatus = dc390_dma_intr (pACB);
-    spin_unlock_irq(pACB->pScsiHost->host_lock);
-
-    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
-    if (! (dstatus & SCSI_INTERRUPT))
-      {
-	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
-	return IRQ_NONE;
-      }
-#else
     //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     //dstatus = DC390_read8 (DMA_Status);
     //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-#endif
 
     spin_lock_irq(pACB->pScsiHost->host_lock);
 
@@ -821,11 +762,10 @@
 }
 
 static void
-dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus;
-    struct scatterlist *psgl;
-    u32    ResidCnt, xferCnt;
+    u32  ResidCnt;
     u8   dstate = 0;
 
     sstatus = *psstatus;
@@ -856,42 +796,35 @@
 	    if( pSRB->SGIndex < pSRB->SGcount )
 	    {
 		pSRB->pSegmentList++;
-		psgl = pSRB->pSegmentList;
 
-		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+		dc390_start_segment(pSRB);
 	    }
 	    else
 		pSRB->SGToBeXferLen = 0;
 	}
 	else
 	{
-	    ResidCnt  = (u32) DC390_read8 (Current_Fifo) & 0x1f;
-	    ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;
-	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; 
-	    ResidCnt += (u32) DC390_read8 (CtcReg_Low);
+	    ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) +
+		    (((u32) DC390_read8 (CtcReg_High) << 16) |
+		     ((u32) DC390_read8 (CtcReg_Mid) << 8) |
+		     (u32) DC390_read8 (CtcReg_Low));
 
-	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGBusAddr += xferCnt;
-	    pSRB->TotalXferredLen += xferCnt;
-	    pSRB->SGToBeXferLen = ResidCnt;
+	    dc390_advance_segment(pSRB, ResidCnt);
 	}
     }
     if ((*psstatus & 7) != SCSI_DATA_OUT)
     {
-	    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD);
 	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     }	    
 }
 
 static void
-dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus, residual, bval;
-    struct scatterlist *psgl;
-    u32    ResidCnt, i;
+    u32  ResidCnt, i;
     unsigned long   xferCnt;
-    u8      *ptr;
 
     sstatus = *psstatus;
 
@@ -922,19 +855,17 @@
 	    DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16)	\
 		+ ((unsigned long) DC390_read8 (CtcReg_Mid) << 8)		\
 		+ ((unsigned long) DC390_read8 (CtcReg_Low)));
-	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen));
+	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen));
 
-	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
 
 	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
 	    pSRB->SGIndex++;
 	    if( pSRB->SGIndex < pSRB->SGcount )
 	    {
 		pSRB->pSegmentList++;
-		psgl = pSRB->pSegmentList;
 
-		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+		dc390_start_segment(pSRB);
 	    }
 	    else
 		pSRB->SGToBeXferLen = 0;
@@ -973,47 +904,45 @@
 	    }
 	    /* It seems a DMA Blast abort isn't that bad ... */
 	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
-	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
+	    dc390_laststatus &= ~0xff000000;
+	    dc390_laststatus |= bval << 24;
 
 	    DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
-	    ResidCnt = (u32) DC390_read8 (CtcReg_High);
-	    ResidCnt <<= 8;
-	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
-	    ResidCnt <<= 8;
-	    ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
+	    ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) |
+			((u32) DC390_read8 (CtcReg_Mid) << 8)) |
+		    (u32) DC390_read8 (CtcReg_Low);
 
-	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGBusAddr += xferCnt;
-	    pSRB->TotalXferredLen += xferCnt;
-	    pSRB->SGToBeXferLen = ResidCnt;
+	    xferCnt = dc390_advance_segment(pSRB, ResidCnt);
 
-	    if( residual )
-	    {
-		static int feedback_requested;
+	    if (residual) {
+		size_t count = 1;
+		size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList);
+		unsigned long flags;
+		u8 *ptr;
+
 		bval = DC390_read8 (ScsiFifo);	    /* get one residual byte */
 
-		if (!feedback_requested) {
-			feedback_requested = 1;
-			printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
-			       "to help improve support for your system.\n", __FILE__);
+		local_irq_save(flags);
+		ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count);
+		if (likely(ptr)) {
+			*(ptr + offset) = bval;
+			scsi_kunmap_atomic_sg(ptr);
 		}
+		local_irq_restore(flags);
+		WARN_ON(!ptr);
 
-		ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
-		*ptr = bval;
-		pSRB->SGBusAddr++; xferCnt++;
-		pSRB->TotalXferredLen++;
-		pSRB->SGToBeXferLen--;
+		/* 1 more byte read */
+		xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1);
 	    }
-	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+	    DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\
 			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
-
 	}
     }
     if ((*psstatus & 7) != SCSI_DATA_IN)
     {
 	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
     }
 }
 
@@ -1216,7 +1145,7 @@
 
 
 /* handle RESTORE_PTR */
-/* I presume, this command is already mapped, so, have to remap. */
+/* This doesn't look very healthy... to-be-fixed */
 static void 
 dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
 {
@@ -1225,6 +1154,7 @@
     pSRB->TotalXferredLen = 0;
     pSRB->SGIndex = 0;
     if (pcmd->use_sg) {
+	size_t saved;
 	pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
 	psgl = pSRB->pSegmentList;
 	//dc390_pci_sync(pSRB);
@@ -1236,15 +1166,16 @@
 	    if( pSRB->SGIndex < pSRB->SGcount )
 	    {
 		pSRB->pSegmentList++;
-		psgl = pSRB->pSegmentList;
-		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+
+		dc390_start_segment(pSRB);
 	    }
 	    else
 		pSRB->SGToBeXferLen = 0;
 	}
-	pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
-	pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+
+	saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen;
+	pSRB->SGToBeXferLen -= saved;
+	pSRB->SGBusAddr += saved;
 	printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
 		pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
 
@@ -1365,7 +1296,6 @@
 static void
 dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
 {
-    struct scatterlist *psgl;
     unsigned long  lval;
     struct dc390_dcb*   pDCB = pACB->pActiveDCB;
 
@@ -1391,12 +1321,11 @@
 
     if( pSRB->SGIndex < pSRB->SGcount )
     {
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
 	if( !pSRB->SGToBeXferLen )
 	{
-	    psgl = pSRB->pSegmentList;
-	    pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-	    pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    dc390_start_segment(pSRB);
+
 	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
 	}
 	lval = pSRB->SGToBeXferLen;
@@ -1410,12 +1339,12 @@
 	DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
 	DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
 
-	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
 	pSRB->SRBState = SRB_DATA_XFER;
 
 	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
-	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
 	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
 	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
 	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
@@ -1436,8 +1365,8 @@
 	pSRB->SRBState |= SRB_XFERPAD;
 	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
 /*
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
-	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
 */
     }
 }
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index 9b66fa8..c3d8c80 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -19,14 +19,6 @@
 
 #define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
 
-#define pci_dma_lo32(a)			(a & 0xffffffff)
-
-typedef u8		UCHAR;	/*  8 bits */
-typedef u16		USHORT;	/* 16 bits */
-typedef u32		UINT;	/* 32 bits */
-typedef unsigned long	ULONG;	/* 32/64 bits */
-
-
 /*
 ;-----------------------------------------------------------------------
 ; SCSI Request Block
@@ -43,7 +35,9 @@
 
 struct scatterlist Segmentx;	/* make a one entry of S/G list table */
 
-unsigned long	SGBusAddr;	/*;a segment starting address as seen by AM53C974A*/
+unsigned long	SGBusAddr;	/*;a segment starting address as seen by AM53C974A
+				  in CPU endianness. We're only getting 32-bit bus
+				  addresses by default */
 unsigned long	SGToBeXferLen;	/*; to be xfer length */
 unsigned long	TotalXferredLen;
 unsigned long	SavedTotXLen;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 66e7bc9..1d8a2f6 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -22,10 +22,7 @@
 #include <asm/io.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
-
-#ifdef CONFIG_ARCH_AT91
 #include <asm/arch/cpu.h>
-#endif
 
 #include "atmel_spi.h"
 
@@ -552,10 +549,8 @@
 		goto out_free_buffer;
 	as->irq = irq;
 	as->clk = clk;
-#ifdef CONFIG_ARCH_AT91
 	if (!cpu_is_at91rm9200())
 		as->new_1 = 1;
-#endif
 
 	ret = request_irq(irq, atmel_spi_interrupt, 0,
 			pdev->dev.bus_id, master);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index b847bbc8..278a22c 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -87,8 +87,6 @@
 
 source "drivers/usb/image/Kconfig"
 
-source "drivers/usb/net/Kconfig"
-
 source "drivers/usb/mon/Kconfig"
 
 comment "USB port drivers"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 0ef090b..72464b5 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -23,13 +23,6 @@
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-$(CONFIG_USB)		+= storage/
 
-obj-$(CONFIG_USB_CATC)		+= net/
-obj-$(CONFIG_USB_KAWETH)	+= net/
-obj-$(CONFIG_USB_PEGASUS)	+= net/
-obj-$(CONFIG_USB_RTL8150)	+= net/
-obj-$(CONFIG_USB_USBNET)	+= net/
-obj-$(CONFIG_USB_ZD1201)	+= net/
-
 obj-$(CONFIG_USB_MDC800)	+= image/
 obj-$(CONFIG_USB_MICROTEK)	+= image/
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index b082d95..11e9b15 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -1033,7 +1033,7 @@
 
 static int usbatm_heavy_init(struct usbatm_data *instance)
 {
-	int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+	int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
 
 	if (ret < 0) {
 		usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index b5332e6..88fb56d 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1307,7 +1307,7 @@
 }
 
 
-/* remove a service from the the device
+/* remove a service from the device
    scp->id must be set! */
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
 {
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index ba5d1dc..3efe670 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -558,7 +558,7 @@
 	tristate "USB Debugging Device"
 	depends on USB_SERIAL
 	help
-	  Say Y here if you have a USB debugging device used to recieve
+	  Say Y here if you have a USB debugging device used to receive
 	  debugging data from another machine.  The most common of these
 	  devices is the NetChip TurboCONNECT device.
 
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index b675735..fbc8c27 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -9,7 +9,7 @@
  * The device works as an standard CDC device, it has 2 interfaces, the first
  * one is for firmware access and the second is the serial one.
  * The protocol is very simply, there are two posibilities reading or writing.
- * When writting the first urb must have a Header that starts with 0x20 0x29 the
+ * When writing the first urb must have a Header that starts with 0x20 0x29 the
  * next two bytes must say how much data will be sended.
  * When reading the process is almost equal except that the header starts with
  * 0x00 0x20.
@@ -18,7 +18,7 @@
  * buffer: The First and Second byte is used for a Header, the Third and Fourth
  * tells the  device the amount of information the package holds.
  * Packages are 60 bytes long Header Stuff.
- * When writting to the device the first two bytes of the header are 0x20 0x29
+ * When writing to the device the first two bytes of the header are 0x20 0x29
  * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
  * situation, when too much data arrives to the device because it sends the data
  * but with out the header. I will use a simply hack to override this situation,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 18f74ac..4807f96 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2465,7 +2465,7 @@
 	    ((edge_serial->is_epic) &&
 	     (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
 	     (regNum == MCR))) {
-		dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+		dbg("SendCmdWriteUartReg - Not writing to MCR Register");
 		return 0;
 	}
 
@@ -2473,7 +2473,7 @@
 	    ((edge_serial->is_epic) &&
 	     (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
 	     (regNum == LCR))) {
-		dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+		dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
 		return 0;
 	}
 
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1132ba5..9a256d2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1348,6 +1348,20 @@
 	  Please read the <file:Documentation/fb/README-sstfb.txt> for supported
 	  options and other important info  support.
 
+config FB_VT8623
+	tristate "VIA VT8623 support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_TILEBLITTING
+	select FB_SVGALIB
+	select VGASTATE
+	select FONT_8x16 if FRAMEBUFFER_CONSOLE
+	---help---
+	  Driver for CastleRock integrated graphics core in the
+	  VIA VT8623 [Apollo CLE266] chipset.
+
 config FB_CYBLA
 	tristate "Cyberblade/i1 support"
 	depends on FB && PCI && X86_32 && !64BIT
@@ -1401,6 +1415,20 @@
 	This will compile the Trident frame buffer device with
 	acceleration functions.
 
+config FB_ARK
+	tristate "ARK 2000PV support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_TILEBLITTING
+	select FB_SVGALIB
+	select VGASTATE
+	select FONT_8x16 if FRAMEBUFFER_CONSOLE
+	---help---
+	  Driver for PCI graphics boards with ARK 2000PV chip
+	  and ICS 5342 RAMDAC.
+
 config FB_PM3
 	tristate "Permedia3 support"
 	depends on FB && PCI && BROKEN
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a916c20..0b70567 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -54,10 +54,12 @@
 obj-$(CONFIG_FB_CT65550)          += chipsfb.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_VT8623)           += vt8623fb.o
 obj-$(CONFIG_FB_CYBLA)            += cyblafb.o
 obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o
 obj-$(CONFIG_FB_LE80578)          += vermilion/
 obj-$(CONFIG_FB_S3)               += s3fb.o
+obj-$(CONFIG_FB_ARK)              += arkfb.o
 obj-$(CONFIG_FB_STI)              += stifb.o
 obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o
 obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
new file mode 100644
index 0000000..ba6fede
--- /dev/null
+++ b/drivers/video/arkfb.c
@@ -0,0 +1,1200 @@
+/*
+ *  linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV
+ *  with ICS 5342 dac (it is easy to add support for different dacs).
+ *
+ *  Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  Code is based on s3fb
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct arkfb_info {
+	int mclk_freq;
+	int mtrr_reg;
+
+	struct dac_info *dac;
+	struct vgastate state;
+	struct mutex open_lock;
+	unsigned int ref_count;
+	u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static const struct svga_fb_format arkfb_formats[] = {
+	{ 0,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4,	FB_VISUAL_PSEUDOCOLOR, 8, 8},
+	{ 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 8, 16},
+	{ 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 1,
+		FB_TYPE_INTERLEAVED_PLANES, 1,		FB_VISUAL_PSEUDOCOLOR, 8, 16},
+	{ 8,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 8, 8},
+	{16,  {10, 5, 0}, {5, 5, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 4, 4},
+	{16,  {11, 5, 0}, {5, 6, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 4, 4},
+	{24,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 8, 8},
+	{32,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 2, 2},
+	SVGA_FORMAT_END
+};
+
+
+/* CRT timing register sets */
+
+static const struct vga_regset ark_h_total_regs[]        = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_h_display_regs[]      = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_start_regs[]  = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_end_regs[]    = {{0x03, 0, 4}, {0x05, 7, 7	}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_start_regs[]   = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_end_regs[]     = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset ark_v_total_regs[]        = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_display_regs[]      = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_start_regs[]  = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
+// const struct vga_regset ark_v_blank_end_regs[]    = {{0x16, 0, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_end_regs[]    = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_start_regs[]   = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_end_regs[]     = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset ark_line_compare_regs[]   = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_start_address_regs[]  = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
+static const struct vga_regset ark_offset_regs[]         = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
+
+static const struct svga_timing_regs ark_timing_regs     = {
+	ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
+	ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
+	ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
+	ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+static int threshold = 4;
+
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "FIFO threshold");
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+	const u8 *font = map->data;
+	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+	int i, c;
+
+	if ((map->width != 8) || (map->height != 16) ||
+	    (map->depth != 1) || (map->length != 256)) {
+	    	printk(KERN_ERR "fb%d: unsupported font parameters: width %d, "
+		       "height %d, depth %d, length %d\n", info->node,
+		       map->width, map->height, map->depth, map->length);
+		return;
+	}
+
+	fb += 2;
+	for (c = 0; c < map->length; c++) {
+		for (i = 0; i < map->height; i++) {
+			fb_writeb(font[i], &fb[i * 4]);
+			fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
+		}
+		fb += 128;
+
+		if ((c % 8) == 7)
+			fb += 128*8;
+
+		font += map->height;
+	}
+}
+
+static struct fb_tile_ops arkfb_tile_ops = {
+	.fb_settile	= arkfb_settile,
+	.fb_tilecopy	= svga_tilecopy,
+	.fb_tilefill    = svga_tilefill,
+	.fb_tileblit    = svga_tileblit,
+	.fb_tilecursor  = svga_tilecursor,
+	.fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+	return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	u32 fg = expand_color(image->fg_color);
+	u32 bg = expand_color(image->bg_color);
+	const u8 *src1, *src;
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	u32 val;
+	int x, y;
+
+	src1 = image->data;
+	dst1 = info->screen_base + (image->dy * info->fix.line_length)
+		 + ((image->dx / 8) * 4);
+
+	for (y = 0; y < image->height; y++) {
+		src = src1;
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < image->width; x += 8) {
+			val = *(src++) * 0x01010101;
+			val = (val & fg) | (~val & bg);
+			fb_writel(val, dst++);
+		}
+		src1 += image->width / 8;
+		dst1 += info->fix.line_length;
+	}
+
+}
+
+/* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	u32 fg = expand_color(rect->color);
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	int x, y;
+
+	dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+		 + ((rect->dx / 8) * 4);
+
+	for (y = 0; y < rect->height; y++) {
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < rect->width; x += 8) {
+			fb_writel(fg, dst++);
+		}
+		dst1 += info->fix.line_length;
+	}
+
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+	return (((c &  1) << 24) | ((c &  2) << 27) | ((c &  4) << 14) | ((c &   8) << 17) |
+		((c & 16) <<  4) | ((c & 32) <<  7) | ((c & 64) >>  6) | ((c & 128) >>  3)) * 0xF;
+}
+
+/* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	u32 fg = image->fg_color * 0x11111111;
+	u32 bg = image->bg_color * 0x11111111;
+	const u8 *src1, *src;
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	u32 val;
+	int x, y;
+
+	src1 = image->data;
+	dst1 = info->screen_base + (image->dy * info->fix.line_length)
+		 + ((image->dx / 8) * 4);
+
+	for (y = 0; y < image->height; y++) {
+		src = src1;
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < image->width; x += 8) {
+			val = expand_pixel(*(src++));
+			val = (val & fg) | (~val & bg);
+			fb_writel(val, dst++);
+		}
+		src1 += image->width / 8;
+		dst1 += info->fix.line_length;
+	}
+
+}
+
+static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+	    && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+		if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+			arkfb_iplan_imageblit(info, image);
+		else
+			arkfb_cfb4_imageblit(info, image);
+	} else
+		cfb_imageblit(info, image);
+}
+
+static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	if ((info->var.bits_per_pixel == 4)
+	    && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+	    && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+		arkfb_iplan_fillrect(info, rect);
+	 else
+		cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+enum
+{
+	DAC_PSEUDO8_8,
+	DAC_RGB1555_8,
+	DAC_RGB0565_8,
+	DAC_RGB0888_8,
+	DAC_RGB8888_8,
+	DAC_PSEUDO8_16,
+	DAC_RGB1555_16,
+	DAC_RGB0565_16,
+	DAC_RGB0888_16,
+	DAC_RGB8888_16,
+	DAC_MAX
+};
+
+struct dac_ops {
+	int (*dac_get_mode)(struct dac_info *info);
+	int (*dac_set_mode)(struct dac_info *info, int mode);
+	int (*dac_get_freq)(struct dac_info *info, int channel);
+	int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
+	void (*dac_release)(struct dac_info *info);
+};
+
+typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
+typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
+
+struct dac_info
+{
+	struct dac_ops *dacops;
+	dac_read_regs_t dac_read_regs;
+	dac_write_regs_t dac_write_regs;
+	void *data;
+};
+
+
+static inline u8 dac_read_reg(struct dac_info *info, u8 reg)
+{
+	u8 code[2] = {reg, 0};
+	info->dac_read_regs(info->data, code, 1);
+	return code[1];
+}
+
+static inline void dac_read_regs(struct dac_info *info, u8 *code, int count)
+{
+	info->dac_read_regs(info->data, code, count);
+}
+
+static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val)
+{
+	u8 code[2] = {reg, val};
+	info->dac_write_regs(info->data, code, 1);
+}
+
+static inline void dac_write_regs(struct dac_info *info, u8 *code, int count)
+{
+	info->dac_write_regs(info->data, code, count);
+}
+
+static inline int dac_set_mode(struct dac_info *info, int mode)
+{
+	return info->dacops->dac_set_mode(info, mode);
+}
+
+static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+	return info->dacops->dac_set_freq(info, channel, freq);
+}
+
+static inline void dac_release(struct dac_info *info)
+{
+	info->dacops->dac_release(info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ICS5342 DAC */
+
+struct ics5342_info
+{
+	struct dac_info dac;
+	u8 mode;
+};
+
+#define DAC_PAR(info) ((struct ics5342_info *) info)
+
+/* LSB is set to distinguish unused slots */
+static const u8 ics5342_mode_table[DAC_MAX] = {
+	[DAC_PSEUDO8_8]  = 0x01, [DAC_RGB1555_8]  = 0x21, [DAC_RGB0565_8]  = 0x61,
+	[DAC_RGB0888_8]  = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31,
+	[DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71
+};
+
+static int ics5342_set_mode(struct dac_info *info, int mode)
+{
+	u8 code;
+
+	if (mode >= DAC_MAX)
+		return -EINVAL;
+
+	code = ics5342_mode_table[mode];
+
+	if (! code)
+		return -EINVAL;
+
+	dac_write_reg(info, 6, code & 0xF0);
+	DAC_PAR(info)->mode = mode;
+
+	return 0;
+}
+
+static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3,
+	60000, 250000, 14318};
+
+/* pd4 - allow only posdivider 4 (r=2) */
+static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2,
+	60000, 335000, 14318};
+
+/* 270 MHz should be upper bound for VCO clock according to specs,
+   but that is too restrictive in pd4 case */
+
+static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+	u16 m, n, r;
+
+	/* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */
+	int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16)
+				  ? &ics5342_pll_pd4 : &ics5342_pll,
+				  freq, &m, &n, &r, 0);
+
+	if (rv < 0) {
+		return -EINVAL;
+	} else {
+		u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)};
+		dac_write_regs(info, code, 3);
+		return 0;
+	}
+}
+
+static void ics5342_release(struct dac_info *info)
+{
+	ics5342_set_mode(info, DAC_PSEUDO8_8);
+	kfree(info);
+}
+
+static struct dac_ops ics5342_ops = {
+	.dac_set_mode	= ics5342_set_mode,
+	.dac_set_freq	= ics5342_set_freq,
+	.dac_release	= ics5342_release
+};
+
+
+static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data)
+{
+	struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL);
+
+	if (! info)
+		return NULL;
+
+	info->dacops = &ics5342_ops;
+	info->dac_read_regs = drr;
+	info->dac_write_regs = dwr;
+	info->data = data;
+	DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */
+	return info;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
+
+static void ark_dac_read_regs(void *data, u8 *code, int count)
+{
+	u8 regval = vga_rseq(NULL, 0x1C);
+
+	while (count != 0)
+	{
+		vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+		code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+		count--;
+		code += 2;
+	}
+
+	vga_wseq(NULL, 0x1C, regval);
+}
+
+static void ark_dac_write_regs(void *data, u8 *code, int count)
+{
+	u8 regval = vga_rseq(NULL, 0x1C);
+
+	while (count != 0)
+	{
+		vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+		vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+		count--;
+		code += 2;
+	}
+
+	vga_wseq(NULL, 0x1C, regval);
+}
+
+
+static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+	struct arkfb_info *par = info->par;
+	u8 regval;
+
+	int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
+	if (rv < 0) {
+		printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+		return;
+	}
+
+	/* Set VGA misc register  */
+	regval = vga_r(NULL, VGA_MIS_R);
+	vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+}
+
+
+/* Open framebuffer */
+
+static int arkfb_open(struct fb_info *info, int user)
+{
+	struct arkfb_info *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count == 0) {
+		memset(&(par->state), 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+		par->state.num_crtc = 0x60;
+		par->state.num_seq = 0x30;
+		save_vga(&(par->state));
+	}
+
+	par->ref_count++;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+/* Close framebuffer */
+
+static int arkfb_release(struct fb_info *info, int user)
+{
+	struct arkfb_info *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count == 0) {
+		mutex_unlock(&(par->open_lock));
+		return -EINVAL;
+	}
+
+	if (par->ref_count == 1) {
+		restore_vga(&(par->state));
+		dac_set_mode(par->dac, DAC_PSEUDO8_8);
+	}
+
+	par->ref_count--;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+/* Validate passed in var */
+
+static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int rv, mem, step;
+
+	/* Find appropriate format */
+	rv = svga_match_format (arkfb_formats, var, NULL);
+	if (rv < 0)
+	{
+		printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+		return rv;
+	}
+
+	/* Do not allow to have real resoulution larger than virtual */
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	/* Round up xres_virtual to have proper alignment of lines */
+	step = arkfb_formats[rv].xresstep - 1;
+	var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+
+	/* Check whether have enough memory */
+	mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+	if (mem > info->screen_size)
+	{
+		printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+		return -EINVAL;
+	}
+
+	rv = svga_check_timings (&ark_timing_regs, var, info->node);
+	if (rv < 0)
+	{
+		printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+		return rv;
+	}
+
+	/* Interlaced mode is broken */
+	if (var->vmode & FB_VMODE_INTERLACED)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* Set video mode from par */
+
+static int arkfb_set_par(struct fb_info *info)
+{
+	struct arkfb_info *par = info->par;
+	u32 value, mode, hmul, hdiv, offset_value, screen_size;
+	u32 bpp = info->var.bits_per_pixel;
+	u8 regval;
+
+	if (bpp != 0) {
+		info->fix.ypanstep = 1;
+		info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+		info->flags &= ~FBINFO_MISC_TILEBLITTING;
+		info->tileops = NULL;
+
+		/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+		info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+		info->pixmap.blit_y = ~(u32)0;
+
+		offset_value = (info->var.xres_virtual * bpp) / 64;
+		screen_size = info->var.yres_virtual * info->fix.line_length;
+	} else {
+		info->fix.ypanstep = 16;
+		info->fix.line_length = 0;
+
+		info->flags |= FBINFO_MISC_TILEBLITTING;
+		info->tileops = &arkfb_tile_ops;
+
+		/* supports 8x16 tiles only */
+		info->pixmap.blit_x = 1 << (8 - 1);
+		info->pixmap.blit_y = 1 << (16 - 1);
+
+		offset_value = info->var.xres_virtual / 16;
+		screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+	}
+
+	info->var.xoffset = 0;
+	info->var.yoffset = 0;
+	info->var.activate = FB_ACTIVATE_NOW;
+
+	/* Unlock registers */
+	svga_wcrt_mask(0x11, 0x00, 0x80);
+
+	/* Blank screen and turn off sync */
+	svga_wseq_mask(0x01, 0x20, 0x20);
+	svga_wcrt_mask(0x17, 0x00, 0x80);
+
+	/* Set default values */
+	svga_set_default_gfx_regs();
+	svga_set_default_atc_regs();
+	svga_set_default_seq_regs();
+	svga_set_default_crt_regs();
+	svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
+	svga_wcrt_multi(ark_start_address_regs, 0);
+
+	/* ARK specific initialization */
+	svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+	svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+
+	vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
+	vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
+	vga_wseq(NULL, 0x15, 0);
+	vga_wseq(NULL, 0x16, 0);
+
+	/* Set the FIFO threshold register */
+	/* It is fascinating way to store 5-bit value in 8-bit register */
+	regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
+	vga_wseq(NULL, 0x18, regval);
+
+	/* Set the offset register */
+	pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
+	svga_wcrt_multi(ark_offset_regs, offset_value);
+
+	/* fix for hi-res textmode */
+	svga_wcrt_mask(0x40, 0x08, 0x08);
+
+	if (info->var.vmode & FB_VMODE_DOUBLE)
+		svga_wcrt_mask(0x09, 0x80, 0x80);
+	else
+		svga_wcrt_mask(0x09, 0x00, 0x80);
+
+	if (info->var.vmode & FB_VMODE_INTERLACED)
+		svga_wcrt_mask(0x44, 0x04, 0x04);
+	else
+		svga_wcrt_mask(0x44, 0x00, 0x04);
+
+	hmul = 1;
+	hdiv = 1;
+	mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix));
+
+	/* Set mode-specific register values */
+	switch (mode) {
+	case 0:
+		pr_debug("fb%d: text mode\n", info->node);
+		svga_set_textmode_vga_regs();
+
+		vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+		svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+		dac_set_mode(par->dac, DAC_PSEUDO8_8);
+
+		break;
+	case 1:
+		pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+		vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+		vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+		svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+		dac_set_mode(par->dac, DAC_PSEUDO8_8);
+		break;
+	case 2:
+		pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+		svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+		dac_set_mode(par->dac, DAC_PSEUDO8_8);
+		break;
+	case 3:
+		pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+
+		if (info->var.pixclock > 20000) {
+			pr_debug("fb%d: not using multiplex\n", info->node);
+			svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+			dac_set_mode(par->dac, DAC_PSEUDO8_8);
+		} else {
+			pr_debug("fb%d: using multiplex\n", info->node);
+			svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+			dac_set_mode(par->dac, DAC_PSEUDO8_16);
+			hdiv = 2;
+		}
+		break;
+	case 4:
+		pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+		svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+		dac_set_mode(par->dac, DAC_RGB1555_16);
+		break;
+	case 5:
+		pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+		svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+		dac_set_mode(par->dac, DAC_RGB0565_16);
+		break;
+	case 6:
+		pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
+		svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+		dac_set_mode(par->dac, DAC_RGB0888_16);
+		hmul = 3;
+		hdiv = 2;
+		break;
+	case 7:
+		pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+
+		vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
+		svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+		dac_set_mode(par->dac, DAC_RGB8888_16);
+		hmul = 2;
+		break;
+	default:
+		printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+		return -EINVAL;
+	}
+
+	ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
+	svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+			 (info->var.vmode & FB_VMODE_DOUBLE)     ? 2 : 1,
+			 (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+			  hmul, info->node);
+
+	/* Set interlaced mode start/end register */
+	value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+	value = ((value * hmul / hdiv) / 8) - 5;
+	vga_wcrt(NULL, 0x42, (value + 1) / 2);
+
+	memset_io(info->screen_base, 0x00, screen_size);
+	/* Device and screen back on */
+	svga_wcrt_mask(0x17, 0x80, 0x80);
+	svga_wseq_mask(0x01, 0x00, 0x20);
+
+	return 0;
+}
+
+/* Set a colour register */
+
+static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+				u_int transp, struct fb_info *fb)
+{
+	switch (fb->var.bits_per_pixel) {
+	case 0:
+	case 4:
+		if (regno >= 16)
+			return -EINVAL;
+
+		if ((fb->var.bits_per_pixel == 4) &&
+		    (fb->var.nonstd == 0)) {
+			outb(0xF0, VGA_PEL_MSK);
+			outb(regno*16, VGA_PEL_IW);
+		} else {
+			outb(0x0F, VGA_PEL_MSK);
+			outb(regno, VGA_PEL_IW);
+		}
+		outb(red >> 10, VGA_PEL_D);
+		outb(green >> 10, VGA_PEL_D);
+		outb(blue >> 10, VGA_PEL_D);
+		break;
+	case 8:
+		if (regno >= 256)
+			return -EINVAL;
+
+		outb(0xFF, VGA_PEL_MSK);
+		outb(regno, VGA_PEL_IW);
+		outb(red >> 10, VGA_PEL_D);
+		outb(green >> 10, VGA_PEL_D);
+		outb(blue >> 10, VGA_PEL_D);
+		break;
+	case 16:
+		if (regno >= 16)
+			return 0;
+
+		if (fb->var.green.length == 5)
+			((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+				((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+		else if (fb->var.green.length == 6)
+			((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+				((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+		else
+			return -EINVAL;
+		break;
+	case 24:
+	case 32:
+		if (regno >= 16)
+			return 0;
+
+		((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+			(green & 0xFF00) | ((blue & 0xFF00) >> 8);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set the display blanking state */
+
+static int arkfb_blank(int blank_mode, struct fb_info *info)
+{
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		pr_debug("fb%d: unblank\n", info->node);
+		svga_wseq_mask(0x01, 0x00, 0x20);
+		svga_wcrt_mask(0x17, 0x80, 0x80);
+		break;
+	case FB_BLANK_NORMAL:
+		pr_debug("fb%d: blank\n", info->node);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		svga_wcrt_mask(0x17, 0x80, 0x80);
+		break;
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_VSYNC_SUSPEND:
+		pr_debug("fb%d: sync down\n", info->node);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		svga_wcrt_mask(0x17, 0x00, 0x80);
+		break;
+	}
+	return 0;
+}
+
+
+/* Pan the display */
+
+static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	unsigned int offset;
+
+	/* Calculate the offset */
+	if (var->bits_per_pixel == 0) {
+		offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+		offset = offset >> 2;
+	} else {
+		offset = (var->yoffset * info->fix.line_length) +
+			 (var->xoffset * var->bits_per_pixel / 8);
+		offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+	}
+
+	/* Set the offset */
+	svga_wcrt_multi(ark_start_address_regs, offset);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops arkfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= arkfb_open,
+	.fb_release	= arkfb_release,
+	.fb_check_var	= arkfb_check_var,
+	.fb_set_par	= arkfb_set_par,
+	.fb_setcolreg	= arkfb_setcolreg,
+	.fb_blank	= arkfb_blank,
+	.fb_pan_display	= arkfb_pan_display,
+	.fb_fillrect	= arkfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= arkfb_imageblit,
+	.fb_get_caps    = svga_get_caps,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* PCI probe */
+static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct fb_info *info;
+	struct arkfb_info *par;
+	int rc;
+	u8 regval;
+
+	/* Ignore secondary VGA device because there is no VGA arbitration */
+	if (! svga_primary_device(dev)) {
+		dev_info(&(dev->dev), "ignoring secondary device\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and fill driver data structure */
+	info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+	if (! info) {
+		dev_err(&(dev->dev), "cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	par = info->par;
+	mutex_init(&par->open_lock);
+
+	info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+	info->fbops = &arkfb_ops;
+
+	/* Prepare PCI device */
+	rc = pci_enable_device(dev);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot enable PCI device\n");
+		goto err_enable_device;
+	}
+
+	rc = pci_request_regions(dev, "arkfb");
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+		goto err_request_regions;
+	}
+
+	par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
+	if (! par->dac) {
+		rc = -ENOMEM;
+		dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+		goto err_dac;
+	}
+
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = pci_resource_len(dev, 0);
+
+	/* Map physical IO memory address into kernel space */
+	info->screen_base = pci_iomap(dev, 0, 0);
+	if (! info->screen_base) {
+		rc = -ENOMEM;
+		dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+		goto err_iomap;
+	}
+
+	/* FIXME get memsize */
+	regval = vga_rseq(NULL, 0x10);
+	info->screen_size = (1 << (regval >> 6)) << 20;
+	info->fix.smem_len = info->screen_size;
+
+	strcpy(info->fix.id, "ARK 2000PV");
+	info->fix.mmio_start = 0;
+	info->fix.mmio_len = 0;
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	info->fix.ypanstep = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->pseudo_palette = (void*) (par->pseudo_palette);
+
+	/* Prepare startup mode */
+	rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+	if (! ((rc == 1) || (rc == 2))) {
+		rc = -EINVAL;
+		dev_err(&(dev->dev), "mode %s not found\n", mode);
+		goto err_find_mode;
+	}
+
+	rc = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot allocate colormap\n");
+		goto err_alloc_cmap;
+	}
+
+	rc = register_framebuffer(info);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot register framebugger\n");
+		goto err_reg_fb;
+	}
+
+	printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+		 pci_name(dev), info->fix.smem_len >> 20);
+
+	/* Record a reference to the driver data */
+	pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		par->mtrr_reg = -1;
+		par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+	}
+#endif
+
+	return 0;
+
+	/* Error handling */
+err_reg_fb:
+	fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+	pci_iounmap(dev, info->screen_base);
+err_iomap:
+	dac_release(par->dac);
+err_dac:
+	pci_release_regions(dev);
+err_request_regions:
+/*	pci_disable_device(dev); */
+err_enable_device:
+	framebuffer_release(info);
+	return rc;
+}
+
+/* PCI remove */
+
+static void __devexit ark_pci_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct arkfb_info *par = info->par;
+
+	if (info) {
+#ifdef CONFIG_MTRR
+		if (par->mtrr_reg >= 0) {
+			mtrr_del(par->mtrr_reg, 0, 0);
+			par->mtrr_reg = -1;
+		}
+#endif
+
+		dac_release(par->dac);
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+
+		pci_iounmap(dev, info->screen_base);
+		pci_release_regions(dev);
+/*		pci_disable_device(dev); */
+
+		pci_set_drvdata(dev, NULL);
+		framebuffer_release(info);
+	}
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct arkfb_info *par = info->par;
+
+	dev_info(&(dev->dev), "suspend\n");
+
+	acquire_console_sem();
+	mutex_lock(&(par->open_lock));
+
+	if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+		mutex_unlock(&(par->open_lock));
+		release_console_sem();
+		return 0;
+	}
+
+	fb_set_suspend(info, 1);
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	mutex_unlock(&(par->open_lock));
+	release_console_sem();
+
+	return 0;
+}
+
+
+/* PCI resume */
+
+static int ark_pci_resume (struct pci_dev* dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct arkfb_info *par = info->par;
+
+	dev_info(&(dev->dev), "resume\n");
+
+	acquire_console_sem();
+	mutex_lock(&(par->open_lock));
+
+	if (par->ref_count == 0) {
+		mutex_unlock(&(par->open_lock));
+		release_console_sem();
+		return 0;
+	}
+
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+
+	if (pci_enable_device(dev))
+		goto fail;
+
+	pci_set_master(dev);
+
+	arkfb_set_par(info);
+	fb_set_suspend(info, 0);
+
+	mutex_unlock(&(par->open_lock));
+fail:
+	release_console_sem();
+	return 0;
+}
+#else
+#define ark_pci_suspend NULL
+#define ark_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id ark_devices[] __devinitdata = {
+	{PCI_DEVICE(0xEDD8, 0xA099)},
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, ark_devices);
+
+static struct pci_driver arkfb_pci_driver = {
+	.name		= "arkfb",
+	.id_table	= ark_devices,
+	.probe		= ark_pci_probe,
+	.remove		= __devexit_p(ark_pci_remove),
+	.suspend	= ark_pci_suspend,
+	.resume		= ark_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit arkfb_cleanup(void)
+{
+	pr_debug("arkfb: cleaning up\n");
+	pci_unregister_driver(&arkfb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init arkfb_init(void)
+{
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("arkfb", &option))
+		return -ENODEV;
+
+	if (option && *option)
+		mode = option;
+#endif
+
+	pr_debug("arkfb: initializing\n");
+	return pci_register_driver(&arkfb_pci_driver);
+}
+
+module_init(arkfb_init);
+module_exit(arkfb_cleanup);
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index ea67dd9..8d3455d 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -80,8 +80,9 @@
 #include "../macmodes.h"
 #endif
 #ifdef __sparc__
-#include <asm/pbm.h>
 #include <asm/fbio.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
 #endif
 
 #ifdef CONFIG_ADB_PMU
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index 2a7f381..fe2c6ad 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -11,7 +11,6 @@
 #include <asm/uaccess.h>
 
 #ifdef __sparc__
-#include <asm/pbm.h>
 #include <asm/fbio.h>
 #endif
 
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index f577bd8..03cfb7a 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/video/softcursor.c
+ * linux/drivers/video/console/softcursor.c
  *
  * Generic software cursor for frame buffer devices
  *
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 08d4e11..38c2e25 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1236,6 +1236,10 @@
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
 #elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+	vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+				      & ~_PAGE_CACHABLE)
+				     | (_PAGE_BUFFER | _PAGE_DIRTY));
 #elif defined(__ia64__)
 	if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
 		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 7e76019..1a7d778 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1717,7 +1717,7 @@
  * @info: pointer to device specific info structure
  *
  * DESCRIPTION:
- * Sets the the user monitor's horizontal and vertical
+ * Sets the user monitor's horizontal and vertical
  * frequency limits
  */
 static void __devinit i810_init_monspecs(struct fb_info *info)
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index a5690a5..9445cdb 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -72,7 +72,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index a5c825d..c57aaad 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -70,7 +70,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index cb2aa40..c8559a7 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -93,7 +93,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 18886b6..5948e54 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -78,7 +78,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index f297c7b..c627955 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -149,8 +149,7 @@
 		pll = NV_RD32(par->PMC, 0x4024);
 		M = pll & 0xFF;
 		N = (pll >> 8) & 0xFF;
-		if (((par->Chipset & 0xfff0) == 0x0290) ||
-				((par->Chipset & 0xfff0) == 0x0390)) {
+		if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
 			MB = 1;
 			NB = 1;
 		} else {
@@ -963,6 +962,7 @@
 
 		if (((par->Chipset & 0xfff0) == 0x0090) ||
 		    ((par->Chipset & 0xfff0) == 0x01D0) ||
+		    ((par->Chipset & 0xfff0) == 0x02E0) ||
 		    ((par->Chipset & 0xfff0) == 0x0290))
 			regions = 15;
 		for(i = 0; i < regions; i++) {
@@ -1275,6 +1275,7 @@
 						0x00100000);
 					break;
 				case 0x0090:
+				case 0x02E0:
 				case 0x0290:
 					NV_WR32(par->PRAMDAC, 0x0608,
 						NV_RD32(par->PRAMDAC, 0x0608) |
@@ -1352,6 +1353,7 @@
 			} else {
 				if (((par->Chipset & 0xfff0) == 0x0090) ||
 				    ((par->Chipset & 0xfff0) == 0x01D0) ||
+				    ((par->Chipset & 0xfff0) == 0x02E0) ||
 				    ((par->Chipset & 0xfff0) == 0x0290)) {
 					for (i = 0; i < 60; i++) {
 						NV_WR32(par->PGRAPH,
@@ -1403,6 +1405,7 @@
 				} else {
 					if ((par->Chipset & 0xfff0) == 0x0090 ||
 					    (par->Chipset & 0xfff0) == 0x01D0 ||
+					    (par->Chipset & 0xfff0) == 0x02E0 ||
 					    (par->Chipset & 0xfff0) == 0x0290) {
 						NV_WR32(par->PGRAPH, 0x0DF0,
 							NV_RD32(par->PFB, 0x0200));
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 7c36b5f..f85edf0 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -1243,6 +1243,7 @@
 	case 0x0140:		/* GeForce 6600 */
 	case 0x0160:		/* GeForce 6200 */
 	case 0x01D0:		/* GeForce 7200, 7300, 7400 */
+	case 0x02E0:		/* GeForce 7300 GT */
 	case 0x0090:		/* GeForce 7800 */
 	case 0x0210:		/* GeForce 6800 */
 	case 0x0220:		/* GeForce 6200 */
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 756fafb..d117358 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -796,23 +796,6 @@
 	return 0;
 }
 
-/* Get capabilities of accelerator based on the mode */
-
-static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
-			  struct fb_var_screeninfo *var)
-{
-	if (var->bits_per_pixel == 0) {
-		/* can only support 256 8x16 bitmap */
-		caps->x = 1 << (8 - 1);
-		caps->y = 1 << (16 - 1);
-		caps->len = 256;
-	} else {
-		caps->x = ~(u32)0;
-		caps->y = ~(u32)0;
-		caps->len = ~(u32)0;
-	}
-}
-
 /* ------------------------------------------------------------------------- */
 
 /* Frame buffer operations */
@@ -829,7 +812,7 @@
 	.fb_fillrect	= s3fb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= s3fb_imageblit,
-	.fb_get_caps    = s3fb_get_caps,
+	.fb_get_caps    = svga_get_caps,
 };
 
 /* ------------------------------------------------------------------------- */
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 842b5cd..836a612 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -14,7 +14,7 @@
  *  of it. 
  *
  *  First the roles of struct fb_info and struct display have changed. Struct
- *  display will go away. The way the the new framebuffer console code will
+ *  display will go away. The way the new framebuffer console code will
  *  work is that it will act to translate data about the tty/console in 
  *  struct vc_data to data in a device independent way in struct fb_info. Then
  *  various functions in struct fb_ops will be called to store the device 
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 079cdc9..25df928 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -347,6 +347,23 @@
 	return 256;
 }
 
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+		   struct fb_var_screeninfo *var)
+{
+	if (var->bits_per_pixel == 0) {
+		/* can only support 256 8x16 bitmap */
+		caps->x = 1 << (8 - 1);
+		caps->y = 1 << (16 - 1);
+		caps->len = 256;
+	} else {
+		caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+		caps->y = ~(u32)0;
+		caps->len = ~(u32)0;
+	}
+}
+EXPORT_SYMBOL(svga_get_caps);
 
 /* ------------------------------------------------------------------------- */
 
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
new file mode 100644
index 0000000..5e9755e
--- /dev/null
+++ b/drivers/video/vt8623fb.c
@@ -0,0 +1,927 @@
+/*
+ * linux/drivers/video/vt8623fb.c - fbdev driver for
+ * integrated graphic core in VIA VT8623 [CLE266] chipset
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb, some parts are from David Boucher's viafb
+ * (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct vt8623fb_info {
+	char __iomem *mmio_base;
+	int mtrr_reg;
+	struct vgastate state;
+	struct mutex open_lock;
+	unsigned int ref_count;
+	u32 pseudo_palette[16];
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format vt8623fb_formats[] = {
+	{ 0,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8,	FB_VISUAL_PSEUDOCOLOR, 16, 16},
+	{ 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 16, 16},
+	{ 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 1,
+		FB_TYPE_INTERLEAVED_PLANES, 1,		FB_VISUAL_PSEUDOCOLOR, 16, 16},
+	{ 8,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 8, 8},
+/*	{16,  {10, 5, 0}, {5, 5, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 4, 4},	*/
+	{16,  {11, 5, 0}, {5, 6, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 4, 4},
+	{32,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 2, 2},
+	SVGA_FORMAT_END
+};
+
+static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
+	60000, 300000, 14318};
+
+/* CRT timing register sets */
+
+struct vga_regset vt8623_h_total_regs[]       = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_h_display_regs[]     = {{0x01, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_end_regs[]   = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_start_regs[]  = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_end_regs[]    = {{0x05, 0, 4}, VGA_REGSET_END};
+
+struct vga_regset vt8623_v_total_regs[]       = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+struct vga_regset vt8623_v_display_regs[]     = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_end_regs[]   = {{0x16, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_start_regs[]  = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_end_regs[]    = {{0x11, 0, 3}, VGA_REGSET_END};
+
+struct vga_regset vt8623_offset_regs[]        = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_line_compare_regs[]  = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_fetch_count_regs[]   = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+struct svga_timing_regs vt8623_timing_regs     = {
+	vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
+	vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
+	vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
+	vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
+
+module_param(mode, charp, 0644);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_tile_ops vt8623fb_tile_ops = {
+	.fb_settile	= svga_settile,
+	.fb_tilecopy	= svga_tilecopy,
+	.fb_tilefill    = svga_tilefill,
+	.fb_tileblit    = svga_tileblit,
+	.fb_tilecursor  = svga_tilecursor,
+	.fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+	return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	u32 fg = expand_color(image->fg_color);
+	u32 bg = expand_color(image->bg_color);
+	const u8 *src1, *src;
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	u32 val;
+	int x, y;
+
+	src1 = image->data;
+	dst1 = info->screen_base + (image->dy * info->fix.line_length)
+		 + ((image->dx / 8) * 4);
+
+	for (y = 0; y < image->height; y++) {
+		src = src1;
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < image->width; x += 8) {
+			val = *(src++) * 0x01010101;
+			val = (val & fg) | (~val & bg);
+			fb_writel(val, dst++);
+		}
+		src1 += image->width / 8;
+		dst1 += info->fix.line_length;
+	}
+}
+
+/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	u32 fg = expand_color(rect->color);
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	int x, y;
+
+	dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+		 + ((rect->dx / 8) * 4);
+
+	for (y = 0; y < rect->height; y++) {
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < rect->width; x += 8) {
+			fb_writel(fg, dst++);
+		}
+		dst1 += info->fix.line_length;
+	}
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+	return (((c &  1) << 24) | ((c &  2) << 27) | ((c &  4) << 14) | ((c &   8) << 17) |
+		((c & 16) <<  4) | ((c & 32) <<  7) | ((c & 64) >>  6) | ((c & 128) >>  3)) * 0xF;
+}
+
+/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	u32 fg = image->fg_color * 0x11111111;
+	u32 bg = image->bg_color * 0x11111111;
+	const u8 *src1, *src;
+	u8 __iomem *dst1;
+	u32 __iomem *dst;
+	u32 val;
+	int x, y;
+
+	src1 = image->data;
+	dst1 = info->screen_base + (image->dy * info->fix.line_length)
+		 + ((image->dx / 8) * 4);
+
+	for (y = 0; y < image->height; y++) {
+		src = src1;
+		dst = (u32 __iomem *) dst1;
+		for (x = 0; x < image->width; x += 8) {
+			val = expand_pixel(*(src++));
+			val = (val & fg) | (~val & bg);
+			fb_writel(val, dst++);
+		}
+		src1 += image->width / 8;
+		dst1 += info->fix.line_length;
+	}
+}
+
+static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+	    && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+		if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+			vt8623fb_iplan_imageblit(info, image);
+		else
+			vt8623fb_cfb4_imageblit(info, image);
+	} else
+		cfb_imageblit(info, image);
+}
+
+static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	if ((info->var.bits_per_pixel == 4)
+	    && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+	    && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+		vt8623fb_iplan_fillrect(info, rect);
+	 else
+		cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+	u16 m, n, r;
+	u8 regval;
+	int rv;
+
+	rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+	if (rv < 0) {
+		printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+		return;
+	}
+
+	/* Set VGA misc register  */
+	regval = vga_r(NULL, VGA_MIS_R);
+	vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+	/* Set clock registers */
+	vga_wseq(NULL, 0x46, (n  | (r << 6)));
+	vga_wseq(NULL, 0x47, m);
+
+	udelay(1000);
+
+	/* PLL reset */
+	svga_wseq_mask(0x40, 0x02, 0x02);
+	svga_wseq_mask(0x40, 0x00, 0x02);
+}
+
+
+static int vt8623fb_open(struct fb_info *info, int user)
+{
+	struct vt8623fb_info *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count == 0) {
+		memset(&(par->state), 0, sizeof(struct vgastate));
+		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+		par->state.num_crtc = 0xA2;
+		par->state.num_seq = 0x50;
+		save_vga(&(par->state));
+	}
+
+	par->ref_count++;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static int vt8623fb_release(struct fb_info *info, int user)
+{
+	struct vt8623fb_info *par = info->par;
+
+	mutex_lock(&(par->open_lock));
+	if (par->ref_count == 0) {
+		mutex_unlock(&(par->open_lock));
+		return -EINVAL;
+	}
+
+	if (par->ref_count == 1)
+		restore_vga(&(par->state));
+
+	par->ref_count--;
+	mutex_unlock(&(par->open_lock));
+
+	return 0;
+}
+
+static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int rv, mem, step;
+
+	/* Find appropriate format */
+	rv = svga_match_format (vt8623fb_formats, var, NULL);
+	if (rv < 0)
+	{
+		printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+		return rv;
+	}
+
+	/* Do not allow to have real resoulution larger than virtual */
+	if (var->xres > var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if (var->yres > var->yres_virtual)
+		var->yres_virtual = var->yres;
+
+	/* Round up xres_virtual to have proper alignment of lines */
+	step = vt8623fb_formats[rv].xresstep - 1;
+	var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+	/* Check whether have enough memory */
+	mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+	if (mem > info->screen_size)
+	{
+		printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+		return -EINVAL;
+	}
+
+	/* Text mode is limited to 256 kB of memory */
+	if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
+	{
+		printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10);
+		return -EINVAL;
+	}
+
+	rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
+	if (rv < 0)
+	{
+		printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+		return rv;
+	}
+
+	/* Interlaced mode not supported */
+	if (var->vmode & FB_VMODE_INTERLACED)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static int vt8623fb_set_par(struct fb_info *info)
+{
+	u32 mode, offset_value, fetch_value, screen_size;
+	u32 bpp = info->var.bits_per_pixel;
+
+	if (bpp != 0) {
+		info->fix.ypanstep = 1;
+		info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+		info->flags &= ~FBINFO_MISC_TILEBLITTING;
+		info->tileops = NULL;
+
+		/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+		info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+		info->pixmap.blit_y = ~(u32)0;
+
+		offset_value = (info->var.xres_virtual * bpp) / 64;
+		fetch_value  = ((info->var.xres * bpp) / 128) + 4;
+
+		if (bpp == 4)
+			fetch_value  = (info->var.xres / 8) + 8; /* + 0 is OK */
+
+		screen_size  = info->var.yres_virtual * info->fix.line_length;
+	} else {
+		info->fix.ypanstep = 16;
+		info->fix.line_length = 0;
+
+		info->flags |= FBINFO_MISC_TILEBLITTING;
+		info->tileops = &vt8623fb_tile_ops;
+
+		/* supports 8x16 tiles only */
+		info->pixmap.blit_x = 1 << (8 - 1);
+		info->pixmap.blit_y = 1 << (16 - 1);
+
+		offset_value = info->var.xres_virtual / 16;
+		fetch_value  = (info->var.xres / 8) + 8;
+		screen_size  = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+	}
+
+	info->var.xoffset = 0;
+	info->var.yoffset = 0;
+	info->var.activate = FB_ACTIVATE_NOW;
+
+	/* Unlock registers */
+	svga_wseq_mask(0x10, 0x01, 0x01);
+	svga_wcrt_mask(0x11, 0x00, 0x80);
+	svga_wcrt_mask(0x47, 0x00, 0x01);
+
+	/* Device, screen and sync off */
+	svga_wseq_mask(0x01, 0x20, 0x20);
+	svga_wcrt_mask(0x36, 0x30, 0x30);
+	svga_wcrt_mask(0x17, 0x00, 0x80);
+
+	/* Set default values */
+	svga_set_default_gfx_regs();
+	svga_set_default_atc_regs();
+	svga_set_default_seq_regs();
+	svga_set_default_crt_regs();
+	svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
+	svga_wcrt_multi(vt8623_start_address_regs, 0);
+
+	svga_wcrt_multi(vt8623_offset_regs, offset_value);
+	svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+
+	if (info->var.vmode & FB_VMODE_DOUBLE)
+		svga_wcrt_mask(0x09, 0x80, 0x80);
+	else
+		svga_wcrt_mask(0x09, 0x00, 0x80);
+
+	svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
+	svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
+	svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+	vga_wseq(NULL, 0x17, 0x1F);       // FIFO depth
+	vga_wseq(NULL, 0x18, 0x4E);
+	svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+
+	vga_wcrt(NULL, 0x32, 0x00);
+	vga_wcrt(NULL, 0x34, 0x00);
+	vga_wcrt(NULL, 0x6A, 0x80);
+	vga_wcrt(NULL, 0x6A, 0xC0);
+
+	vga_wgfx(NULL, 0x20, 0x00);
+	vga_wgfx(NULL, 0x21, 0x00);
+	vga_wgfx(NULL, 0x22, 0x00);
+
+	/* Set SR15 according to number of bits per pixel */
+	mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
+	switch (mode) {
+	case 0:
+		pr_debug("fb%d: text mode\n", info->node);
+		svga_set_textmode_vga_regs();
+		svga_wseq_mask(0x15, 0x00, 0xFE);
+		svga_wcrt_mask(0x11, 0x60, 0x70);
+		break;
+	case 1:
+		pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+		vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+		svga_wseq_mask(0x15, 0x20, 0xFE);
+		svga_wcrt_mask(0x11, 0x00, 0x70);
+		break;
+	case 2:
+		pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+		svga_wseq_mask(0x15, 0x00, 0xFE);
+		svga_wcrt_mask(0x11, 0x00, 0x70);
+		break;
+	case 3:
+		pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+		svga_wseq_mask(0x15, 0x22, 0xFE);
+		break;
+	case 4:
+		pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+		svga_wseq_mask(0x15, 0xB6, 0xFE);
+		break;
+	case 5:
+		pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+		svga_wseq_mask(0x15, 0xAE, 0xFE);
+		break;
+	default:
+		printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
+		return (-EINVAL);
+	}
+
+	vt8623_set_pixclock(info, info->var.pixclock);
+	svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+			 (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
+			 1, info->node);
+
+	memset_io(info->screen_base, 0x00, screen_size);
+
+	/* Device and screen back on */
+	svga_wcrt_mask(0x17, 0x80, 0x80);
+	svga_wcrt_mask(0x36, 0x00, 0x30);
+	svga_wseq_mask(0x01, 0x00, 0x20);
+
+	return 0;
+}
+
+
+static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+				u_int transp, struct fb_info *fb)
+{
+	switch (fb->var.bits_per_pixel) {
+	case 0:
+	case 4:
+		if (regno >= 16)
+			return -EINVAL;
+
+		outb(0x0F, VGA_PEL_MSK);
+		outb(regno, VGA_PEL_IW);
+		outb(red >> 10, VGA_PEL_D);
+		outb(green >> 10, VGA_PEL_D);
+		outb(blue >> 10, VGA_PEL_D);
+		break;
+	case 8:
+		if (regno >= 256)
+			return -EINVAL;
+
+		outb(0xFF, VGA_PEL_MSK);
+		outb(regno, VGA_PEL_IW);
+		outb(red >> 10, VGA_PEL_D);
+		outb(green >> 10, VGA_PEL_D);
+		outb(blue >> 10, VGA_PEL_D);
+		break;
+	case 16:
+		if (regno >= 16)
+			return 0;
+
+		if (fb->var.green.length == 5)
+			((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+				((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+		else if (fb->var.green.length == 6)
+			((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+				((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+		else
+			return -EINVAL;
+		break;
+	case 24:
+	case 32:
+		if (regno >= 16)
+			return 0;
+
+		/* ((transp & 0xFF00) << 16) */
+		((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+			(green & 0xFF00) | ((blue & 0xFF00) >> 8);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int vt8623fb_blank(int blank_mode, struct fb_info *info)
+{
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		pr_debug("fb%d: unblank\n", info->node);
+		svga_wcrt_mask(0x36, 0x00, 0x30);
+		svga_wseq_mask(0x01, 0x00, 0x20);
+		break;
+	case FB_BLANK_NORMAL:
+		pr_debug("fb%d: blank\n", info->node);
+		svga_wcrt_mask(0x36, 0x00, 0x30);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
+		svga_wcrt_mask(0x36, 0x10, 0x30);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
+		svga_wcrt_mask(0x36, 0x20, 0x30);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		break;
+	case FB_BLANK_POWERDOWN:
+		pr_debug("fb%d: DPMS off (no sync)\n", info->node);
+		svga_wcrt_mask(0x36, 0x30, 0x30);
+		svga_wseq_mask(0x01, 0x20, 0x20);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	unsigned int offset;
+
+	/* Calculate the offset */
+	if (var->bits_per_pixel == 0) {
+		offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+		offset = offset >> 3;
+	} else {
+		offset = (var->yoffset * info->fix.line_length) +
+			 (var->xoffset * var->bits_per_pixel / 8);
+		offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+	}
+
+	/* Set the offset */
+	svga_wcrt_multi(vt8623_start_address_regs, offset);
+
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops vt8623fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= vt8623fb_open,
+	.fb_release	= vt8623fb_release,
+	.fb_check_var	= vt8623fb_check_var,
+	.fb_set_par	= vt8623fb_set_par,
+	.fb_setcolreg	= vt8623fb_setcolreg,
+	.fb_blank	= vt8623fb_blank,
+	.fb_pan_display	= vt8623fb_pan_display,
+	.fb_fillrect	= vt8623fb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= vt8623fb_imageblit,
+	.fb_get_caps    = svga_get_caps,
+};
+
+
+/* PCI probe */
+
+static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct fb_info *info;
+	struct vt8623fb_info *par;
+	unsigned int memsize1, memsize2;
+	int rc;
+
+	/* Ignore secondary VGA device because there is no VGA arbitration */
+	if (! svga_primary_device(dev)) {
+		dev_info(&(dev->dev), "ignoring secondary device\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and fill driver data structure */
+	info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+	if (! info) {
+		dev_err(&(dev->dev), "cannot allocate memory\n");
+		return -ENOMEM;
+	}
+
+	par = info->par;
+	mutex_init(&par->open_lock);
+
+	info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+	info->fbops = &vt8623fb_ops;
+
+	/* Prepare PCI device */
+
+	rc = pci_enable_device(dev);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot enable PCI device\n");
+		goto err_enable_device;
+	}
+
+	rc = pci_request_regions(dev, "vt8623fb");
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+		goto err_request_regions;
+	}
+
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = pci_resource_len(dev, 0);
+	info->fix.mmio_start = pci_resource_start(dev, 1);
+	info->fix.mmio_len = pci_resource_len(dev, 1);
+
+	/* Map physical IO memory address into kernel space */
+	info->screen_base = pci_iomap(dev, 0, 0);
+	if (! info->screen_base) {
+		rc = -ENOMEM;
+		dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+		goto err_iomap_1;
+	}
+
+	par->mmio_base = pci_iomap(dev, 1, 0);
+	if (! par->mmio_base) {
+		rc = -ENOMEM;
+		dev_err(&(dev->dev), "iomap for MMIO failed\n");
+		goto err_iomap_2;
+	}
+
+	/* Find how many physical memory there is on card */
+	memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
+	memsize2 = vga_rseq(NULL, 0x39) << 2;
+
+	if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
+		info->screen_size = memsize1 << 20;
+	else {
+		dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+		info->screen_size = 16 << 20;
+	}
+
+	info->fix.smem_len = info->screen_size;
+	strcpy(info->fix.id, "VIA VT8623");
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	info->fix.ypanstep = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->pseudo_palette = (void*)par->pseudo_palette;
+
+	/* Prepare startup mode */
+
+	rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+	if (! ((rc == 1) || (rc == 2))) {
+		rc = -EINVAL;
+		dev_err(&(dev->dev), "mode %s not found\n", mode);
+		goto err_find_mode;
+	}
+
+	rc = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot allocate colormap\n");
+		goto err_alloc_cmap;
+	}
+
+	rc = register_framebuffer(info);
+	if (rc < 0) {
+		dev_err(&(dev->dev), "cannot register framebugger\n");
+		goto err_reg_fb;
+	}
+
+	printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+		 pci_name(dev), info->fix.smem_len >> 20);
+
+	/* Record a reference to the driver data */
+	pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		par->mtrr_reg = -1;
+		par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+	}
+#endif
+
+	return 0;
+
+	/* Error handling */
+err_reg_fb:
+	fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+	pci_iounmap(dev, par->mmio_base);
+err_iomap_2:
+	pci_iounmap(dev, info->screen_base);
+err_iomap_1:
+	pci_release_regions(dev);
+err_request_regions:
+/*	pci_disable_device(dev); */
+err_enable_device:
+	framebuffer_release(info);
+	return rc;
+}
+
+/* PCI remove */
+
+static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct vt8623fb_info *par = info->par;
+
+	if (info) {
+#ifdef CONFIG_MTRR
+		if (par->mtrr_reg >= 0) {
+			mtrr_del(par->mtrr_reg, 0, 0);
+			par->mtrr_reg = -1;
+		}
+#endif
+
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+
+		pci_iounmap(dev, info->screen_base);
+		pci_iounmap(dev, par->mmio_base);
+		pci_release_regions(dev);
+/*		pci_disable_device(dev); */
+
+		pci_set_drvdata(dev, NULL);
+		framebuffer_release(info);
+	}
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct vt8623fb_info *par = info->par;
+
+	dev_info(&(dev->dev), "suspend\n");
+
+	acquire_console_sem();
+	mutex_lock(&(par->open_lock));
+
+	if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+		mutex_unlock(&(par->open_lock));
+		release_console_sem();
+		return 0;
+	}
+
+	fb_set_suspend(info, 1);
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	mutex_unlock(&(par->open_lock));
+	release_console_sem();
+
+	return 0;
+}
+
+
+/* PCI resume */
+
+static int vt8623_pci_resume(struct pci_dev* dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct vt8623fb_info *par = info->par;
+
+	dev_info(&(dev->dev), "resume\n");
+
+	acquire_console_sem();
+	mutex_lock(&(par->open_lock));
+
+	if (par->ref_count == 0) {
+		mutex_unlock(&(par->open_lock));
+		release_console_sem();
+		return 0;
+	}
+
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+
+	if (pci_enable_device(dev))
+		goto fail;
+
+	pci_set_master(dev);
+
+	vt8623fb_set_par(info);
+	fb_set_suspend(info, 0);
+
+	mutex_unlock(&(par->open_lock));
+fail:
+	release_console_sem();
+
+	return 0;
+}
+#else
+#define vt8623_pci_suspend NULL
+#define vt8623_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id vt8623_devices[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
+	{0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, vt8623_devices);
+
+static struct pci_driver vt8623fb_pci_driver = {
+	.name		= "vt8623fb",
+	.id_table	= vt8623_devices,
+	.probe		= vt8623_pci_probe,
+	.remove		= __devexit_p(vt8623_pci_remove),
+	.suspend	= vt8623_pci_suspend,
+	.resume		= vt8623_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit vt8623fb_cleanup(void)
+{
+	pr_debug("vt8623fb: cleaning up\n");
+	pci_unregister_driver(&vt8623fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+int __init vt8623fb_init(void)
+{
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("vt8623fb", &option))
+		return -ENODEV;
+
+	if (option && *option)
+		mode = option;
+#endif
+
+	pr_debug("vt8623fb: initializing\n");
+	return pci_register_driver(&vt8623fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(vt8623fb_init);
+module_exit(vt8623fb_cleanup);
diff --git a/fs/Kconfig b/fs/Kconfig
index 4622dab..0fa0c11 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -724,10 +724,6 @@
 	  file system and use GNU tar's M option. GNU tar is a program
 	  available for Unix and DOS ("man tar" or "info tar").
 
-	  It is now also becoming possible to read and write compressed FAT
-	  file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
-	  details.
-
 	  The FAT support will enlarge your kernel by about 37 KB. If unsure,
 	  say Y.
 
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 4aa8079..c879690 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -628,11 +628,7 @@
 			return err;
 	}
 	if (to < PAGE_CACHE_SIZE) {
-		char *kaddr = kmap_atomic(page, KM_USER0);
-
-		memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0);
 		if (size > offset + to) {
 			if (size < offset + PAGE_CACHE_SIZE)
 				tmp = size & ~PAGE_CACHE_MASK;
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index cf83e5d..73ce561 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -22,6 +22,7 @@
 	vlclient.o \
 	vlocation.o \
 	vnode.o \
-	volume.o
+	volume.o \
+	write.o
 
 obj-$(CONFIG_AFS_FS)  := kafs.o
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index 89e0d16..2198006 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -18,6 +18,8 @@
 enum AFS_FS_Operations {
 	FSFETCHDATA		= 130,	/* AFS Fetch file data */
 	FSFETCHSTATUS		= 132,	/* AFS Fetch file status */
+	FSSTOREDATA		= 133,	/* AFS Store file data */
+	FSSTORESTATUS		= 135,	/* AFS Store file status */
 	FSREMOVEFILE		= 136,	/* AFS Remove a file */
 	FSCREATEFILE		= 137,	/* AFS Create a file */
 	FSRENAME		= 138,	/* AFS Rename or move a file or directory */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 9bdbf36..f64e40f 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -44,7 +44,7 @@
 	while (!RB_EMPTY_ROOT(&server->cb_promises)) {
 		vnode = rb_entry(server->cb_promises.rb_node,
 				 struct afs_vnode, cb_promise);
-		_debug("UNPROMISE { vid=%x vn=%u uq=%u}",
+		_debug("UNPROMISE { vid=%x:%u uq=%u}",
 		       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 		rb_erase(&vnode->cb_promise, &server->cb_promises);
 		vnode->cb_promised = false;
@@ -84,11 +84,8 @@
 
 		/* if the vnode's data version number changed then its contents
 		 * are different */
-		if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-			_debug("zap data {%x:%u}",
-			       vnode->fid.vid, vnode->fid.vnode);
-			invalidate_remote_inode(&vnode->vfs_inode);
-		}
+		if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+			afs_zap_data(vnode);
 	}
 
 out:
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 0c1e902..2fb3127 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -55,7 +55,8 @@
 	.rmdir		= afs_rmdir,
 	.rename		= afs_rename,
 	.permission	= afs_permission,
-	.getattr	= afs_inode_getattr,
+	.getattr	= afs_getattr,
+	.setattr	= afs_setattr,
 };
 
 static struct dentry_operations afs_fs_dentry_operations = {
@@ -491,7 +492,7 @@
 
 	vnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},%p{%s},",
+	_enter("{%x:%u},%p{%s},",
 	       vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
 
 	ASSERTCMP(dentry->d_inode, ==, NULL);
@@ -731,7 +732,7 @@
 
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%s},%o",
+	_enter("{%x:%u},{%s},%o",
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
 	ret = -ENAMETOOLONG;
@@ -796,7 +797,7 @@
 
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%s}",
+	_enter("{%x:%u},{%s}",
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
@@ -842,7 +843,7 @@
 
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%s}",
+	_enter("{%x:%u},{%s}",
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
 	ret = -ENAMETOOLONG;
@@ -916,7 +917,7 @@
 
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%s},%o,",
+	_enter("{%x:%u},{%s},%o,",
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
 	ret = -ENAMETOOLONG;
@@ -983,7 +984,7 @@
 	vnode = AFS_FS_I(from->d_inode);
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%x:%d},{%s}",
+	_enter("{%x:%u},{%x:%u},{%s}",
 	       vnode->fid.vid, vnode->fid.vnode,
 	       dvnode->fid.vid, dvnode->fid.vnode,
 	       dentry->d_name.name);
@@ -1032,7 +1033,7 @@
 
 	dvnode = AFS_FS_I(dir);
 
-	_enter("{%x:%d},{%s},%s",
+	_enter("{%x:%u},{%s},%s",
 	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
 	       content);
 
@@ -1104,7 +1105,7 @@
 	orig_dvnode = AFS_FS_I(old_dir);
 	new_dvnode = AFS_FS_I(new_dir);
 
-	_enter("{%x:%d},{%x:%d},{%x:%d},{%s}",
+	_enter("{%x:%u},{%x:%u},{%x:%u},{%s}",
 	       orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
 	       vnode->fid.vid, vnode->fid.vnode,
 	       new_dvnode->fid.vid, new_dvnode->fid.vnode,
diff --git a/fs/afs/file.c b/fs/afs/file.c
index ae25649..3e25795 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -15,32 +15,43 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/writeback.h>
 #include "internal.h"
 
-static int afs_file_readpage(struct file *file, struct page *page);
-static void afs_file_invalidatepage(struct page *page, unsigned long offset);
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_readpage(struct file *file, struct page *page);
+static void afs_invalidatepage(struct page *page, unsigned long offset);
+static int afs_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_launder_page(struct page *page);
 
 const struct file_operations afs_file_operations = {
 	.open		= afs_open,
 	.release	= afs_release,
 	.llseek		= generic_file_llseek,
 	.read		= do_sync_read,
+	.write		= do_sync_write,
 	.aio_read	= generic_file_aio_read,
+	.aio_write	= afs_file_write,
 	.mmap		= generic_file_readonly_mmap,
 	.sendfile	= generic_file_sendfile,
+	.fsync		= afs_fsync,
 };
 
 const struct inode_operations afs_file_inode_operations = {
-	.getattr	= afs_inode_getattr,
+	.getattr	= afs_getattr,
+	.setattr	= afs_setattr,
 	.permission	= afs_permission,
 };
 
 const struct address_space_operations afs_fs_aops = {
-	.readpage	= afs_file_readpage,
-	.set_page_dirty	= __set_page_dirty_nobuffers,
-	.releasepage	= afs_file_releasepage,
-	.invalidatepage	= afs_file_invalidatepage,
+	.readpage	= afs_readpage,
+	.set_page_dirty	= afs_set_page_dirty,
+	.launder_page	= afs_launder_page,
+	.releasepage	= afs_releasepage,
+	.invalidatepage	= afs_invalidatepage,
+	.prepare_write	= afs_prepare_write,
+	.commit_write	= afs_commit_write,
+	.writepage	= afs_writepage,
+	.writepages	= afs_writepages,
 };
 
 /*
@@ -52,7 +63,7 @@
 	struct key *key;
 	int ret;
 
-	_enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
 
 	key = afs_request_key(vnode->volume->cell);
 	if (IS_ERR(key)) {
@@ -78,7 +89,7 @@
 {
 	struct afs_vnode *vnode = AFS_FS_I(inode);
 
-	_enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
 
 	key_put(file->private_data);
 	_leave(" = 0");
@@ -89,10 +100,10 @@
  * deal with notification that a page was read from the cache
  */
 #ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_read_complete(void *cookie_data,
-					    struct page *page,
-					    void *data,
-					    int error)
+static void afs_readpage_read_complete(void *cookie_data,
+				       struct page *page,
+				       void *data,
+				       int error)
 {
 	_enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
@@ -109,10 +120,10 @@
  * deal with notification that a page was written to the cache
  */
 #ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_write_complete(void *cookie_data,
-					     struct page *page,
-					     void *data,
-					     int error)
+static void afs_readpage_write_complete(void *cookie_data,
+					struct page *page,
+					void *data,
+					int error)
 {
 	_enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
@@ -121,9 +132,9 @@
 #endif
 
 /*
- * AFS read page from file (or symlink)
+ * AFS read page from file, directory or symlink
  */
-static int afs_file_readpage(struct file *file, struct page *page)
+static int afs_readpage(struct file *file, struct page *page)
 {
 	struct afs_vnode *vnode;
 	struct inode *inode;
@@ -219,39 +230,17 @@
 }
 
 /*
- * get a page cookie for the specified page
- */
-#ifdef AFS_CACHING_SUPPORT
-int afs_cache_get_page_cookie(struct page *page,
-			      struct cachefs_page **_page_cookie)
-{
-	int ret;
-
-	_enter("");
-	ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
-
-	_leave(" = %d", ret);
-	return ret;
-}
-#endif
-
-/*
  * invalidate part or all of a page
  */
-static void afs_file_invalidatepage(struct page *page, unsigned long offset)
+static void afs_invalidatepage(struct page *page, unsigned long offset)
 {
 	int ret = 1;
 
-	_enter("{%lu},%lu", page->index, offset);
+	kenter("{%lu},%lu", page->index, offset);
 
 	BUG_ON(!PageLocked(page));
 
 	if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
-		struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-		cachefs_uncache_page(vnode->cache,page);
-#endif
-
 		/* We release buffers only if the entire page is being
 		 * invalidated.
 		 * The get_block cached value has been unconditionally
@@ -272,25 +261,33 @@
 }
 
 /*
+ * write back a dirty page
+ */
+static int afs_launder_page(struct page *page)
+{
+	_enter("{%lu}", page->index);
+
+	return 0;
+}
+
+/*
  * release a page and cleanup its private data
  */
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
+static int afs_releasepage(struct page *page, gfp_t gfp_flags)
 {
-	struct cachefs_page *pageio;
+	struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+	struct afs_writeback *wb;
 
-	_enter("{%lu},%x", page->index, gfp_flags);
+	_enter("{{%x:%u}[%lu],%lx},%x",
+	       vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
+	       gfp_flags);
 
 	if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
-		struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-		cachefs_uncache_page(vnode->cache, page);
-#endif
-
-		pageio = (struct cachefs_page *) page_private(page);
+		wb = (struct afs_writeback *) page_private(page);
+		ASSERT(wb != NULL);
 		set_page_private(page, 0);
 		ClearPagePrivate(page);
-
-		kfree(pageio);
+		afs_put_writeback(wb);
 	}
 
 	_leave(" = 0");
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index e54e6c2..025b190 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -33,8 +33,10 @@
  */
 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
 				      struct afs_file_status *status,
-				      struct afs_vnode *vnode)
+				      struct afs_vnode *vnode,
+				      afs_dataversion_t *store_version)
 {
+	afs_dataversion_t expected_version;
 	const __be32 *bp = *_bp;
 	umode_t mode;
 	u64 data_version, size;
@@ -101,7 +103,11 @@
 		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime;
 	}
 
-	if (status->data_version != data_version) {
+	expected_version = status->data_version;
+	if (store_version)
+		expected_version = *store_version;
+
+	if (expected_version != data_version) {
 		status->data_version = data_version;
 		if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
 			_debug("vnode modified %llx on {%x:%u}",
@@ -110,6 +116,8 @@
 			set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
 			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
 		}
+	} else if (store_version) {
+		status->data_version = data_version;
 	}
 }
 
@@ -156,6 +164,44 @@
 }
 
 /*
+ * encode the requested attributes into an AFSStoreStatus block
+ */
+static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
+{
+	__be32 *bp = *_bp;
+	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
+
+	mask = 0;
+	if (attr->ia_valid & ATTR_MTIME) {
+		mask |= AFS_SET_MTIME;
+		mtime = attr->ia_mtime.tv_sec;
+	}
+
+	if (attr->ia_valid & ATTR_UID) {
+		mask |= AFS_SET_OWNER;
+		owner = attr->ia_uid;
+	}
+
+	if (attr->ia_valid & ATTR_GID) {
+		mask |= AFS_SET_GROUP;
+		group = attr->ia_gid;
+	}
+
+	if (attr->ia_valid & ATTR_MODE) {
+		mask |= AFS_SET_MODE;
+		mode = attr->ia_mode & S_IALLUGO;
+	}
+
+	*bp++ = htonl(mask);
+	*bp++ = htonl(mtime);
+	*bp++ = htonl(owner);
+	*bp++ = htonl(group);
+	*bp++ = htonl(mode);
+	*bp++ = 0;		/* segment size */
+	*_bp = bp;
+}
+
+/*
  * deliver reply data to an FS.FetchStatus
  */
 static int afs_deliver_fs_fetch_status(struct afs_call *call,
@@ -175,7 +221,7 @@
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
 	xdr_decode_AFSCallBack(&bp, vnode);
 	if (call->reply2)
 		xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -206,7 +252,7 @@
 	struct afs_call *call;
 	__be32 *bp;
 
-	_enter(",%x,{%x:%d},,",
+	_enter(",%x,{%x:%u},,",
 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
 
 	call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
@@ -265,25 +311,20 @@
 		call->offset = 0;
 		call->unmarshall++;
 
-		if (call->count < PAGE_SIZE) {
-			page = call->reply3;
-			buffer = kmap_atomic(page, KM_USER0);
-			memset(buffer + PAGE_SIZE - call->count, 0,
-			       call->count);
-			kunmap_atomic(buffer, KM_USER0);
-		}
-
 		/* extract the returned data */
 	case 2:
 		_debug("extract data");
-		page = call->reply3;
-		buffer = kmap_atomic(page, KM_USER0);
-		ret = afs_extract_data(call, skb, last, buffer, call->count);
-		kunmap_atomic(buffer, KM_USER0);
-		switch (ret) {
-		case 0:		break;
-		case -EAGAIN:	return 0;
-		default:	return ret;
+		if (call->count > 0) {
+			page = call->reply3;
+			buffer = kmap_atomic(page, KM_USER0);
+			ret = afs_extract_data(call, skb, last, buffer,
+					       call->count);
+			kunmap_atomic(buffer, KM_USER0);
+			switch (ret) {
+			case 0:		break;
+			case -EAGAIN:	return 0;
+			default:	return ret;
+			}
 		}
 
 		call->offset = 0;
@@ -300,7 +341,7 @@
 		}
 
 		bp = call->buffer;
-		xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+		xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
 		xdr_decode_AFSCallBack(&bp, vnode);
 		if (call->reply2)
 			xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -318,6 +359,14 @@
 	if (!last)
 		return 0;
 
+	if (call->count < PAGE_SIZE) {
+		_debug("clear");
+		page = call->reply3;
+		buffer = kmap_atomic(page, KM_USER0);
+		memset(buffer + call->count, 0, PAGE_SIZE - call->count);
+		kunmap_atomic(buffer, KM_USER0);
+	}
+
 	_leave(" = 0 [done]");
 	return 0;
 }
@@ -476,8 +525,8 @@
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
 	xdr_decode_AFSFid(&bp, call->reply2);
-	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
-	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
 	xdr_decode_AFSCallBack_raw(&bp, call->reply4);
 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
@@ -574,7 +623,7 @@
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
 	_leave(" = 0 [done]");
@@ -657,8 +706,8 @@
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
-	xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
+	xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
 	_leave(" = 0 [done]");
@@ -746,8 +795,8 @@
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
 	xdr_decode_AFSFid(&bp, call->reply2);
-	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
-	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
 	_leave(" = 0 [done]");
@@ -852,9 +901,10 @@
 
 	/* unmarshall the reply once we've received all of it */
 	bp = call->buffer;
-	xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
+	xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
 	if (new_dvnode != orig_dvnode)
-		xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
+		xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
+					  NULL);
 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
 	_leave(" = 0 [done]");
@@ -936,3 +986,262 @@
 
 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 }
+
+/*
+ * deliver reply data to an FS.StoreData
+ */
+static int afs_deliver_fs_store_data(struct afs_call *call,
+				     struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
+
+	_enter(",,%u", last);
+
+	afs_transfer_reply(call, skb);
+	if (!last) {
+		_leave(" = 0 [more]");
+		return 0;
+	}
+
+	if (call->reply_size != call->reply_max) {
+		_leave(" = -EBADMSG [%u != %u]",
+		       call->reply_size, call->reply_max);
+		return -EBADMSG;
+	}
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
+				  &call->store_version);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	afs_pages_written_back(vnode, call);
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.StoreData operation type
+ */
+static const struct afs_call_type afs_RXFSStoreData = {
+	.name		= "FS.StoreData",
+	.deliver	= afs_deliver_fs_store_data,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * store a set of pages
+ */
+int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
+		      pgoff_t first, pgoff_t last,
+		      unsigned offset, unsigned to,
+		      const struct afs_wait_mode *wait_mode)
+{
+	struct afs_vnode *vnode = wb->vnode;
+	struct afs_call *call;
+	loff_t size, pos, i_size;
+	__be32 *bp;
+
+	_enter(",%x,{%x:%u},,",
+	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+
+	size = to - offset;
+	if (first != last)
+		size += (loff_t)(last - first) << PAGE_SHIFT;
+	pos = (loff_t)first << PAGE_SHIFT;
+	pos += offset;
+
+	i_size = i_size_read(&vnode->vfs_inode);
+	if (pos + size > i_size)
+		i_size = size + pos;
+
+	_debug("size %llx, at %llx, i_size %llx",
+	       (unsigned long long) size, (unsigned long long) pos,
+	       (unsigned long long) i_size);
+
+	BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store
+
+	call = afs_alloc_flat_call(&afs_RXFSStoreData,
+				   (4 + 6 + 3) * 4,
+				   (21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->wb = wb;
+	call->key = wb->key;
+	call->reply = vnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+	call->mapping = vnode->vfs_inode.i_mapping;
+	call->first = first;
+	call->last = last;
+	call->first_offset = offset;
+	call->last_to = to;
+	call->send_pages = true;
+	call->store_version = vnode->status.data_version + 1;
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(FSSTOREDATA);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+
+	*bp++ = 0; /* mask */
+	*bp++ = 0; /* mtime */
+	*bp++ = 0; /* owner */
+	*bp++ = 0; /* group */
+	*bp++ = 0; /* unix mode */
+	*bp++ = 0; /* segment size */
+
+	*bp++ = htonl(pos);
+	*bp++ = htonl(size);
+	*bp++ = htonl(i_size);
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * deliver reply data to an FS.StoreStatus
+ */
+static int afs_deliver_fs_store_status(struct afs_call *call,
+				       struct sk_buff *skb, bool last)
+{
+	afs_dataversion_t *store_version;
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
+
+	_enter(",,%u", last);
+
+	afs_transfer_reply(call, skb);
+	if (!last) {
+		_leave(" = 0 [more]");
+		return 0;
+	}
+
+	if (call->reply_size != call->reply_max) {
+		_leave(" = -EBADMSG [%u != %u]",
+		       call->reply_size, call->reply_max);
+		return -EBADMSG;
+	}
+
+	/* unmarshall the reply once we've received all of it */
+	store_version = NULL;
+	if (call->operation_ID == FSSTOREDATA)
+		store_version = &call->store_version;
+
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.StoreStatus operation type
+ */
+static const struct afs_call_type afs_RXFSStoreStatus = {
+	.name		= "FS.StoreStatus",
+	.deliver	= afs_deliver_fs_store_status,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSStoreData_as_Status = {
+	.name		= "FS.StoreData",
+	.deliver	= afs_deliver_fs_store_status,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
+ * so as to alter the file size also
+ */
+static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
+			       struct afs_vnode *vnode, struct iattr *attr,
+			       const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	__be32 *bp;
+
+	_enter(",%x,{%x:%u},,",
+	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+	ASSERT(attr->ia_valid & ATTR_SIZE);
+	ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store
+
+	call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
+				   (4 + 6 + 3) * 4,
+				   (21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->key = key;
+	call->reply = vnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+	call->store_version = vnode->status.data_version + 1;
+	call->operation_ID = FSSTOREDATA;
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(FSSTOREDATA);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+
+	xdr_encode_AFS_StoreStatus(&bp, attr);
+
+	*bp++ = 0;				/* position of start of write */
+	*bp++ = 0;				/* size of write */
+	*bp++ = htonl(attr->ia_size);		/* new file length */
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * set the attributes on a file, using FS.StoreData if there's a change in file
+ * size, and FS.StoreStatus otherwise
+ */
+int afs_fs_setattr(struct afs_server *server, struct key *key,
+		   struct afs_vnode *vnode, struct iattr *attr,
+		   const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	__be32 *bp;
+
+	if (attr->ia_valid & ATTR_SIZE)
+		return afs_fs_setattr_size(server, key, vnode, attr,
+					   wait_mode);
+
+	_enter(",%x,{%x:%u},,",
+	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+	call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
+				   (4 + 6) * 4,
+				   (21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->key = key;
+	call->reply = vnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+	call->operation_ID = FSSTORESTATUS;
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(FSSTORESTATUS);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+
+	xdr_encode_AFS_StoreStatus(&bp, attr);
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index c184a4e..515a5d1 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -125,7 +125,7 @@
 	struct inode *inode;
 	int ret;
 
-	_enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique);
+	_enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique);
 
 	as = sb->s_fs_info;
 	data.volume = as->volume;
@@ -204,6 +204,19 @@
 }
 
 /*
+ * mark the data attached to an inode as obsolete due to a write on the server
+ * - might also want to ditch all the outstanding writes and dirty pages
+ */
+void afs_zap_data(struct afs_vnode *vnode)
+{
+	_enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+	/* nuke all the non-dirty pages that aren't locked, mapped or being
+	 * written back */
+	invalidate_remote_inode(&vnode->vfs_inode);
+}
+
+/*
  * validate a vnode/inode
  * - there are several things we need to check
  *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
@@ -258,10 +271,8 @@
 
 	/* if the vnode's data version number changed then its contents are
 	 * different */
-	if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-		_debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
-		invalidate_remote_inode(&vnode->vfs_inode);
-	}
+	if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+		afs_zap_data(vnode);
 
 	clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
 	mutex_unlock(&vnode->validate_lock);
@@ -278,7 +289,7 @@
 /*
  * read the attributes of an inode
  */
-int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
+int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		      struct kstat *stat)
 {
 	struct inode *inode;
@@ -301,7 +312,7 @@
 
 	vnode = AFS_FS_I(inode);
 
-	_enter("{%x:%d.%d} v=%u x=%u t=%u }",
+	_enter("{%x:%u.%d} v=%u x=%u t=%u }",
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
 	       vnode->fid.unique,
@@ -323,6 +334,7 @@
 		vnode->server = NULL;
 	}
 
+	ASSERT(list_empty(&vnode->writebacks));
 	ASSERT(!vnode->cb_promised);
 
 #ifdef AFS_CACHING_SUPPORT
@@ -339,3 +351,47 @@
 
 	_leave("");
 }
+
+/*
+ * set the attributes of an inode
+ */
+int afs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+	struct key *key;
+	int ret;
+
+	_enter("{%x:%u},{n=%s},%x",
+	       vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+	       attr->ia_valid);
+
+	if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
+				ATTR_MTIME))) {
+		_leave(" = 0 [unsupported]");
+		return 0;
+	}
+
+	/* flush any dirty data outstanding on a regular file */
+	if (S_ISREG(vnode->vfs_inode.i_mode)) {
+		filemap_write_and_wait(vnode->vfs_inode.i_mapping);
+		afs_writeback_all(vnode);
+	}
+
+	if (attr->ia_valid & ATTR_FILE) {
+		key = attr->ia_file->private_data;
+	} else {
+		key = afs_request_key(vnode->volume->cell);
+		if (IS_ERR(key)) {
+			ret = PTR_ERR(key);
+			goto error;
+		}
+	}
+
+	ret = afs_vnode_setattr(vnode, key, attr);
+	if (!(attr->ia_valid & ATTR_FILE))
+		key_put(key);
+
+error:
+	_leave(" = %d", ret);
+	return ret;
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index d90c158..a30d4fa 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -21,6 +21,7 @@
 
 #define AFS_CELL_MAX_ADDRS 15
 
+struct pagevec;
 struct afs_call;
 
 typedef enum {
@@ -75,12 +76,15 @@
 	struct key		*key;		/* security for this call */
 	struct afs_server	*server;	/* server affected by incoming CM call */
 	void			*request;	/* request data (first part) */
-	void			*request2;	/* request data (second part) */
+	struct address_space	*mapping;	/* page set */
+	struct afs_writeback	*wb;		/* writeback being performed */
 	void			*buffer;	/* reply receive buffer */
 	void			*reply;		/* reply buffer (first part) */
 	void			*reply2;	/* reply buffer (second part) */
 	void			*reply3;	/* reply buffer (third part) */
 	void			*reply4;	/* reply buffer (fourth part) */
+	pgoff_t			first;		/* first page in mapping to deal with */
+	pgoff_t			last;		/* last page in mapping to deal with */
 	enum {					/* call state */
 		AFS_CALL_REQUESTING,	/* request is being sent for outgoing call */
 		AFS_CALL_AWAIT_REPLY,	/* awaiting reply to outgoing call */
@@ -97,14 +101,18 @@
 	unsigned		request_size;	/* size of request data */
 	unsigned		reply_max;	/* maximum size of reply */
 	unsigned		reply_size;	/* current size of reply */
+	unsigned		first_offset;	/* offset into mapping[first] */
+	unsigned		last_to;	/* amount of mapping[last] */
 	unsigned short		offset;		/* offset into received data store */
 	unsigned char		unmarshall;	/* unmarshalling phase */
 	bool			incoming;	/* T if incoming call */
+	bool			send_pages;	/* T if data from mapping should be sent */
 	u16			service_id;	/* RxRPC service ID to call */
 	__be16			port;		/* target UDP port */
 	__be32			operation_ID;	/* operation ID for an incoming call */
 	u32			count;		/* count for use in unmarshalling */
 	__be32			tmp;		/* place to extract temporary data */
+	afs_dataversion_t	store_version;	/* updated version expected from store */
 };
 
 struct afs_call_type {
@@ -124,6 +132,32 @@
 };
 
 /*
+ * record of an outstanding writeback on a vnode
+ */
+struct afs_writeback {
+	struct list_head	link;		/* link in vnode->writebacks */
+	struct work_struct	writer;		/* work item to perform the writeback */
+	struct afs_vnode	*vnode;		/* vnode to which this write applies */
+	struct key		*key;		/* owner of this write */
+	wait_queue_head_t	waitq;		/* completion and ready wait queue */
+	pgoff_t			first;		/* first page in batch */
+	pgoff_t			point;		/* last page in current store op */
+	pgoff_t			last;		/* last page in batch (inclusive) */
+	unsigned		offset_first;	/* offset into first page of start of write */
+	unsigned		to_last;	/* offset into last page of end of write */
+	int			num_conflicts;	/* count of conflicting writes in list */
+	int			usage;
+	bool			conflicts;	/* T if has dependent conflicts */
+	enum {
+		AFS_WBACK_SYNCING,		/* synchronisation being performed */
+		AFS_WBACK_PENDING,		/* write pending */
+		AFS_WBACK_CONFLICTING,		/* conflicting writes posted */
+		AFS_WBACK_WRITING,		/* writing back */
+		AFS_WBACK_COMPLETE		/* the writeback record has been unlinked */
+	} state __attribute__((packed));
+};
+
+/*
  * AFS superblock private data
  * - there's one superblock per volume
  */
@@ -305,6 +339,7 @@
 	wait_queue_head_t	update_waitq;	/* status fetch waitqueue */
 	int			update_cnt;	/* number of outstanding ops that will update the
 						 * status */
+	spinlock_t		writeback_lock;	/* lock for writebacks */
 	spinlock_t		lock;		/* waitqueue/flags lock */
 	unsigned long		flags;
 #define AFS_VNODE_CB_BROKEN	0		/* set if vnode's callback was broken */
@@ -316,6 +351,8 @@
 
 	long			acl_order;	/* ACL check count (callback break count) */
 
+	struct list_head	writebacks;	/* alterations in pagecache that need writing */
+
 	/* outstanding callback notification on this file */
 	struct rb_node		server_rb;	/* link in server->fs_vnodes */
 	struct rb_node		cb_promise;	/* link in server->cb_promises */
@@ -433,10 +470,6 @@
 extern int afs_open(struct inode *, struct file *);
 extern int afs_release(struct inode *, struct file *);
 
-#ifdef AFS_CACHING_SUPPORT
-extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
-#endif
-
 /*
  * fsclient.c
  */
@@ -467,6 +500,12 @@
 			 struct afs_vnode *, const char *,
 			 struct afs_vnode *, const char *,
 			 const struct afs_wait_mode *);
+extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *,
+			     pgoff_t, pgoff_t, unsigned, unsigned,
+			     const struct afs_wait_mode *);
+extern int afs_fs_setattr(struct afs_server *, struct key *,
+			  struct afs_vnode *, struct iattr *,
+			  const struct afs_wait_mode *);
 
 /*
  * inode.c
@@ -474,10 +513,10 @@
 extern struct inode *afs_iget(struct super_block *, struct key *,
 			      struct afs_fid *, struct afs_file_status *,
 			      struct afs_callback *);
+extern void afs_zap_data(struct afs_vnode *);
 extern int afs_validate(struct afs_vnode *, struct key *);
-extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
-			     struct kstat *);
-extern void afs_zap_permits(struct rcu_head *);
+extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int afs_setattr(struct dentry *, struct iattr *);
 extern void afs_clear_inode(struct inode *);
 
 /*
@@ -533,6 +572,7 @@
  */
 extern void afs_clear_permits(struct afs_vnode *);
 extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
+extern void afs_zap_permits(struct rcu_head *);
 extern struct key *afs_request_key(struct afs_cell *);
 extern int afs_permission(struct inode *, int, struct nameidata *);
 
@@ -629,6 +669,9 @@
 			     struct afs_file_status *, struct afs_server **);
 extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
 			    struct key *, const char *, const char *);
+extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
+				unsigned, unsigned);
+extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
 
 /*
  * volume.c
@@ -645,6 +688,23 @@
 extern int afs_volume_release_fileserver(struct afs_vnode *,
 					 struct afs_server *, int);
 
+/*
+ * write.c
+ */
+extern int afs_set_page_dirty(struct page *);
+extern void afs_put_writeback(struct afs_writeback *);
+extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_writepage(struct page *, struct writeback_control *);
+extern int afs_writepages(struct address_space *, struct writeback_control *);
+extern int afs_write_inode(struct inode *, int);
+extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
+extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
+			      unsigned long, loff_t);
+extern int afs_writeback_all(struct afs_vnode *);
+extern int afs_fsync(struct file *, struct dentry *, int);
+
+
 /*****************************************************************************/
 /*
  * debug tracing
@@ -726,6 +786,21 @@
 	}								\
 } while(0)
 
+#define ASSERTRANGE(L, OP1, N, OP2, H)					\
+do {									\
+	if (unlikely(!((L) OP1 (N)) || !((N) OP2 (H)))) {		\
+		printk(KERN_ERR "\n");					\
+		printk(KERN_ERR "AFS: Assertion failed\n");		\
+		printk(KERN_ERR "%lu "#OP1" %lu "#OP2" %lu is false\n",	\
+		       (unsigned long)(L), (unsigned long)(N),		\
+		       (unsigned long)(H));				\
+		printk(KERN_ERR "0x%lx "#OP1" 0x%lx "#OP2" 0x%lx is false\n", \
+		       (unsigned long)(L), (unsigned long)(N),		\
+		       (unsigned long)(H));				\
+		BUG();							\
+	}								\
+} while(0)
+
 #define ASSERTIF(C, X)						\
 do {								\
 	if (unlikely((C) && !(X))) {				\
@@ -758,6 +833,10 @@
 do {						\
 } while(0)
 
+#define ASSERTRANGE(L, OP1, N, OP2, H)		\
+do {						\
+} while(0)
+
 #define ASSERTIF(C, X)				\
 do {						\
 } while(0)
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 80ec6fd..f1f71ff 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -149,6 +149,7 @@
 	afs_vlocation_purge();
 	afs_cell_purge();
 	afs_proc_cleanup();
+	rcu_barrier();
 	printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
 	return ret;
 }
@@ -176,6 +177,7 @@
 	cachefs_unregister_netfs(&afs_cache_netfs);
 #endif
 	afs_proc_cleanup();
+	rcu_barrier();
 }
 
 module_exit(afs_exit);
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index cdb9792..d1a889c 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -22,6 +22,7 @@
 {
 	switch (abort_code) {
 	case 13:		return -EACCES;
+	case 27:		return -EFBIG;
 	case 30:		return -EROFS;
 	case VSALVAGE:		return -EIO;
 	case VNOVNODE:		return -ENOENT;
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 034fcfd..a3684dc 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -36,7 +36,7 @@
 	.lookup		= afs_mntpt_lookup,
 	.follow_link	= afs_mntpt_follow_link,
 	.readlink	= page_readlink,
-	.getattr	= afs_inode_getattr,
+	.getattr	= afs_getattr,
 };
 
 static LIST_HEAD(afs_vfsmounts);
@@ -58,7 +58,8 @@
 	char *buf;
 	int ret;
 
-	_enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique);
+	_enter("{%x:%u,%u}",
+	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
 	/* read the contents of the symlink into the pagecache */
 	page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 222c1a3..04189c4 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -237,6 +237,70 @@
 }
 
 /*
+ * attach the data from a bunch of pages on an inode to a call
+ */
+int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov)
+{
+	struct page *pages[8];
+	unsigned count, n, loop, offset, to;
+	pgoff_t first = call->first, last = call->last;
+	int ret;
+
+	_enter("");
+
+	offset = call->first_offset;
+	call->first_offset = 0;
+
+	do {
+		_debug("attach %lx-%lx", first, last);
+
+		count = last - first + 1;
+		if (count > ARRAY_SIZE(pages))
+			count = ARRAY_SIZE(pages);
+		n = find_get_pages_contig(call->mapping, first, count, pages);
+		ASSERTCMP(n, ==, count);
+
+		loop = 0;
+		do {
+			msg->msg_flags = 0;
+			to = PAGE_SIZE;
+			if (first + loop >= last)
+				to = call->last_to;
+			else
+				msg->msg_flags = MSG_MORE;
+			iov->iov_base = kmap(pages[loop]) + offset;
+			iov->iov_len = to - offset;
+			offset = 0;
+
+			_debug("- range %u-%u%s",
+			       offset, to, msg->msg_flags ? " [more]" : "");
+			msg->msg_iov = (struct iovec *) iov;
+			msg->msg_iovlen = 1;
+
+			/* have to change the state *before* sending the last
+			 * packet as RxRPC might give us the reply before it
+			 * returns from sending the request */
+			if (first + loop >= last)
+				call->state = AFS_CALL_AWAIT_REPLY;
+			ret = rxrpc_kernel_send_data(call->rxcall, msg,
+						     to - offset);
+			kunmap(pages[loop]);
+			if (ret < 0)
+				break;
+		} while (++loop < count);
+		first += count;
+
+		for (loop = 0; loop < count; loop++)
+			put_page(pages[loop]);
+		if (ret < 0)
+			break;
+	} while (first < last);
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
  * initiate a call
  */
 int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
@@ -253,8 +317,9 @@
 	ASSERT(call->type != NULL);
 	ASSERT(call->type->name != NULL);
 
-	_debug("MAKE %p{%s} [%d]",
-	       call, call->type->name, atomic_read(&afs_outstanding_calls));
+	_debug("____MAKE %p{%s,%x} [%d]____",
+	       call, call->type->name, key_serial(call->key),
+	       atomic_read(&afs_outstanding_calls));
 
 	call->wait_mode = wait_mode;
 	INIT_WORK(&call->async_work, afs_process_async_call);
@@ -289,16 +354,23 @@
 	msg.msg_iovlen		= 1;
 	msg.msg_control		= NULL;
 	msg.msg_controllen	= 0;
-	msg.msg_flags		= 0;
+	msg.msg_flags		= (call->send_pages ? MSG_MORE : 0);
 
 	/* have to change the state *before* sending the last packet as RxRPC
 	 * might give us the reply before it returns from sending the
 	 * request */
-	call->state = AFS_CALL_AWAIT_REPLY;
+	if (!call->send_pages)
+		call->state = AFS_CALL_AWAIT_REPLY;
 	ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size);
 	if (ret < 0)
 		goto error_do_abort;
 
+	if (call->send_pages) {
+		ret = afs_send_pages(call, &msg, iov);
+		if (ret < 0)
+			goto error_do_abort;
+	}
+
 	/* at this point, an async call may no longer exist as it may have
 	 * already completed */
 	return wait_mode->wait(call);
diff --git a/fs/afs/security.c b/fs/afs/security.c
index f9f424d..e0ea88b 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -109,7 +109,7 @@
 {
 	struct afs_permits *permits;
 
-	_enter("{%x}", vnode->fid.vnode);
+	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
 
 	mutex_lock(&vnode->permits_lock);
 	permits = vnode->permits;
@@ -132,7 +132,8 @@
 	struct afs_vnode *auth_vnode;
 	int count, loop;
 
-	_enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order);
+	_enter("{%x:%u},%x,%lx",
+	       vnode->fid.vid, vnode->fid.vnode, key_serial(key), acl_order);
 
 	auth_vnode = afs_get_auth_inode(vnode, key);
 	if (IS_ERR(auth_vnode)) {
@@ -220,7 +221,8 @@
 	bool valid;
 	int loop, ret;
 
-	_enter("");
+	_enter("{%x:%u},%x",
+	       vnode->fid.vid, vnode->fid.vnode, key_serial(key));
 
 	auth_vnode = afs_get_auth_inode(vnode, key);
 	if (IS_ERR(auth_vnode)) {
@@ -268,9 +270,9 @@
 			_leave(" = %d", ret);
 			return ret;
 		}
+		*_access = vnode->status.caller_access;
 	}
 
-	*_access = vnode->status.caller_access;
 	iput(&auth_vnode->vfs_inode);
 	_leave(" = 0 [access %x]", *_access);
 	return 0;
@@ -288,7 +290,7 @@
 	struct key *key;
 	int ret;
 
-	_enter("{{%x:%x},%lx},%x,",
+	_enter("{{%x:%u},%lx},%x,",
 	       vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
 
 	key = afs_request_key(vnode->volume->cell);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 96bb23b..231ae41 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -252,6 +252,9 @@
 {
 	_enter("%p", server);
 
+	ASSERTIF(server->cb_break_head != server->cb_break_tail,
+		 delayed_work_pending(&server->cb_break_work));
+
 	ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
 	ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
 	ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 7030d76..d24be33 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -50,6 +50,7 @@
 	.statfs		= simple_statfs,
 	.alloc_inode	= afs_alloc_inode,
 	.drop_inode	= generic_delete_inode,
+	.write_inode	= afs_write_inode,
 	.destroy_inode	= afs_destroy_inode,
 	.clear_inode	= afs_clear_inode,
 	.umount_begin	= afs_umount_begin,
@@ -66,7 +67,7 @@
 	afs_opt_vol,
 };
 
-static const match_table_t afs_options_list = {
+static match_table_t afs_options_list = {
 	{ afs_opt_cell,		"cell=%s"	},
 	{ afs_opt_rwpath,	"rwpath"	},
 	{ afs_opt_vol,		"vol=%s"	},
@@ -459,7 +460,9 @@
 		init_waitqueue_head(&vnode->update_waitq);
 		mutex_init(&vnode->permits_lock);
 		mutex_init(&vnode->validate_lock);
+		spin_lock_init(&vnode->writeback_lock);
 		spin_lock_init(&vnode->lock);
+		INIT_LIST_HEAD(&vnode->writebacks);
 		INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
 	}
 }
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index a1904ab..ec81466 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -261,7 +261,7 @@
 
 	DECLARE_WAITQUEUE(myself, current);
 
-	_enter("%s,{%u,%u,%u}",
+	_enter("%s,{%x:%u.%u}",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
@@ -389,7 +389,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%x,,,",
+	_enter("%s{%x:%u.%u},%x,,,",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
@@ -446,7 +446,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%x,%s,,",
+	_enter("%s{%x:%u.%u},%x,%s,,",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
@@ -502,7 +502,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%x,%s",
+	_enter("%s{%x:%u.%u},%x,%s",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
@@ -557,7 +557,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
+	_enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s",
 	       dvnode->volume->vlocation->vldb.name,
 	       dvnode->fid.vid,
 	       dvnode->fid.vnode,
@@ -628,7 +628,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%x,%s,%s,,,",
+	_enter("%s{%x:%u.%u},%x,%s,%s,,,",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
@@ -687,7 +687,7 @@
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
+	_enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s",
 	       orig_dvnode->volume->vlocation->vldb.name,
 	       orig_dvnode->fid.vid,
 	       orig_dvnode->fid.vnode,
@@ -753,3 +753,110 @@
 	_leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
 	return PTR_ERR(server);
 }
+
+/*
+ * write to a file
+ */
+int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last,
+			 unsigned offset, unsigned to)
+{
+	struct afs_server *server;
+	struct afs_vnode *vnode = wb->vnode;
+	int ret;
+
+	_enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       key_serial(wb->key),
+	       first, last, offset, to);
+
+	/* this op will fetch the status */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_store_data(server, wb, first, last, offset, to,
+					&afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	return PTR_ERR(server);
+}
+
+/*
+ * set the attributes on a file
+ */
+int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key,
+		      struct iattr *attr)
+{
+	struct afs_server *server;
+	int ret;
+
+	_enter("%s{%x:%u.%u},%x",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       key_serial(key));
+
+	/* this op will fetch the status */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	return PTR_ERR(server);
+}
diff --git a/fs/afs/write.c b/fs/afs/write.c
new file mode 100644
index 0000000..83ff292
--- /dev/null
+++ b/fs/afs/write.c
@@ -0,0 +1,835 @@
+/* handling of writes to regular files and writing back to the server
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/pagevec.h>
+#include "internal.h"
+
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+					   struct page *page);
+
+/*
+ * mark a page as having been made dirty and thus needing writeback
+ */
+int afs_set_page_dirty(struct page *page)
+{
+	_enter("");
+	return __set_page_dirty_nobuffers(page);
+}
+
+/*
+ * unlink a writeback record because its usage has reached zero
+ * - must be called with the wb->vnode->writeback_lock held
+ */
+static void afs_unlink_writeback(struct afs_writeback *wb)
+{
+	struct afs_writeback *front;
+	struct afs_vnode *vnode = wb->vnode;
+
+	list_del_init(&wb->link);
+	if (!list_empty(&vnode->writebacks)) {
+		/* if an fsync rises to the front of the queue then wake it
+		 * up */
+		front = list_entry(vnode->writebacks.next,
+				   struct afs_writeback, link);
+		if (front->state == AFS_WBACK_SYNCING) {
+			_debug("wake up sync");
+			front->state = AFS_WBACK_COMPLETE;
+			wake_up(&front->waitq);
+		}
+	}
+}
+
+/*
+ * free a writeback record
+ */
+static void afs_free_writeback(struct afs_writeback *wb)
+{
+	_enter("");
+	key_put(wb->key);
+	kfree(wb);
+}
+
+/*
+ * dispose of a reference to a writeback record
+ */
+void afs_put_writeback(struct afs_writeback *wb)
+{
+	struct afs_vnode *vnode = wb->vnode;
+
+	_enter("{%d}", wb->usage);
+
+	spin_lock(&vnode->writeback_lock);
+	if (--wb->usage == 0)
+		afs_unlink_writeback(wb);
+	else
+		wb = NULL;
+	spin_unlock(&vnode->writeback_lock);
+	if (wb)
+		afs_free_writeback(wb);
+}
+
+/*
+ * partly or wholly fill a page that's under preparation for writing
+ */
+static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
+			 unsigned start, unsigned len, struct page *page)
+{
+	int ret;
+
+	_enter(",,%u,%u", start, len);
+
+	ASSERTCMP(start + len, <=, PAGE_SIZE);
+
+	ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+	if (ret < 0) {
+		if (ret == -ENOENT) {
+			_debug("got NOENT from server"
+			       " - marking file deleted and stale");
+			set_bit(AFS_VNODE_DELETED, &vnode->flags);
+			ret = -ESTALE;
+		}
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * prepare a page for being written to
+ */
+static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
+			    struct key *key, unsigned offset, unsigned to)
+{
+	unsigned eof, tail, start, stop, len;
+	loff_t i_size, pos;
+	void *p;
+	int ret;
+
+	_enter("");
+
+	if (offset == 0 && to == PAGE_SIZE)
+		return 0;
+
+	p = kmap(page);
+
+	i_size = i_size_read(&vnode->vfs_inode);
+	pos = (loff_t) page->index << PAGE_SHIFT;
+	if (pos >= i_size) {
+		/* partial write, page beyond EOF */
+		_debug("beyond");
+		if (offset > 0)
+			memset(p, 0, offset);
+		if (to < PAGE_SIZE)
+			memset(p + to, 0, PAGE_SIZE - to);
+		kunmap(page);
+		return 0;
+	}
+
+	if (i_size - pos >= PAGE_SIZE) {
+		/* partial write, page entirely before EOF */
+		_debug("before");
+		tail = eof = PAGE_SIZE;
+	} else {
+		/* partial write, page overlaps EOF */
+		eof = i_size - pos;
+		_debug("overlap %u", eof);
+		tail = max(eof, to);
+		if (tail < PAGE_SIZE)
+			memset(p + tail, 0, PAGE_SIZE - tail);
+		if (offset > eof)
+			memset(p + eof, 0, PAGE_SIZE - eof);
+	}
+
+	kunmap(p);
+
+	ret = 0;
+	if (offset > 0 || eof > to) {
+		/* need to fill one or two bits that aren't going to be written
+		 * (cover both fillers in one read if there are two) */
+		start = (offset > 0) ? 0 : to;
+		stop = (eof > to) ? eof : offset;
+		len = stop - start;
+		_debug("wr=%u-%u av=0-%u rd=%u@%u",
+		       offset, to, eof, start, len);
+		ret = afs_fill_page(vnode, key, start, len, page);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * prepare to perform part of a write to a page
+ * - the caller holds the page locked, preventing it from being written out or
+ *   modified by anyone else
+ */
+int afs_prepare_write(struct file *file, struct page *page,
+		      unsigned offset, unsigned to)
+{
+	struct afs_writeback *candidate, *wb;
+	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+	struct key *key = file->private_data;
+	pgoff_t index;
+	int ret;
+
+	_enter("{%x:%u},{%lx},%u,%u",
+	       vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+	candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
+	if (!candidate)
+		return -ENOMEM;
+	candidate->vnode = vnode;
+	candidate->first = candidate->last = page->index;
+	candidate->offset_first = offset;
+	candidate->to_last = to;
+	candidate->usage = 1;
+	candidate->state = AFS_WBACK_PENDING;
+	init_waitqueue_head(&candidate->waitq);
+
+	if (!PageUptodate(page)) {
+		_debug("not up to date");
+		ret = afs_prepare_page(vnode, page, key, offset, to);
+		if (ret < 0) {
+			kfree(candidate);
+			_leave(" = %d [prep]", ret);
+			return ret;
+		}
+		SetPageUptodate(page);
+	}
+
+try_again:
+	index = page->index;
+	spin_lock(&vnode->writeback_lock);
+
+	/* see if this page is already pending a writeback under a suitable key
+	 * - if so we can just join onto that one */
+	wb = (struct afs_writeback *) page_private(page);
+	if (wb) {
+		if (wb->key == key && wb->state == AFS_WBACK_PENDING)
+			goto subsume_in_current_wb;
+		goto flush_conflicting_wb;
+	}
+
+	if (index > 0) {
+		/* see if we can find an already pending writeback that we can
+		 * append this page to */
+		list_for_each_entry(wb, &vnode->writebacks, link) {
+			if (wb->last == index - 1 && wb->key == key &&
+			    wb->state == AFS_WBACK_PENDING)
+				goto append_to_previous_wb;
+		}
+	}
+
+	list_add_tail(&candidate->link, &vnode->writebacks);
+	candidate->key = key_get(key);
+	spin_unlock(&vnode->writeback_lock);
+	SetPagePrivate(page);
+	set_page_private(page, (unsigned long) candidate);
+	_leave(" = 0 [new]");
+	return 0;
+
+subsume_in_current_wb:
+	_debug("subsume");
+	ASSERTRANGE(wb->first, <=, index, <=, wb->last);
+	if (index == wb->first && offset < wb->offset_first)
+		wb->offset_first = offset;
+	if (index == wb->last && to > wb->to_last)
+		wb->to_last = to;
+	spin_unlock(&vnode->writeback_lock);
+	kfree(candidate);
+	_leave(" = 0 [sub]");
+	return 0;
+
+append_to_previous_wb:
+	_debug("append into %lx-%lx", wb->first, wb->last);
+	wb->usage++;
+	wb->last++;
+	wb->to_last = to;
+	spin_unlock(&vnode->writeback_lock);
+	SetPagePrivate(page);
+	set_page_private(page, (unsigned long) wb);
+	kfree(candidate);
+	_leave(" = 0 [app]");
+	return 0;
+
+	/* the page is currently bound to another context, so if it's dirty we
+	 * need to flush it before we can use the new context */
+flush_conflicting_wb:
+	_debug("flush conflict");
+	if (wb->state == AFS_WBACK_PENDING)
+		wb->state = AFS_WBACK_CONFLICTING;
+	spin_unlock(&vnode->writeback_lock);
+	if (PageDirty(page)) {
+		ret = afs_write_back_from_locked_page(wb, page);
+		if (ret < 0) {
+			afs_put_writeback(candidate);
+			_leave(" = %d", ret);
+			return ret;
+		}
+	}
+
+	/* the page holds a ref on the writeback record */
+	afs_put_writeback(wb);
+	set_page_private(page, 0);
+	ClearPagePrivate(page);
+	goto try_again;
+}
+
+/*
+ * finalise part of a write to a page
+ */
+int afs_commit_write(struct file *file, struct page *page,
+		     unsigned offset, unsigned to)
+{
+	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+	loff_t i_size, maybe_i_size;
+
+	_enter("{%x:%u},{%lx},%u,%u",
+	       vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+	maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
+	maybe_i_size += to;
+
+	i_size = i_size_read(&vnode->vfs_inode);
+	if (maybe_i_size > i_size) {
+		spin_lock(&vnode->writeback_lock);
+		i_size = i_size_read(&vnode->vfs_inode);
+		if (maybe_i_size > i_size)
+			i_size_write(&vnode->vfs_inode, maybe_i_size);
+		spin_unlock(&vnode->writeback_lock);
+	}
+
+	set_page_dirty(page);
+
+	if (PageDirty(page))
+		_debug("dirtied");
+
+	return 0;
+}
+
+/*
+ * kill all the pages in the given range
+ */
+static void afs_kill_pages(struct afs_vnode *vnode, bool error,
+			   pgoff_t first, pgoff_t last)
+{
+	struct pagevec pv;
+	unsigned count, loop;
+
+	_enter("{%x:%u},%lx-%lx",
+	       vnode->fid.vid, vnode->fid.vnode, first, last);
+
+	pagevec_init(&pv, 0);
+
+	do {
+		_debug("kill %lx-%lx", first, last);
+
+		count = last - first + 1;
+		if (count > PAGEVEC_SIZE)
+			count = PAGEVEC_SIZE;
+		pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping,
+					      first, count, pv.pages);
+		ASSERTCMP(pv.nr, ==, count);
+
+		for (loop = 0; loop < count; loop++) {
+			ClearPageUptodate(pv.pages[loop]);
+			if (error)
+				SetPageError(pv.pages[loop]);
+			end_page_writeback(pv.pages[loop]);
+		}
+
+		__pagevec_release(&pv);
+	} while (first < last);
+
+	_leave("");
+}
+
+/*
+ * synchronously write back the locked page and any subsequent non-locked dirty
+ * pages also covered by the same writeback record
+ */
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+					   struct page *primary_page)
+{
+	struct page *pages[8], *page;
+	unsigned long count;
+	unsigned n, offset, to;
+	pgoff_t start, first, last;
+	int loop, ret;
+
+	_enter(",%lx", primary_page->index);
+
+	count = 1;
+	if (!clear_page_dirty_for_io(primary_page))
+		BUG();
+	if (test_set_page_writeback(primary_page))
+		BUG();
+
+	/* find all consecutive lockable dirty pages, stopping when we find a
+	 * page that is not immediately lockable, is not dirty or is missing,
+	 * or we reach the end of the range */
+	start = primary_page->index;
+	if (start >= wb->last)
+		goto no_more;
+	start++;
+	do {
+		_debug("more %lx [%lx]", start, count);
+		n = wb->last - start + 1;
+		if (n > ARRAY_SIZE(pages))
+			n = ARRAY_SIZE(pages);
+		n = find_get_pages_contig(wb->vnode->vfs_inode.i_mapping,
+					  start, n, pages);
+		_debug("fgpc %u", n);
+		if (n == 0)
+			goto no_more;
+		if (pages[0]->index != start) {
+			for (n--; n >= 0; n--)
+				put_page(pages[n]);
+			goto no_more;
+		}
+
+		for (loop = 0; loop < n; loop++) {
+			page = pages[loop];
+			if (page->index > wb->last)
+				break;
+			if (TestSetPageLocked(page))
+				break;
+			if (!PageDirty(page) ||
+			    page_private(page) != (unsigned long) wb) {
+				unlock_page(page);
+				break;
+			}
+			if (!clear_page_dirty_for_io(page))
+				BUG();
+			if (test_set_page_writeback(page))
+				BUG();
+			unlock_page(page);
+			put_page(page);
+		}
+		count += loop;
+		if (loop < n) {
+			for (; loop < n; loop++)
+				put_page(pages[loop]);
+			goto no_more;
+		}
+
+		start += loop;
+	} while (start <= wb->last && count < 65536);
+
+no_more:
+	/* we now have a contiguous set of dirty pages, each with writeback set
+	 * and the dirty mark cleared; the first page is locked and must remain
+	 * so, all the rest are unlocked */
+	first = primary_page->index;
+	last = first + count - 1;
+
+	offset = (first == wb->first) ? wb->offset_first : 0;
+	to = (last == wb->last) ? wb->to_last : PAGE_SIZE;
+
+	_debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to);
+
+	ret = afs_vnode_store_data(wb, first, last, offset, to);
+	if (ret < 0) {
+		switch (ret) {
+		case -EDQUOT:
+		case -ENOSPC:
+			set_bit(AS_ENOSPC,
+				&wb->vnode->vfs_inode.i_mapping->flags);
+			break;
+		case -EROFS:
+		case -EIO:
+		case -EREMOTEIO:
+		case -EFBIG:
+		case -ENOENT:
+		case -ENOMEDIUM:
+		case -ENXIO:
+			afs_kill_pages(wb->vnode, true, first, last);
+			set_bit(AS_EIO, &wb->vnode->vfs_inode.i_mapping->flags);
+			break;
+		case -EACCES:
+		case -EPERM:
+		case -ENOKEY:
+		case -EKEYEXPIRED:
+		case -EKEYREJECTED:
+		case -EKEYREVOKED:
+			afs_kill_pages(wb->vnode, false, first, last);
+			break;
+		default:
+			break;
+		}
+	} else {
+		ret = count;
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * write a page back to the server
+ * - the caller locked the page for us
+ */
+int afs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct backing_dev_info *bdi = page->mapping->backing_dev_info;
+	struct afs_writeback *wb;
+	int ret;
+
+	_enter("{%lx},", page->index);
+
+	if (wbc->sync_mode != WB_SYNC_NONE)
+		wait_on_page_writeback(page);
+
+	if (PageWriteback(page) || !PageDirty(page)) {
+		unlock_page(page);
+		return 0;
+	}
+
+	wb = (struct afs_writeback *) page_private(page);
+	ASSERT(wb != NULL);
+
+	ret = afs_write_back_from_locked_page(wb, page);
+	unlock_page(page);
+	if (ret < 0) {
+		_leave(" = %d", ret);
+		return 0;
+	}
+
+	wbc->nr_to_write -= ret;
+	if (wbc->nonblocking && bdi_write_congested(bdi))
+		wbc->encountered_congestion = 1;
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * write a region of pages back to the server
+ */
+int afs_writepages_region(struct address_space *mapping,
+			  struct writeback_control *wbc,
+			  pgoff_t index, pgoff_t end, pgoff_t *_next)
+{
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	struct afs_writeback *wb;
+	struct page *page;
+	int ret, n;
+
+	_enter(",,%lx,%lx,", index, end);
+
+	do {
+		n = find_get_pages_tag(mapping, &index, PAGECACHE_TAG_DIRTY,
+				       1, &page);
+		if (!n)
+			break;
+
+		_debug("wback %lx", page->index);
+
+		if (page->index > end) {
+			*_next = index;
+			page_cache_release(page);
+			_leave(" = 0 [%lx]", *_next);
+			return 0;
+		}
+
+		/* at this point we hold neither mapping->tree_lock nor lock on
+		 * the page itself: the page may be truncated or invalidated
+		 * (changing page->mapping to NULL), or even swizzled back from
+		 * swapper_space to tmpfs file mapping
+		 */
+		lock_page(page);
+
+		if (page->mapping != mapping) {
+			unlock_page(page);
+			page_cache_release(page);
+			continue;
+		}
+
+		if (wbc->sync_mode != WB_SYNC_NONE)
+			wait_on_page_writeback(page);
+
+		if (PageWriteback(page) || !PageDirty(page)) {
+			unlock_page(page);
+			continue;
+		}
+
+		wb = (struct afs_writeback *) page_private(page);
+		ASSERT(wb != NULL);
+
+		spin_lock(&wb->vnode->writeback_lock);
+		wb->state = AFS_WBACK_WRITING;
+		spin_unlock(&wb->vnode->writeback_lock);
+
+		ret = afs_write_back_from_locked_page(wb, page);
+		unlock_page(page);
+		page_cache_release(page);
+		if (ret < 0) {
+			_leave(" = %d", ret);
+			return ret;
+		}
+
+		wbc->nr_to_write -= ret;
+
+		if (wbc->nonblocking && bdi_write_congested(bdi)) {
+			wbc->encountered_congestion = 1;
+			break;
+		}
+
+		cond_resched();
+	} while (index < end && wbc->nr_to_write > 0);
+
+	*_next = index;
+	_leave(" = 0 [%lx]", *_next);
+	return 0;
+}
+
+/*
+ * write some of the pending data back to the server
+ */
+int afs_writepages(struct address_space *mapping,
+		   struct writeback_control *wbc)
+{
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
+	pgoff_t start, end, next;
+	int ret;
+
+	_enter("");
+
+	if (wbc->nonblocking && bdi_write_congested(bdi)) {
+		wbc->encountered_congestion = 1;
+		_leave(" = 0 [congest]");
+		return 0;
+	}
+
+	if (wbc->range_cyclic) {
+		start = mapping->writeback_index;
+		end = -1;
+		ret = afs_writepages_region(mapping, wbc, start, end, &next);
+		if (start > 0 && wbc->nr_to_write > 0 && ret == 0 &&
+		    !(wbc->nonblocking && wbc->encountered_congestion))
+			ret = afs_writepages_region(mapping, wbc, 0, start,
+						    &next);
+		mapping->writeback_index = next;
+	} else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
+		end = (pgoff_t)(LLONG_MAX >> PAGE_CACHE_SHIFT);
+		ret = afs_writepages_region(mapping, wbc, 0, end, &next);
+		if (wbc->nr_to_write > 0)
+			mapping->writeback_index = next;
+	} else {
+		start = wbc->range_start >> PAGE_CACHE_SHIFT;
+		end = wbc->range_end >> PAGE_CACHE_SHIFT;
+		ret = afs_writepages_region(mapping, wbc, start, end, &next);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * write an inode back
+ */
+int afs_write_inode(struct inode *inode, int sync)
+{
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+	int ret;
+
+	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
+
+	ret = 0;
+	if (sync) {
+		ret = filemap_fdatawait(inode->i_mapping);
+		if (ret < 0)
+			__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * completion of write to server
+ */
+void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
+{
+	struct afs_writeback *wb = call->wb;
+	struct pagevec pv;
+	unsigned count, loop;
+	pgoff_t first = call->first, last = call->last;
+	bool free_wb;
+
+	_enter("{%x:%u},{%lx-%lx}",
+	       vnode->fid.vid, vnode->fid.vnode, first, last);
+
+	ASSERT(wb != NULL);
+
+	pagevec_init(&pv, 0);
+
+	do {
+		_debug("attach %lx-%lx", first, last);
+
+		count = last - first + 1;
+		if (count > PAGEVEC_SIZE)
+			count = PAGEVEC_SIZE;
+		pv.nr = find_get_pages_contig(call->mapping, first, count,
+					      pv.pages);
+		ASSERTCMP(pv.nr, ==, count);
+
+		spin_lock(&vnode->writeback_lock);
+		for (loop = 0; loop < count; loop++) {
+			struct page *page = pv.pages[loop];
+			end_page_writeback(page);
+			if (page_private(page) == (unsigned long) wb) {
+				set_page_private(page, 0);
+				ClearPagePrivate(page);
+				wb->usage--;
+			}
+		}
+		free_wb = false;
+		if (wb->usage == 0) {
+			afs_unlink_writeback(wb);
+			free_wb = true;
+		}
+		spin_unlock(&vnode->writeback_lock);
+		first += count;
+		if (free_wb) {
+			afs_free_writeback(wb);
+			wb = NULL;
+		}
+
+		__pagevec_release(&pv);
+	} while (first < last);
+
+	_leave("");
+}
+
+/*
+ * write to an AFS file
+ */
+ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
+		       unsigned long nr_segs, loff_t pos)
+{
+	struct dentry *dentry = iocb->ki_filp->f_path.dentry;
+	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+	ssize_t result;
+	size_t count = iov_length(iov, nr_segs);
+	int ret;
+
+	_enter("{%x.%u},{%zu},%lu,",
+	       vnode->fid.vid, vnode->fid.vnode, count, nr_segs);
+
+	if (IS_SWAPFILE(&vnode->vfs_inode)) {
+		printk(KERN_INFO
+		       "AFS: Attempt to write to active swap file!\n");
+		return -EBUSY;
+	}
+
+	if (!count)
+		return 0;
+
+	result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+	if (IS_ERR_VALUE(result)) {
+		_leave(" = %zd", result);
+		return result;
+	}
+
+	/* return error values for O_SYNC and IS_SYNC() */
+	if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) {
+		ret = afs_fsync(iocb->ki_filp, dentry, 1);
+		if (ret < 0)
+			result = ret;
+	}
+
+	_leave(" = %zd", result);
+	return result;
+}
+
+/*
+ * flush the vnode to the fileserver
+ */
+int afs_writeback_all(struct afs_vnode *vnode)
+{
+	struct address_space *mapping = vnode->vfs_inode.i_mapping;
+	struct writeback_control wbc = {
+		.bdi		= mapping->backing_dev_info,
+		.sync_mode	= WB_SYNC_ALL,
+		.nr_to_write	= LONG_MAX,
+		.for_writepages = 1,
+		.range_cyclic	= 1,
+	};
+	int ret;
+
+	_enter("");
+
+	ret = mapping->a_ops->writepages(mapping, &wbc);
+	__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * flush any dirty pages for this process, and check for write errors.
+ * - the return status from this call provides a reliable indication of
+ *   whether any write errors occurred for this process.
+ */
+int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct afs_writeback *wb, *xwb;
+	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+	int ret;
+
+	_enter("{%x:%u},{n=%s},%d",
+	       vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+	       datasync);
+
+	/* use a writeback record as a marker in the queue - when this reaches
+	 * the front of the queue, all the outstanding writes are either
+	 * completed or rejected */
+	wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+	if (!wb)
+		return -ENOMEM;
+	wb->vnode = vnode;
+	wb->first = 0;
+	wb->last = -1;
+	wb->offset_first = 0;
+	wb->to_last = PAGE_SIZE;
+	wb->usage = 1;
+	wb->state = AFS_WBACK_SYNCING;
+	init_waitqueue_head(&wb->waitq);
+
+	spin_lock(&vnode->writeback_lock);
+	list_for_each_entry(xwb, &vnode->writebacks, link) {
+		if (xwb->state == AFS_WBACK_PENDING)
+			xwb->state = AFS_WBACK_CONFLICTING;
+	}
+	list_add_tail(&wb->link, &vnode->writebacks);
+	spin_unlock(&vnode->writeback_lock);
+
+	/* push all the outstanding writebacks to the server */
+	ret = afs_writeback_all(vnode);
+	if (ret < 0) {
+		afs_put_writeback(wb);
+		_leave(" = %d [wb]", ret);
+		return ret;
+	}
+
+	/* wait for the preceding writes to actually complete */
+	ret = wait_event_interruptible(wb->waitq,
+				       wb->state == AFS_WBACK_COMPLETE ||
+				       vnode->writebacks.next == &wb->link);
+	afs_put_writeback(wb);
+	_leave(" = %d", ret);
+	return ret;
+}
diff --git a/fs/aio.c b/fs/aio.c
index b97ab80..ac1c158 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -346,10 +346,9 @@
 
 		wait_for_all_aios(ctx);
 		/*
-		 * this is an overkill, but ensures we don't leave
-		 * the ctx on the aio_wq
+		 * Ensure we don't leave the ctx on the aio_wq
 		 */
-		flush_workqueue(aio_wq);
+		cancel_work_sync(&ctx->wq.work);
 
 		if (1 != atomic_read(&ctx->users))
 			printk(KERN_DEBUG
@@ -372,7 +371,7 @@
 	BUG_ON(ctx->reqs_active);
 
 	cancel_delayed_work(&ctx->wq);
-	flush_workqueue(aio_wq);
+	cancel_work_sync(&ctx->wq.work);
 	aio_free_ring(ctx);
 	mmdrop(ctx->mm);
 	ctx->mm = NULL;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 18657f0..72d0b41 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -675,19 +675,8 @@
 bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
 	char *s = enabled ? "enabled" : "disabled";
-	int len = strlen(s);
-	loff_t pos = *ppos;
 
-	if (pos < 0)
-		return -EINVAL;
-	if (pos >= len)
-		return 0;
-	if (len < pos + nbytes)
-		nbytes = len - pos;
-	if (copy_to_user(buf, s + pos, nbytes))
-		return -EFAULT;
-	*ppos = pos + nbytes;
-	return nbytes;
+	return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
 }
 
 static ssize_t bm_status_write(struct file * file, const char __user * buffer,
diff --git a/fs/buffer.c b/fs/buffer.c
index eb820b8..aecd057 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1846,13 +1846,8 @@
 		if (block_start >= to)
 			break;
 		if (buffer_new(bh)) {
-			void *kaddr;
-
 			clear_buffer_new(bh);
-			kaddr = kmap_atomic(page, KM_USER0);
-			memset(kaddr+block_start, 0, bh->b_size);
-			flush_dcache_page(page);
-			kunmap_atomic(kaddr, KM_USER0);
+			zero_user_page(page, block_start, bh->b_size, KM_USER0);
 			set_buffer_uptodate(bh);
 			mark_buffer_dirty(bh);
 		}
@@ -1940,10 +1935,8 @@
 					SetPageError(page);
 			}
 			if (!buffer_mapped(bh)) {
-				void *kaddr = kmap_atomic(page, KM_USER0);
-				memset(kaddr + i * blocksize, 0, blocksize);
-				flush_dcache_page(page);
-				kunmap_atomic(kaddr, KM_USER0);
+				zero_user_page(page, i * blocksize, blocksize,
+						KM_USER0);
 				if (!err)
 					set_buffer_uptodate(bh);
 				continue;
@@ -2086,7 +2079,6 @@
 	long status;
 	unsigned zerofrom;
 	unsigned blocksize = 1 << inode->i_blkbits;
-	void *kaddr;
 
 	while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) {
 		status = -ENOMEM;
@@ -2108,10 +2100,8 @@
 						PAGE_CACHE_SIZE, get_block);
 		if (status)
 			goto out_unmap;
-		kaddr = kmap_atomic(new_page, KM_USER0);
-		memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
-		flush_dcache_page(new_page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, zerofrom, PAGE_CACHE_SIZE - zerofrom,
+				KM_USER0);
 		generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE);
 		unlock_page(new_page);
 		page_cache_release(new_page);
@@ -2138,10 +2128,7 @@
 	if (status)
 		goto out1;
 	if (zerofrom < offset) {
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr+zerofrom, 0, offset-zerofrom);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, zerofrom, offset - zerofrom, KM_USER0);
 		__block_commit_write(inode, page, zerofrom, offset);
 	}
 	return 0;
@@ -2340,10 +2327,7 @@
 	 * Error recovery is pretty slack.  Clear the page and mark it dirty
 	 * so we'll later zero out any blocks which _were_ allocated.
 	 */
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr, 0, PAGE_CACHE_SIZE);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
+	zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
 	SetPageUptodate(page);
 	set_page_dirty(page);
 	return ret;
@@ -2382,7 +2366,6 @@
 	loff_t i_size = i_size_read(inode);
 	const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
-	void *kaddr;
 	int ret;
 
 	/* Is the page fully inside i_size? */
@@ -2413,10 +2396,7 @@
 	 * the  page size, the remaining memory is zeroed when mapped, and
 	 * writes to that region are not written out to the file."
 	 */
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
+	zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
 out:
 	ret = mpage_writepage(page, get_block, wbc);
 	if (ret == -EAGAIN)
@@ -2437,7 +2417,6 @@
 	unsigned to;
 	struct page *page;
 	const struct address_space_operations *a_ops = mapping->a_ops;
-	char *kaddr;
 	int ret = 0;
 
 	if ((offset & (blocksize - 1)) == 0)
@@ -2451,10 +2430,8 @@
 	to = (offset + blocksize) & ~(blocksize - 1);
 	ret = a_ops->prepare_write(NULL, page, offset, to);
 	if (ret == 0) {
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+				KM_USER0);
 		/*
 		 * It would be more correct to call aops->commit_write()
 		 * here, but this is more efficient.
@@ -2480,7 +2457,6 @@
 	struct inode *inode = mapping->host;
 	struct page *page;
 	struct buffer_head *bh;
-	void *kaddr;
 	int err;
 
 	blocksize = 1 << inode->i_blkbits;
@@ -2534,11 +2510,7 @@
 			goto unlock;
 	}
 
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr + offset, 0, length);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
-
+	zero_user_page(page, offset, length, KM_USER0);
 	mark_buffer_dirty(bh);
 	err = 0;
 
@@ -2559,7 +2531,6 @@
 	loff_t i_size = i_size_read(inode);
 	const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
-	void *kaddr;
 
 	/* Is the page fully inside i_size? */
 	if (page->index < end_index)
@@ -2585,10 +2556,7 @@
 	 * the  page size, the remaining memory is zeroed when mapped, and
 	 * writes to that region are not written out to the file."
 	 */
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
+	zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
 	return __block_write_full_page(inode, page, get_block, wbc);
 }
 
@@ -2978,7 +2946,7 @@
 static int buffer_cpu_notify(struct notifier_block *self,
 			      unsigned long action, void *hcpu)
 {
-	if (action == CPU_DEAD)
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
 		buffer_exit_cpu((unsigned long)hcpu);
 	return NOTIFY_OK;
 }
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index d98be5e..3527c7c 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -77,36 +77,6 @@
 	return ret;
 }
 
-
-/**
- *	flush_read_buffer - push buffer to userspace.
- *	@buffer:	data buffer for file.
- *	@userbuf:	user-passed buffer.
- *	@count:		number of bytes requested.
- *	@ppos:		file position.
- *
- *	Copy the buffer we filled in fill_read_buffer() to userspace.
- *	This is done at the reader's leisure, copying and advancing
- *	the amount they specify each time.
- *	This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf,
-			     size_t count, loff_t * ppos)
-{
-	int error;
-
-	if (*ppos > buffer->count)
-		return 0;
-
-	if (count > (buffer->count - *ppos))
-		count = buffer->count - *ppos;
-
-	error = copy_to_user(buf,buffer->page + *ppos,count);
-	if (!error)
-		*ppos += count;
-	return error ? -EFAULT : count;
-}
-
 /**
  *	configfs_read_file - read an attribute.
  *	@file:	file pointer.
@@ -139,7 +109,8 @@
 	}
 	pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
 		 __FUNCTION__, count, *ppos, buffer->page);
-	retval = flush_read_buffer(buffer,buf,count,ppos);
+	retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+					 buffer->count);
 out:
 	up(&buffer->sem);
 	return retval;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index d9d0833..8593f3d 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -439,7 +439,7 @@
  * Wait on and process all in-flight BIOs.  This must only be called once
  * all bios have been issued so that the refcount can only decrease.
  * This just waits for all bios to make it through dio_bio_complete.  IO
- * errors are propogated through dio->io_error and should be propogated via
+ * errors are propagated through dio->io_error and should be propagated via
  * dio_complete().
  */
 static void dio_await_completion(struct dio *dio)
@@ -867,7 +867,6 @@
 do_holes:
 			/* Handle holes */
 			if (!buffer_mapped(map_bh)) {
-				char *kaddr;
 				loff_t i_size_aligned;
 
 				/* AKPM: eargh, -ENOTBLK is a hack */
@@ -888,11 +887,8 @@
 					page_cache_release(page);
 					goto out;
 				}
-				kaddr = kmap_atomic(page, KM_USER0);
-				memset(kaddr + (block_in_page << blkbits),
-						0, 1 << blkbits);
-				flush_dcache_page(page);
-				kunmap_atomic(kaddr, KM_USER0);
+				zero_user_page(page, block_in_page << blkbits,
+						1 << blkbits, KM_USER0);
 				dio->block_in_file++;
 				block_in_page++;
 				goto next_block;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index e1bb031..a6cb617 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1767,7 +1767,6 @@
 	struct inode *inode = mapping->host;
 	struct buffer_head *bh;
 	int err = 0;
-	void *kaddr;
 
 	blocksize = inode->i_sb->s_blocksize;
 	length = blocksize - (offset & (blocksize - 1));
@@ -1779,10 +1778,7 @@
 	 */
 	if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
 	     ext3_should_writeback_data(inode) && PageUptodate(page)) {
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + offset, 0, length);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, offset, length, KM_USER0);
 		set_page_dirty(page);
 		goto unlock;
 	}
@@ -1835,11 +1831,7 @@
 			goto unlock;
 	}
 
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr + offset, 0, length);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
-
+	zero_user_page(page, offset, length, KM_USER0);
 	BUFFER_TRACE(bh, "zeroed end of block");
 
 	err = 0;
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 0208cc7..47552d4 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd/checkpoint.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 11563fe..2a5f4b8 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/recovery.c
+ * linux/fs/jbd/recovery.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index a68cbb6..824e3b7 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/revoke.c
+ * linux/fs/jbd/revoke.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
  *
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index f9822fc..772b653 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/transaction.c
+ * linux/fs/jbd/transaction.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
  *
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 68039fa..3fccde7 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd2/checkpoint.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 9f10aca..395c92a 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/recovery.c
+ * linux/fs/jbd2/recovery.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 1e864dc..9246e76 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/revoke.c
+ * linux/fs/jbd2/revoke.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
  *
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index e347d8c0..7946ff4 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1,5 +1,5 @@
 /*
- * linux/fs/transaction.c
+ * linux/fs/jbd2/transaction.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
  *
diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h
deleted file mode 100644
index fa3dac1..0000000
--- a/fs/jffs2/histo_mips.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER_MIPS 1043
-static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 6aff389..4884d5e 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -219,9 +219,9 @@
 				struct jffs2_tmp_dnode_info *tn)
 {
 	uint32_t fn_end = tn->fn->ofs + tn->fn->size;
-	struct jffs2_tmp_dnode_info *insert_point = NULL, *this;
+	struct jffs2_tmp_dnode_info *this;
 
-	dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version);
+	dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
 
 	/* If a node has zero dsize, we only have to keep if it if it might be the
 	   node with highest version -- i.e. the one which will end up as f->metadata.
@@ -240,24 +240,17 @@
 
 	/* Find the earliest node which _may_ be relevant to this one */
 	this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
-	if (!this) {
-		/* First addition to empty tree. $DEITY how I love the easy cases */
-		rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node);
-		rb_insert_color(&tn->rb, &rii->tn_root);
-		dbg_readinode("keep new frag\n");
-		return 0;
+	if (this) {
+		/* If the node is coincident with another at a lower address,
+		   back up until the other node is found. It may be relevant */
+		while (this->overlapped)
+			this = tn_prev(this);
+
+		/* First node should never be marked overlapped */
+		BUG_ON(!this);
+		dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
 	}
 
-	/* If we add a new node it'll be somewhere under here. */
-	insert_point = this;
-
-	/* If the node is coincident with another at a lower address,
-	   back up until the other node is found. It may be relevant */
-	while (tn->overlapped)
-		tn = tn_prev(tn);
-
-	dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
-
 	while (this) {
 		if (this->fn->ofs > fn_end)
 			break;
@@ -274,11 +267,10 @@
 				return 0;
 			} else {
 				/* Who cares if the new one is good; keep it for now anyway. */
-				rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-				/* Same overlapping from in front and behind */
-				tn->overlapped = this->overlapped;
-				jffs2_kill_tn(c, this);
 				dbg_readinode("Like new node. Throw away old\n");
+				rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
+				jffs2_kill_tn(c, this);
+				/* Same overlapping from in front and behind */
 				return 0;
 			}
 		}
@@ -291,13 +283,8 @@
 				jffs2_kill_tn(c, tn);
 				return 0;
 			}
-			/* ... and is good. Kill 'this'... */
-			rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-			tn->overlapped = this->overlapped;
-			jffs2_kill_tn(c, this);
-			/* ... and any subsequent nodes which are also overlapped */
-			this = tn_next(tn);
-			while (this && this->fn->ofs + this->fn->size < fn_end) {
+			/* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
+			while (this && this->fn->ofs + this->fn->size <= fn_end) {
 				struct jffs2_tmp_dnode_info *next = tn_next(this);
 				if (this->version < tn->version) {
 					tn_erase(this, &rii->tn_root);
@@ -308,8 +295,8 @@
 				}
 				this = next;
 			}
-			dbg_readinode("Done inserting new\n");
-			return 0;
+			dbg_readinode("Done killing overlapped nodes\n");
+			continue;
 		}
 		if (this->version > tn->version &&
 		    this->fn->ofs <= tn->fn->ofs &&
@@ -321,29 +308,21 @@
 				return 0;
 			}
 			/* ... but 'this' was bad. Replace it... */
-			rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
 			dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
+			tn_erase(this, &rii->tn_root);
 			jffs2_kill_tn(c, this);
-			return 0;
+			break;
 		}
-		/* We want to be inserted under the last node which is
-		   either at a lower offset _or_ has a smaller range */
-		if (this->fn->ofs < tn->fn->ofs ||
-		    (this->fn->ofs == tn->fn->ofs &&
-		     this->fn->size <= tn->fn->size))
-			insert_point = this;
 
 		this = tn_next(this);
 	}
-	dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n",
-		      insert_point, insert_point->version, insert_point->fn->ofs,
-		      insert_point->fn->ofs+insert_point->fn->size,
-		      insert_point->overlapped);
+
 	/* We neither completely obsoleted nor were completely
-	   obsoleted by an earlier node. Insert under insert_point */
+	   obsoleted by an earlier node. Insert into the tree */
 	{
-		struct rb_node *parent = &insert_point->rb;
-		struct rb_node **link = &parent;
+		struct rb_node *parent;
+		struct rb_node **link = &rii->tn_root.rb_node;
+		struct jffs2_tmp_dnode_info *insert_point = NULL;
 
 		while (*link) {
 			parent = *link;
@@ -359,6 +338,7 @@
 		rb_link_node(&tn->rb, &insert_point->rb, link);
 		rb_insert_color(&tn->rb, &rii->tn_root);
 	}
+
 	/* If there's anything behind that overlaps us, note it */
 	this = tn_prev(tn);
 	if (this) {
@@ -457,7 +437,7 @@
 	this = tn_last(&rii->tn_root);
 	while (this) {
 		dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs,
-			     this->fn->ofs+this->fn->size, this->overlapped);
+			      this->fn->ofs+this->fn->size, this->overlapped);
 		this = tn_prev(this);
 	}
 #endif
@@ -483,7 +463,7 @@
 			vers_next = tn_prev(this);
 			eat_last(&ver_root, &this->rb);
 			if (check_tn_node(c, this)) {
-				dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n",
+				dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n",
 					     this->version, this->fn->ofs,
 					     this->fn->ofs+this->fn->size);
 				jffs2_kill_tn(c, this);
@@ -496,7 +476,7 @@
 					high_ver = this->version;
 					rii->latest_ref = this->fn->raw;
 				}
-				dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n",
+				dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n",
 					     this, this->version, this->fn->ofs,
 					     this->fn->ofs+this->fn->size, this->overlapped);
 
@@ -850,7 +830,7 @@
 		return ret;
 	}
 #ifdef JFFS2_DBG_READINODE_MESSAGES
-	dbg_readinode("After adding ver %d:\n", tn->version);
+	dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));
 	tn = tn_first(&rii->tn_root);
 	while (tn) {
 		dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index c556e85..91d1d0f 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -637,7 +637,10 @@
 
 	memset(c->wbuf,0xff,c->wbuf_pagesize);
 	/* adjust write buffer offset, else we get a non contiguous write bug */
-	c->wbuf_ofs += c->wbuf_pagesize;
+	if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize))
+		c->wbuf_ofs += c->wbuf_pagesize;
+	else
+		c->wbuf_ofs = 0xffffffff;
 	c->wbuf_len = 0;
 	return 0;
 }
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 82b0544..f3b1ebb 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -1507,7 +1507,7 @@
 		if (l2nb < budmin) {
 
 			/* search the lower level dmap control pages to get
-			 * the starting block number of the the dmap that
+			 * the starting block number of the dmap that
 			 * contains or starts off the free space.
 			 */
 			if ((rc =
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index c465607..c653022 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -386,7 +386,7 @@
 		return -EIO;
 	}
 
-	/* locate the the disk inode requested */
+	/* locate the disk inode requested */
 	dp = (struct dinode *) mp->data;
 	dp += rel_inode;
 
@@ -1407,7 +1407,7 @@
 	inum = pip->i_ino + 1;
 	ino = inum & (INOSPERIAG - 1);
 
-	/* back off the the hint if it is outside of the iag */
+	/* back off the hint if it is outside of the iag */
 	if (ino == 0)
 		inum = pip->i_ino;
 
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 6a3f00d..44a2f33 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -1960,7 +1960,7 @@
 /*
  * NAME:	lbmRedrive
  *
- * FUNCTION:	add a log buffer to the the log redrive list
+ * FUNCTION:	add a log buffer to the log redrive list
  *
  * PARAMETER:
  *     bp	- log buffer
diff --git a/fs/libfs.c b/fs/libfs.c
index 1247ee9..5294de1 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -159,7 +159,10 @@
 					continue;
 
 				spin_unlock(&dcache_lock);
-				if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
+				if (filldir(dirent, next->d_name.name, 
+					    next->d_name.len, filp->f_pos, 
+					    next->d_inode->i_ino, 
+					    dt_type(next->d_inode)) < 0)
 					return 0;
 				spin_lock(&dcache_lock);
 				/* next is still alive */
diff --git a/fs/mpage.c b/fs/mpage.c
index fa2441f..0fb914f 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -284,11 +284,9 @@
 	}
 
 	if (first_hole != blocks_per_page) {
-		char *kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + (first_hole << blkbits), 0,
-				PAGE_CACHE_SIZE - (first_hole << blkbits));
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, first_hole << blkbits,
+				PAGE_CACHE_SIZE - (first_hole << blkbits),
+				KM_USER0);
 		if (first_hole == 0) {
 			SetPageUptodate(page);
 			unlock_page(page);
@@ -576,14 +574,11 @@
 		 * written out to the file."
 		 */
 		unsigned offset = i_size & (PAGE_CACHE_SIZE - 1);
-		char *kaddr;
 
 		if (page->index > end_index || !offset)
 			goto confused;
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+				KM_USER0);
 	}
 
 	/*
diff --git a/fs/namei.c b/fs/namei.c
index 856b2f5..b3780e3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1152,14 +1152,12 @@
 
 		fput_light(file, fput_needed);
 	}
-	current->total_link_count = 0;
-	retval = link_path_walk(name, nd);
+
+	retval = path_walk(name, nd);
 out:
-	if (likely(retval == 0)) {
-		if (unlikely(!audit_dummy_context() && nd && nd->dentry &&
+	if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
 				nd->dentry->d_inode))
 		audit_inode(name, nd->dentry->d_inode);
-	}
 out_fail:
 	return retval;
 
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 625d8e5..3df4288 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -38,7 +38,6 @@
 #include "delegation.h"
 #include "iostat.h"
 
-#define NFS_PARANOIA 1
 /* #define NFS_DEBUG_VERBOSE 1 */
 
 static int nfs_opendir(struct inode *, struct file *);
@@ -650,12 +649,15 @@
  */
 static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
+	unsigned long verf;
+
 	if (IS_ROOT(dentry))
 		return 1;
-	if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0
-			|| nfs_attribute_timeout(dir))
+	verf = (unsigned long)dentry->d_fsdata;
+	if (nfs_caches_unstable(dir)
+			|| verf != NFS_I(dir)->cache_change_attribute)
 		return 0;
-	return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
+	return 1;
 }
 
 static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
@@ -665,8 +667,7 @@
 
 static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
 {
-	if (time_after(verf, (unsigned long)dentry->d_fsdata))
-		nfs_set_verifier(dentry, verf);
+	nfs_set_verifier(dentry, verf);
 }
 
 /*
@@ -765,6 +766,10 @@
 	nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
 	inode = dentry->d_inode;
 
+	/* Revalidate parent directory attribute cache */
+	if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+		goto out_zap_parent;
+
 	if (!inode) {
 		if (nfs_neg_need_reval(dir, dentry, nd))
 			goto out_bad;
@@ -778,10 +783,6 @@
 		goto out_bad;
 	}
 
-	/* Revalidate parent directory attribute cache */
-	if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
-		goto out_zap_parent;
-
 	/* Force a full look up iff the parent directory has changed */
 	if (nfs_check_verifier(dir, dentry)) {
 		if (nfs_lookup_verify_inode(inode, nd))
@@ -1360,11 +1361,6 @@
 		atomic_read(&dentry->d_count));
 	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
 
-#ifdef NFS_PARANOIA
-if (!dentry->d_inode)
-printk("NFS: silly-renaming %s/%s, negative dentry??\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
 	/*
 	 * We don't allow a dentry to be silly-renamed twice.
 	 */
@@ -1681,16 +1677,9 @@
 			new_inode = NULL;
 			/* instantiate the replacement target */
 			d_instantiate(new_dentry, NULL);
-		} else if (atomic_read(&new_dentry->d_count) > 1) {
-		/* dentry still busy? */
-#ifdef NFS_PARANOIA
-			printk("nfs_rename: target %s/%s busy, d_count=%d\n",
-			       new_dentry->d_parent->d_name.name,
-			       new_dentry->d_name.name,
-			       atomic_read(&new_dentry->d_count));
-#endif
+		} else if (atomic_read(&new_dentry->d_count) > 1)
+			/* dentry still busy? */
 			goto out;
-		}
 	} else
 		drop_nlink(new_inode);
 
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 2347785..d1cbf0a 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -41,7 +41,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_CLIENT
-#define NFS_PARANOIA 1
 
 /*
  * get an NFS2/NFS3 root dentry from the root filehandle
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 9d4a6b2..d11eb055 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -272,7 +272,7 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	mutex_unlock(&idmap->idmap_im_lock);
 	schedule();
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&idmap->idmap_wq, &wq);
 	mutex_lock(&idmap->idmap_im_lock);
 
@@ -333,7 +333,7 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	mutex_unlock(&idmap->idmap_im_lock);
 	schedule();
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&idmap->idmap_wq, &wq);
 	mutex_lock(&idmap->idmap_im_lock);
 
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1e9a915..2a3fd95 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -48,7 +48,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
-#define NFS_PARANOIA 1
 
 static void nfs_invalidate_inode(struct inode *);
 static int nfs_update_inode(struct inode *, struct nfs_fattr *);
@@ -1075,10 +1074,8 @@
 	/*
 	 * Big trouble! The inode has become a different object.
 	 */
-#ifdef NFS_PARANOIA
 	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
 			__FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
-#endif
  out_err:
 	/*
 	 * No need to worry about unhashing the dentry, as the
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index abd9f8b..cd3ca7b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -26,7 +26,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_XDR
-/* #define NFS_PARANOIA 1 */
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b8c28f2..938f371 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -224,7 +224,8 @@
                                 encode_getattr_maxsz)
 #define NFS4_dec_setattr_sz     (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 3)
+                                op_decode_hdr_maxsz + 3 + \
+                                nfs4_fattr_maxsz)
 #define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
 				encode_fsinfo_maxsz)
@@ -2079,9 +2080,11 @@
 
 #define READ_BUF(nbytes)  do { \
 	p = xdr_inline_decode(xdr, nbytes); \
-	if (!p) { \
-		printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \
-			       	__FUNCTION__, __LINE__); \
+	if (unlikely(!p)) { \
+		printk(KERN_INFO "%s: prematurely hit end of receive" \
+				" buffer\n", __FUNCTION__); \
+		printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
+				__FUNCTION__, xdr->p, nbytes, xdr->end); \
 		return -EIO; \
 	} \
 } while (0)
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 3889501..e12054c 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -20,8 +20,6 @@
 
 #include "internal.h"
 
-#define NFS_PARANOIA 1
-
 static struct kmem_cache *nfs_page_cachep;
 
 static inline struct nfs_page *
@@ -167,11 +165,6 @@
 	if (!atomic_dec_and_test(&req->wb_count))
 		return;
 
-#ifdef NFS_PARANOIA
-	BUG_ON (!list_empty(&req->wb_list));
-	BUG_ON (NFS_WBACK_BUSY(req));
-#endif
-
 	/* Release struct file or cached credential */
 	nfs_clear_request(req);
 	put_nfs_open_context(req->wb_context);
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index ce341dc..9b118ee 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -11,4 +11,3 @@
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
 nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
 			   nfs4acl.o nfs4callback.o nfs4recover.o
-nfsd-objs		:= $(nfsd-y)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 6f24768..79bd03b 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -469,6 +469,13 @@
 	nd.dentry = NULL;
 	exp.ex_path = NULL;
 
+	/* fs locations */
+	exp.ex_fslocs.locations = NULL;
+	exp.ex_fslocs.locations_count = 0;
+	exp.ex_fslocs.migrated = 0;
+
+	exp.ex_uuid = NULL;
+
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
@@ -509,13 +516,6 @@
 	if (exp.h.expiry_time == 0)
 		goto out;
 
-	/* fs locations */
-	exp.ex_fslocs.locations = NULL;
-	exp.ex_fslocs.locations_count = 0;
-	exp.ex_fslocs.migrated = 0;
-
-	exp.ex_uuid = NULL;
-
 	/* flags */
 	err = get_int(&mesg, &an_int);
 	if (err == -ENOENT)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 7f5bad0..eac8283 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -177,7 +177,7 @@
 	if (max_blocksize < resp->count)
 		resp->count = max_blocksize;
 
-	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
+	svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh, NULL,
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 7e4bb0a..10f6e7d 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -239,7 +239,7 @@
 encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
 	struct dentry *dentry = fhp->fh_dentry;
-	if (dentry && dentry->d_inode != NULL) {
+	if (dentry && dentry->d_inode) {
 	        int err;
 		struct kstat stat;
 
@@ -300,9 +300,9 @@
 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_sattrargs *args)
 {
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = decode_sattr3(p, &args->attrs)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
+	p = decode_sattr3(p, &args->attrs);
 
 	if ((args->check_guard = ntohl(*p++)) != 0) { 
 		struct timespec time; 
@@ -343,9 +343,9 @@
 	int v,pn;
 	u32 max_blocksize = svc_max_payload(rqstp);
 
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = xdr_decode_hyper(p, &args->offset)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
+	p = xdr_decode_hyper(p, &args->offset);
 
 	len = args->count = ntohl(*p++);
 
@@ -369,28 +369,44 @@
 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_writeargs *args)
 {
-	unsigned int len, v, hdr;
+	unsigned int len, v, hdr, dlen;
 	u32 max_blocksize = svc_max_payload(rqstp);
 
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = xdr_decode_hyper(p, &args->offset)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
+	p = xdr_decode_hyper(p, &args->offset);
 
 	args->count = ntohl(*p++);
 	args->stable = ntohl(*p++);
 	len = args->len = ntohl(*p++);
-
-	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
-	if (rqstp->rq_arg.len < hdr ||
-	    rqstp->rq_arg.len - hdr < len)
+	/*
+	 * The count must equal the amount of data passed.
+	 */
+	if (args->count != args->len)
 		return 0;
 
+	/*
+	 * Check to make sure that we got the right number of
+	 * bytes.
+	 */
+	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+		- hdr;
+	/*
+	 * Round the length of the data which was specified up to
+	 * the next multiple of XDR units and then compare that
+	 * against the length which was actually received.
+	 */
+	if (dlen != XDR_QUADLEN(len)*4)
+		return 0;
+
+	if (args->count > max_blocksize) {
+		args->count = max_blocksize;
+		len = args->len = max_blocksize;
+	}
 	rqstp->rq_vec[0].iov_base = (void*)p;
 	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
-
-	if (len > max_blocksize)
-		len = max_blocksize;
-	v=  0;
+	v = 0;
 	while (len > rqstp->rq_vec[v].iov_len) {
 		len -= rqstp->rq_vec[v].iov_len;
 		v++;
@@ -398,9 +414,8 @@
 		rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 	}
 	rqstp->rq_vec[v].iov_len = len;
-	args->vlen = v+1;
-
-	return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
+	args->vlen = v + 1;
+	return 1;
 }
 
 int
@@ -414,8 +429,7 @@
 	switch (args->createmode = ntohl(*p++)) {
 	case NFS3_CREATE_UNCHECKED:
 	case NFS3_CREATE_GUARDED:
-		if (!(p = decode_sattr3(p, &args->attrs)))
-			return 0;
+		p = decode_sattr3(p, &args->attrs);
 		break;
 	case NFS3_CREATE_EXCLUSIVE:
 		args->verf = p;
@@ -431,10 +445,10 @@
 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd3_createargs *args)
 {
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = decode_filename(p, &args->name, &args->len))
-	 || !(p = decode_sattr3(p, &args->attrs)))
+	if (!(p = decode_fh(p, &args->fh)) ||
+	    !(p = decode_filename(p, &args->name, &args->len)))
 		return 0;
+	p = decode_sattr3(p, &args->attrs);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -448,11 +462,12 @@
 	char *old, *new;
 	struct kvec *vec;
 
-	if (!(p = decode_fh(p, &args->ffh))
-	 || !(p = decode_filename(p, &args->fname, &args->flen))
-	 || !(p = decode_sattr3(p, &args->attrs))
+	if (!(p = decode_fh(p, &args->ffh)) ||
+	    !(p = decode_filename(p, &args->fname, &args->flen))
 		)
 		return 0;
+	p = decode_sattr3(p, &args->attrs);
+
 	/* now decode the pathname, which might be larger than the first page.
 	 * As we have to check for nul's anyway, we copy it into a new page
 	 * This page appears in the rq_res.pages list, but as pages_len is always
@@ -502,10 +517,8 @@
 	args->ftype = ntohl(*p++);
 
 	if (args->ftype == NF3BLK  || args->ftype == NF3CHR
-	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
-		if (!(p = decode_sattr3(p, &args->attrs)))
-			return 0;
-	}
+	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
+		p = decode_sattr3(p, &args->attrs);
 
 	if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
 		args->major = ntohl(*p++);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 673a53c..cc3b7ba 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -137,7 +137,6 @@
 static short ace2type(struct nfs4_ace *);
 static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
 				unsigned int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
 
 struct nfs4_acl *
 nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
@@ -785,21 +784,6 @@
 	return acl;
 }
 
-void
-nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
-		int whotype, uid_t who)
-{
-	struct nfs4_ace *ace = acl->aces + acl->naces;
-
-	ace->type = type;
-	ace->flag = flag;
-	ace->access_mask = access_mask;
-	ace->whotype = whotype;
-	ace->who = who;
-
-	acl->naces++;
-}
-
 static struct {
 	char *string;
 	int   stringlen;
@@ -851,6 +835,5 @@
 }
 
 EXPORT_SYMBOL(nfs4_acl_new);
-EXPORT_SYMBOL(nfs4_acl_add_ace);
 EXPORT_SYMBOL(nfs4_acl_get_whotype);
 EXPORT_SYMBOL(nfs4_acl_write_who);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 678f3be..3cc8ce4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1326,8 +1326,6 @@
 {
 	struct nfs4_delegation *dp = __dp;
 
-	daemonize("nfsv4-recall");
-
 	nfsd4_cb_recall(dp);
 	return 0;
 }
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 739dd3c..6ca2d24 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -323,7 +323,7 @@
 	 *
 	 */
 
-	u8 version = 1;
+	u8 version;
 	u8 fsid_type = 0;
 	struct inode * inode = dentry->d_inode;
 	struct dentry *parent = dentry->d_parent;
@@ -341,15 +341,59 @@
 	 * the reference filehandle (if it is in the same export)
 	 * or the export options.
 	 */
+ retry:
+	version = 1;
 	if (ref_fh && ref_fh->fh_export == exp) {
 		version = ref_fh->fh_handle.fh_version;
-		if (version == 0xca)
+		fsid_type = ref_fh->fh_handle.fh_fsid_type;
+
+		if (ref_fh == fhp)
+			fh_put(ref_fh);
+		ref_fh = NULL;
+
+		switch (version) {
+		case 0xca:
 			fsid_type = FSID_DEV;
-		else
-			fsid_type = ref_fh->fh_handle.fh_fsid_type;
-		/* We know this version/type works for this export
-		 * so there is no need for further checks.
+			break;
+		case 1:
+			break;
+		default:
+			goto retry;
+		}
+
+		/* Need to check that this type works for this
+		 * export point.  As the fsid -> filesystem mapping
+		 * was guided by user-space, there is no guarantee
+		 * that the filesystem actually supports that fsid
+		 * type. If it doesn't we loop around again without
+		 * ref_fh set.
 		 */
+		switch(fsid_type) {
+		case FSID_DEV:
+			if (!old_valid_dev(ex_dev))
+				goto retry;
+			/* FALL THROUGH */
+		case FSID_MAJOR_MINOR:
+		case FSID_ENCODE_DEV:
+			if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags
+			      & FS_REQUIRES_DEV))
+				goto retry;
+			break;
+		case FSID_NUM:
+			if (! (exp->ex_flags & NFSEXP_FSID))
+				goto retry;
+			break;
+		case FSID_UUID8:
+		case FSID_UUID16:
+			if (!root_export)
+				goto retry;
+			/* fall through */
+		case FSID_UUID4_INUM:
+		case FSID_UUID16_INUM:
+			if (exp->ex_uuid == NULL)
+				goto retry;
+			break;
+		}
 	} else if (exp->ex_uuid) {
 		if (fhp->fh_maxsize >= 64) {
 			if (root_export)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 5cc2eec..b2c7147 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -155,7 +155,7 @@
 				argp->count);
 		argp->count = NFSSVC_MAXBLKSIZE_V2;
 	}
-	svc_reserve(rqstp, (19<<2) + argp->count + 4);
+	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
 	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 0c24b9e..cb3e7fa 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -231,9 +231,10 @@
 nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_sattrargs *args)
 {
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = decode_sattr(p, &args->attrs)))
+	p = decode_fh(p, &args->fh);
+	if (!p)
 		return 0;
+	p = decode_sattr(p, &args->attrs);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -284,8 +285,9 @@
 nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_writeargs *args)
 {
-	unsigned int len;
+	unsigned int len, hdr, dlen;
 	int v;
+
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
 
@@ -293,11 +295,30 @@
 	args->offset = ntohl(*p++);	/* offset */
 	p++;				/* totalcount */
 	len = args->len = ntohl(*p++);
-	rqstp->rq_vec[0].iov_base = (void*)p;
-	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
-				(((void*)p) - rqstp->rq_arg.head[0].iov_base);
+	/*
+	 * The protocol specifies a maximum of 8192 bytes.
+	 */
 	if (len > NFSSVC_MAXBLKSIZE_V2)
-		len = NFSSVC_MAXBLKSIZE_V2;
+		return 0;
+
+	/*
+	 * Check to make sure that we got the right number of
+	 * bytes.
+	 */
+	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+		- hdr;
+
+	/*
+	 * Round the length of the data which was specified up to
+	 * the next multiple of XDR units and then compare that
+	 * against the length which was actually received.
+	 */
+	if (dlen != XDR_QUADLEN(len)*4)
+		return 0;
+
+	rqstp->rq_vec[0].iov_base = (void*)p;
+	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
 	v = 0;
 	while (len > rqstp->rq_vec[v].iov_len) {
 		len -= rqstp->rq_vec[v].iov_len;
@@ -306,18 +327,18 @@
 		rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 	}
 	rqstp->rq_vec[v].iov_len = len;
-	args->vlen = v+1;
-	return rqstp->rq_vec[0].iov_len > 0;
+	args->vlen = v + 1;
+	return 1;
 }
 
 int
 nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_createargs *args)
 {
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = decode_filename(p, &args->name, &args->len))
-	 || !(p = decode_sattr(p, &args->attrs)))
+	if (   !(p = decode_fh(p, &args->fh))
+	    || !(p = decode_filename(p, &args->name, &args->len)))
 		return 0;
+	p = decode_sattr(p, &args->attrs);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -361,11 +382,11 @@
 nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
 					struct nfsd_symlinkargs *args)
 {
-	if (!(p = decode_fh(p, &args->ffh))
-	 || !(p = decode_filename(p, &args->fname, &args->flen))
-	 || !(p = decode_pathname(p, &args->tname, &args->tlen))
-	 || !(p = decode_sattr(p, &args->attrs)))
+	if (   !(p = decode_fh(p, &args->ffh))
+	    || !(p = decode_filename(p, &args->fname, &args->flen))
+	    || !(p = decode_pathname(p, &args->tname, &args->tlen)))
 		return 0;
+	p = decode_sattr(p, &args->attrs);
 
 	return xdr_argsize_check(rqstp, p);
 }
diff --git a/fs/open.c b/fs/open.c
index ca9981c..0d515d1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -210,6 +210,9 @@
 		newattrs.ia_valid |= ATTR_FILE;
 	}
 
+	/* Remove suid/sgid on truncate too */
+	newattrs.ia_valid |= should_remove_suid(dentry);
+
 	mutex_lock(&dentry->d_inode->i_mutex);
 	err = notify_change(dentry, &newattrs);
 	mutex_unlock(&dentry->d_inode->i_mutex);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3c41149..a5fa1fd 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -708,6 +708,7 @@
 	.write		= oom_adjust_write,
 };
 
+#ifdef CONFIG_MMU
 static ssize_t clear_refs_write(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
@@ -741,6 +742,7 @@
 static struct file_operations proc_clear_refs_operations = {
 	.write		= clear_refs_write,
 };
+#endif
 
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index ab45db5..9e451a6 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1059,20 +1059,12 @@
 	   maping blocks, since there is none, so we just zero out remaining
 	   parts of first and last pages in write area (if needed) */
 	if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) {
-		if (from != 0) {	/* First page needs to be partially zeroed */
-			char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
-			memset(kaddr, 0, from);
-			kunmap_atomic(kaddr, KM_USER0);
-			flush_dcache_page(prepared_pages[0]);
-		}
-		if (to != PAGE_CACHE_SIZE) {	/* Last page needs to be partially zeroed */
-			char *kaddr =
-			    kmap_atomic(prepared_pages[num_pages - 1],
-					KM_USER0);
-			memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-			kunmap_atomic(kaddr, KM_USER0);
-			flush_dcache_page(prepared_pages[num_pages - 1]);
-		}
+		if (from != 0)		/* First page needs to be partially zeroed */
+			zero_user_page(prepared_pages[0], 0, from, KM_USER0);
+
+		if (to != PAGE_CACHE_SIZE)	/* Last page needs to be partially zeroed */
+			zero_user_page(prepared_pages[num_pages-1], to,
+					PAGE_CACHE_SIZE - to, KM_USER0);
 
 		/* Since all blocks are new - use already calculated value */
 		return blocks;
@@ -1199,13 +1191,9 @@
 					ll_rw_block(READ, 1, &bh);
 					*wait_bh++ = bh;
 				} else {	/* Not mapped, zero it */
-					char *kaddr =
-					    kmap_atomic(prepared_pages[0],
-							KM_USER0);
-					memset(kaddr + block_start, 0,
-					       from - block_start);
-					kunmap_atomic(kaddr, KM_USER0);
-					flush_dcache_page(prepared_pages[0]);
+					zero_user_page(prepared_pages[0],
+						       block_start,
+						       from - block_start, KM_USER0);
 					set_buffer_uptodate(bh);
 				}
 			}
@@ -1237,13 +1225,8 @@
 					ll_rw_block(READ, 1, &bh);
 					*wait_bh++ = bh;
 				} else {	/* Not mapped, zero it */
-					char *kaddr =
-					    kmap_atomic(prepared_pages
-							[num_pages - 1],
-							KM_USER0);
-					memset(kaddr + to, 0, block_end - to);
-					kunmap_atomic(kaddr, KM_USER0);
-					flush_dcache_page(prepared_pages[num_pages - 1]);
+					zero_user_page(prepared_pages[num_pages-1],
+							to, block_end - to, KM_USER0);
 					set_buffer_uptodate(bh);
 				}
 			}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 9fcbfe3..1272d11 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2148,13 +2148,8 @@
 		length = offset & (blocksize - 1);
 		/* if we are not on a block boundary */
 		if (length) {
-			char *kaddr;
-
 			length = blocksize - length;
-			kaddr = kmap_atomic(page, KM_USER0);
-			memset(kaddr + offset, 0, length);
-			flush_dcache_page(page);
-			kunmap_atomic(kaddr, KM_USER0);
+			zero_user_page(page, offset, length, KM_USER0);
 			if (buffer_mapped(bh) && bh->b_blocknr != 0) {
 				mark_buffer_dirty(bh);
 			}
@@ -2370,7 +2365,6 @@
 	 ** last byte in the file
 	 */
 	if (page->index >= end_index) {
-		char *kaddr;
 		unsigned last_offset;
 
 		last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
@@ -2379,10 +2373,7 @@
 			unlock_page(page);
 			return 0;
 		}
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset);
-		flush_dcache_page(page);
-		kunmap_atomic(kaddr, KM_USER0);
+		zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0);
 	}
 	bh = head;
 	block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index e073fd8..f25086a 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1110,7 +1110,7 @@
 	if (!barrier) {
 		/* If there was a write error in the journal - we can't commit
 		 * this transaction - it will be invalid and, if successful,
-		 * will just end up propogating the write error out to
+		 * will just end up propagating the write error out to
 		 * the file system. */
 		if (likely(!retval && !reiserfs_is_journal_aborted (journal))) {
 			if (buffer_dirty(jl->j_commit_bh))
@@ -1125,7 +1125,7 @@
 
 	/* If there was a write error in the journal - we can't commit this
 	 * transaction - it will be invalid and, if successful, will just end
-	 * up propogating the write error out to the filesystem. */
+	 * up propagating the write error out to the filesystem. */
 	if (unlikely(!buffer_uptodate(jl->j_commit_bh))) {
 #ifdef CONFIG_REISERFS_CHECK
 		reiserfs_warning(s, "journal-615: buffer write failed");
diff --git a/fs/select.c b/fs/select.c
index d862241..a974082 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -64,7 +64,7 @@
 
 static void free_poll_entry(struct poll_table_entry *entry)
 {
-	remove_wait_queue(entry->wait_address,&entry->wait);
+	remove_wait_queue(entry->wait_address, &entry->wait);
 	fput(entry->filp);
 }
 
@@ -128,7 +128,7 @@
 	entry->filp = filp;
 	entry->wait_address = wait_address;
 	init_waitqueue_entry(&entry->wait, current);
-	add_wait_queue(wait_address,&entry->wait);
+	add_wait_queue(wait_address, &entry->wait);
 }
 
 #define FDS_IN(fds, n)		(fds->in + n)
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 0e637ad..b502c71 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -111,36 +111,6 @@
 	return ret;
 }
 
-
-/**
- *	flush_read_buffer - push buffer to userspace.
- *	@buffer:	data buffer for file.
- *	@buf:		user-passed buffer.
- *	@count:		number of bytes requested.
- *	@ppos:		file position.
- *
- *	Copy the buffer we filled in fill_read_buffer() to userspace.
- *	This is done at the reader's leisure, copying and advancing 
- *	the amount they specify each time.
- *	This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf,
-			     size_t count, loff_t * ppos)
-{
-	int error;
-
-	if (*ppos > buffer->count)
-		return 0;
-
-	if (count > (buffer->count - *ppos))
-		count = buffer->count - *ppos;
-
-	error = copy_to_user(buf,buffer->page + *ppos,count);
-	if (!error)
-		*ppos += count;
-	return error ? -EFAULT : count;
-}
-
 /**
  *	sysfs_read_file - read an attribute. 
  *	@file:	file pointer.
@@ -177,7 +147,8 @@
 	}
 	pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
 		 __FUNCTION__, count, *ppos, buffer->page);
-	retval = flush_read_buffer(buffer,buf,count,ppos);
+	retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+					 buffer->count);
 out:
 	up(&buffer->sem);
 	return retval;
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 7775ddc..e725ddd 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -809,7 +809,7 @@
 				xfs_buf_relse(agbp);
 				agbp = NULL;
 				/*
-				 * Move up the the last inode in the current
+				 * Move up the last inode in the current
 				 * chunk.  The lookup_ge will always get
 				 * us the first inode in the next chunk.
 				 */
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index f5aa3ef..a96bde6 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1734,11 +1734,13 @@
 			per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		/* Easy Case - initialize the area and locks, and
 		 * then rebalance when online does everything else for us. */
 		memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
 		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		xfs_icsb_lock(mp);
 		xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
 		xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
@@ -1746,6 +1748,7 @@
 		xfs_icsb_unlock(mp);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		/* Disable all the counters, then fold the dead cpu's
 		 * count into the total on the global superblock and
 		 * re-enable the counters. */
diff --git a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h
index a1a1eca..286e1d84 100644
--- a/include/asm-alpha/smp.h
+++ b/include/asm-alpha/smp.h
@@ -51,6 +51,7 @@
 
 #else /* CONFIG_SMP */
 
+#define hard_smp_processor_id()		0
 #define smp_call_function_on_cpu(func,info,retry,wait,cpu)    ({ 0; })
 
 #endif /* CONFIG_SMP */
diff --git a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h
index eeb3bef..f4defc2 100644
--- a/include/asm-alpha/thread_info.h
+++ b/include/asm-alpha/thread_info.h
@@ -97,7 +97,7 @@
 				 1 << TIF_UAC_SIGBUS)
 
 #define SET_UNALIGN_CTL(task,value)	({				     \
-	(task)->thread_info->flags = (((task)->thread_info->flags &	     \
+	task_thread_info(task)->flags = ((task_thread_info(task)->flags &    \
 		~ALPHA_UAC_MASK)					     \
 		| (((value) << ALPHA_UAC_SHIFT)       & (1<<TIF_UAC_NOPRINT))\
 		| (((value) << (ALPHA_UAC_SHIFT + 1)) & (1<<TIF_UAC_SIGBUS)) \
@@ -105,11 +105,11 @@
 	0; })
 
 #define GET_UNALIGN_CTL(task,value)	({				\
-	put_user(((task)->thread_info->flags & (1 << TIF_UAC_NOPRINT))	\
+	put_user((task_thread_info(task)->flags & (1 << TIF_UAC_NOPRINT))\
 		  >> ALPHA_UAC_SHIFT					\
-		 | ((task)->thread_info->flags & (1 << TIF_UAC_SIGBUS))	\
+		 | (task_thread_info(task)->flags & (1 << TIF_UAC_SIGBUS))\
 		 >> (ALPHA_UAC_SHIFT + 1)				\
-		 | ((task)->thread_info->flags & (1 << TIF_UAC_NOFIX))	\
+		 | (task_thread_info(task)->flags & (1 << TIF_UAC_NOFIX))\
 		 >> (ALPHA_UAC_SHIFT - 1),				\
 		 (int __user *)(value));				\
 	})
diff --git a/include/asm-arm/arch-at91/at91rm9200.h b/include/asm-arm/arch-at91/at91rm9200.h
index a12ac8a..802891a 100644
--- a/include/asm-arm/arch-at91/at91rm9200.h
+++ b/include/asm-arm/arch-at91/at91rm9200.h
@@ -107,185 +107,4 @@
 #define AT91RM9200_UHP_BASE	0x00300000	/* USB Host controller */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_MISO		(1 <<  0)	/* A: SPI Master-In Slave-Out */
-#define AT91_PA0_PCK3		(1 <<  0)	/* B: PMC Programmable Clock Output 3 */
-#define AT91_PA1_MOSI		(1 <<  1)	/* A: SPI Master-Out Slave-In */
-#define AT91_PA1_PCK0		(1 <<  1)	/* B: PMC Programmable Clock Output 0 */
-#define AT91_PA2_SPCK		(1 <<  2)	/* A: SPI Serial Clock */
-#define AT91_PA2_IRQ4		(1 <<  2)	/* B: External Interrupt 4 */
-#define AT91_PA3_NPCS0		(1 <<  3)	/* A: SPI Peripheral Chip Select 0 */
-#define AT91_PA3_IRQ5		(1 <<  3)	/* B: External Interrupt 5 */
-#define AT91_PA4_NPCS1		(1 <<  4)	/* A: SPI Peripheral Chip Select 1 */
-#define AT91_PA4_PCK1		(1 <<  4)	/* B: PMC Programmable Clock Output 1 */
-#define AT91_PA5_NPCS2		(1 <<  5)	/* A: SPI Peripheral Chip Select 2 */
-#define AT91_PA5_TXD3		(1 <<  5)	/* B: USART Transmit Data 3 */
-#define AT91_PA6_NPCS3		(1 <<  6)	/* A: SPI Peripheral Chip Select 3 */
-#define AT91_PA6_RXD3		(1 <<  6)	/* B: USART Receive Data 3 */
-#define AT91_PA7_ETXCK_EREFCK	(1 <<  7)	/* A: Ethernet Reference Clock / Transmit Clock */
-#define AT91_PA7_PCK2		(1 <<  7)	/* B: PMC Programmable Clock Output 2 */
-#define AT91_PA8_ETXEN		(1 <<  8)	/* A: Ethernet Transmit Enable */
-#define AT91_PA8_MCCDB		(1 <<  8)	/* B: MMC Multimedia Card B Command */
-#define AT91_PA9_ETX0		(1 <<  9)	/* A: Ethernet Transmit Data 0 */
-#define AT91_PA9_MCDB0		(1 <<  9)	/* B: MMC Multimedia Card B Data 0 */
-#define AT91_PA10_ETX1		(1 << 10)	/* A: Ethernet Transmit Data 1 */
-#define AT91_PA10_MCDB1		(1 << 10)	/* B: MMC Multimedia Card B Data 1 */
-#define AT91_PA11_ECRS_ECRSDV	(1 << 11)	/* A: Ethernet Carrier Sense / Data Valid */
-#define AT91_PA11_MCDB2		(1 << 11)	/* B: MMC Multimedia Card B Data 2 */
-#define AT91_PA12_ERX0		(1 << 12)	/* A: Ethernet Receive Data 0 */
-#define AT91_PA12_MCDB3		(1 << 12)	/* B: MMC Multimedia Card B Data 3 */
-#define AT91_PA13_ERX1		(1 << 13)	/* A: Ethernet Receive Data 1 */
-#define AT91_PA13_TCLK0		(1 << 13)	/* B: TC External Clock Input 0 */
-#define AT91_PA14_ERXER		(1 << 14)	/* A: Ethernet Receive Error */
-#define AT91_PA14_TCLK1		(1 << 14)	/* B: TC External Clock Input 1 */
-#define AT91_PA15_EMDC		(1 << 15)	/* A: Ethernet Management Data Clock */
-#define AT91_PA15_TCLK2		(1 << 15)	/* B: TC External Clock Input 2 */
-#define AT91_PA16_EMDIO		(1 << 16)	/* A: Ethernet Management Data I/O */
-#define AT91_PA16_IRQ6		(1 << 16)	/* B: External Interrupt 6 */
-#define AT91_PA17_TXD0		(1 << 17)	/* A: USART Transmit Data 0 */
-#define AT91_PA17_TIOA0		(1 << 17)	/* B: TC I/O Line A 0 */
-#define AT91_PA18_RXD0		(1 << 18)	/* A: USART Receive Data 0 */
-#define AT91_PA18_TIOB0		(1 << 18)	/* B: TC I/O Line B 0 */
-#define AT91_PA19_SCK0		(1 << 19)	/* A: USART Serial Clock 0 */
-#define AT91_PA19_TIOA1		(1 << 19)	/* B: TC I/O Line A 1 */
-#define AT91_PA20_CTS0		(1 << 20)	/* A: USART Clear To Send 0 */
-#define AT91_PA20_TIOB1		(1 << 20)	/* B: TC I/O Line B 1 */
-#define AT91_PA21_RTS0		(1 << 21)	/* A: USART Ready To Send 0 */
-#define AT91_PA21_TIOA2		(1 << 21)	/* B: TC I/O Line A 2 */
-#define AT91_PA22_RXD2		(1 << 22)	/* A: USART Receive Data 2 */
-#define AT91_PA22_TIOB2		(1 << 22)	/* B: TC I/O Line B 2 */
-#define AT91_PA23_TXD2		(1 << 23)	/* A: USART Transmit Data 2 */
-#define AT91_PA23_IRQ3		(1 << 23)	/* B: External Interrupt 3 */
-#define AT91_PA24_SCK2		(1 << 24)	/* A: USART Serial Clock 2 */
-#define AT91_PA24_PCK1		(1 << 24)	/* B: PMC Programmable Clock Output 1 */
-#define AT91_PA25_TWD		(1 << 25)	/* A: TWI Two-wire Serial Data */
-#define AT91_PA25_IRQ2		(1 << 25)	/* B: External Interrupt 2 */
-#define AT91_PA26_TWCK		(1 << 26)	/* A: TWI Two-wire Serial Clock */
-#define AT91_PA26_IRQ1		(1 << 26)	/* B: External Interrupt 1 */
-#define AT91_PA27_MCCK		(1 << 27)	/* A: MMC Multimedia Card Clock */
-#define AT91_PA27_TCLK3		(1 << 27)	/* B: TC External Clock Input 3 */
-#define AT91_PA28_MCCDA		(1 << 28)	/* A: MMC Multimedia Card A Command */
-#define AT91_PA28_TCLK4		(1 << 28)	/* B: TC External Clock Input 4 */
-#define AT91_PA29_MCDA0		(1 << 29)	/* A: MMC Multimedia Card A Data 0 */
-#define AT91_PA29_TCLK5		(1 << 29)	/* B: TC External Clock Input 5 */
-#define AT91_PA30_DRXD		(1 << 30)	/* A: DBGU Receive Data */
-#define AT91_PA30_CTS2		(1 << 30)	/* B: USART Clear To Send 2 */
-#define AT91_PA31_DTXD		(1 << 31)	/* A: DBGU Transmit Data */
-#define AT91_PA31_RTS2		(1 << 31)	/* B: USART Ready To Send 2 */
-
-#define AT91_PB0_TF0		(1 <<  0)	/* A: SSC Transmit Frame Sync 0 */
-#define AT91_PB0_RTS3		(1 <<  0)	/* B: USART Ready To Send 3 */
-#define AT91_PB1_TK0		(1 <<  1)	/* A: SSC Transmit Clock 0 */
-#define AT91_PB1_CTS3		(1 <<  1)	/* B: USART Clear To Send 3 */
-#define AT91_PB2_TD0		(1 <<  2)	/* A: SSC Transmit Data 0 */
-#define AT91_PB2_SCK3		(1 <<  2)	/* B: USART Serial Clock 3 */
-#define AT91_PB3_RD0		(1 <<  3)	/* A: SSC Receive Data 0 */
-#define AT91_PB3_MCDA1		(1 <<  3)	/* B: MMC Multimedia Card A Data 1 */
-#define AT91_PB4_RK0		(1 <<  4)	/* A: SSC Receive Clock 0 */
-#define AT91_PB4_MCDA2		(1 <<  4)	/* B: MMC Multimedia Card A Data 2 */
-#define AT91_PB5_RF0		(1 <<  5)	/* A: SSC Receive Frame Sync 0 */
-#define AT91_PB5_MCDA3		(1 <<  5)	/* B: MMC Multimedia Card A Data 3 */
-#define AT91_PB6_TF1		(1 <<  6)	/* A: SSC Transmit Frame Sync 1 */
-#define AT91_PB6_TIOA3		(1 <<  6)	/* B: TC I/O Line A 3 */
-#define AT91_PB7_TK1		(1 <<  7)	/* A: SSC Transmit Clock 1 */
-#define AT91_PB7_TIOB3		(1 <<  7)	/* B: TC I/O Line B 3 */
-#define AT91_PB8_TD1		(1 <<  8)	/* A: SSC Transmit Data 1 */
-#define AT91_PB8_TIOA4		(1 <<  8)	/* B: TC I/O Line A 4 */
-#define AT91_PB9_RD1		(1 <<  9)	/* A: SSC Receive Data 1 */
-#define AT91_PB9_TIOB4		(1 <<  9)	/* B: TC I/O Line B 4 */
-#define AT91_PB10_RK1		(1 << 10)	/* A: SSC Receive Clock 1 */
-#define AT91_PB10_TIOA5		(1 << 10)	/* B: TC I/O Line A 5 */
-#define AT91_PB11_RF1		(1 << 11)	/* A: SSC Receive Frame Sync 1 */
-#define AT91_PB11_TIOB5		(1 << 11)	/* B: TC I/O Line B 5 */
-#define AT91_PB12_TF2		(1 << 12)	/* A: SSC Transmit Frame Sync 2 */
-#define AT91_PB12_ETX2		(1 << 12)	/* B: Ethernet Transmit Data 2 */
-#define AT91_PB13_TK2		(1 << 13)	/* A: SSC Transmit Clock 3 */
-#define AT91_PB13_ETX3		(1 << 13)	/* B: Ethernet Transmit Data 3 */
-#define AT91_PB14_TD2		(1 << 14)	/* A: SSC Transmit Data 2 */
-#define AT91_PB14_ETXER		(1 << 14)	/* B: Ethernet Transmit Coding Error */
-#define AT91_PB15_RD2		(1 << 15)	/* A: SSC Receive Data 2 */
-#define AT91_PB15_ERX2		(1 << 15)	/* B: Ethernet Receive Data 2 */
-#define AT91_PB16_RK2		(1 << 16)	/* A: SSC Receive Clock 2 */
-#define AT91_PB16_ERX3		(1 << 16)	/* B: Ethernet Receive Data 3 */
-#define AT91_PB17_RF2		(1 << 17)	/* A: SSC Receive Frame Sync 2 */
-#define AT91_PB17_ERXDV		(1 << 17)	/* B: Ethernet Receive Data Valid */
-#define AT91_PB18_RI1		(1 << 18)	/* A: USART Ring Indicator 1 */
-#define AT91_PB18_ECOL		(1 << 18)	/* B: Ethernet Collision Detected */
-#define AT91_PB19_DTR1		(1 << 19)	/* A: USART Data Terminal Ready 1 */
-#define AT91_PB19_ERXCK		(1 << 19)	/* B: Ethernet Receive Clock */
-#define AT91_PB20_TXD1		(1 << 20)	/* A: USART Transmit Data 1 */
-#define AT91_PB21_RXD1		(1 << 21)	/* A: USART Receive Data 1 */
-#define AT91_PB22_SCK1		(1 << 22)	/* A: USART Serial Clock 1 */
-#define AT91_PB23_DCD1		(1 << 23)	/* A: USART Data Carrier Detect 1 */
-#define AT91_PB24_CTS1		(1 << 24)	/* A: USART Clear To Send 1 */
-#define AT91_PB25_DSR1		(1 << 25)	/* A: USART Data Set Ready 1 */
-#define AT91_PB25_EF100		(1 << 25)	/* B: Ethernet Force 100 Mbit */
-#define AT91_PB26_RTS1		(1 << 26)	/* A: USART Ready To Send 1 */
-#define AT91_PB27_PCK0		(1 << 27)	/* B: PMC Programmable Clock Output 0 */
-#define AT91_PB28_FIQ		(1 << 28)	/* A: Fast Interrupt */
-#define AT91_PB29_IRQ0		(1 << 29)	/* A: External Interrupt 0 */
-
-#define AT91_PC0_BFCK		(1 <<  0)	/* A: Burst Flash Clock */
-#define AT91_PC1_BFRDY_SMOE	(1 <<  1)	/* A: Burst Flash Ready / SmartMedia Output Enable */
-#define AT91_PC2_BFAVD		(1 <<  2)	/* A: Burst Flash Address Valid */
-#define AT91_PC3_BFBAA_SMWE	(1 <<  3)	/* A: Burst Flash Address Advance / SmartMedia Write Enable */
-#define AT91_PC4_BFOE		(1 <<  4)	/* A: Burst Flash Output Enable */
-#define AT91_PC5_BFWE		(1 <<  5)	/* A: Burst Flash Write Enable */
-#define AT91_PC6_NWAIT		(1 <<  6)	/* A: SMC Wait Signal */
-#define AT91_PC7_A23		(1 <<  7)	/* A: Address Bus 23 */
-#define AT91_PC8_A24		(1 <<  8)	/* A: Address Bus 24 */
-#define AT91_PC9_A25_CFRNW	(1 <<  9)	/* A: Address Bus 25 / Compact Flash Read Not Write */
-#define AT91_PC10_NCS4_CFCS	(1 << 10)	/* A: SMC Chip Select 4 / Compact Flash Chip Select */
-#define AT91_PC11_NCS5_CFCE1	(1 << 11)	/* A: SMC Chip Select 5 / Compact Flash Chip Enable 1 */
-#define AT91_PC12_NCS6_CFCE2	(1 << 12)	/* A: SMC Chip Select 6 / Compact Flash Chip Enable 2 */
-#define AT91_PC13_NCS7		(1 << 13)	/* A: Chip Select 7 */
-
-#define AT91_PD0_ETX0		(1 <<  0)	/* A: Ethernet Transmit Data 0 */
-#define AT91_PD1_ETX1		(1 <<  1)	/* A: Ethernet Transmit Data 1 */
-#define AT91_PD2_ETX2		(1 <<  2)	/* A: Ethernet Transmit Data 2 */
-#define AT91_PD3_ETX3		(1 <<  3)	/* A: Ethernet Transmit Data 3 */
-#define AT91_PD4_ETXEN		(1 <<  4)	/* A: Ethernet Transmit Enable */
-#define AT91_PD5_ETXER		(1 <<  5)	/* A: Ethernet Transmit Coding Error */
-#define AT91_PD6_DTXD		(1 <<  6)	/* A: DBGU Transmit Data */
-#define AT91_PD7_PCK0		(1 <<  7)	/* A: PMC Programmable Clock Output 0 */
-#define AT91_PD7_TSYNC		(1 <<  7)	/* B: ETM Trace Synchronization Signal */
-#define AT91_PD8_PCK1		(1 <<  8)	/* A: PMC Programmable Clock Output 1 */
-#define AT91_PD8_TCLK		(1 <<  8)	/* B: ETM Trace Clock */
-#define AT91_PD9_PCK2		(1 <<  9)	/* A: PMC Programmable Clock Output 2 */
-#define AT91_PD9_TPS0		(1 <<  9)	/* B: ETM Trace ARM Pipeline Status 0 */
-#define AT91_PD10_PCK3		(1 << 10)	/* A: PMC Programmable Clock Output 3 */
-#define AT91_PD10_TPS1		(1 << 10)	/* B: ETM Trace ARM Pipeline Status 1 */
-#define AT91_PD11_TPS2		(1 << 11)	/* B: ETM Trace ARM Pipeline Status 2 */
-#define AT91_PD12_TPK0		(1 << 12)	/* B: ETM Trace Packet Port 0 */
-#define AT91_PD13_TPK1		(1 << 13)	/* B: ETM Trace Packet Port 1 */
-#define AT91_PD14_TPK2		(1 << 14)	/* B: ETM Trace Packet Port 2 */
-#define AT91_PD15_TD0		(1 << 15)	/* A: SSC Transmit Data 0 */
-#define AT91_PD15_TPK3		(1 << 15)	/* B: ETM Trace Packet Port 3 */
-#define AT91_PD16_TD1		(1 << 16)	/* A: SSC Transmit Data 1 */
-#define AT91_PD16_TPK4		(1 << 16)	/* B: ETM Trace Packet Port 4 */
-#define AT91_PD17_TD2		(1 << 17)	/* A: SSC Transmit Data 2 */
-#define AT91_PD17_TPK5		(1 << 17)	/* B: ETM Trace Packet Port 5 */
-#define AT91_PD18_NPCS1		(1 << 18)	/* A: SPI Peripheral Chip Select 1 */
-#define AT91_PD18_TPK6		(1 << 18)	/* B: ETM Trace Packet Port 6 */
-#define AT91_PD19_NPCS2		(1 << 19)	/* A: SPI Peripheral Chip Select 2 */
-#define AT91_PD19_TPK7		(1 << 19)	/* B: ETM Trace Packet Port 7 */
-#define AT91_PD20_NPCS3		(1 << 20)	/* A: SPI Peripheral Chip Select 3 */
-#define AT91_PD20_TPK8		(1 << 20)	/* B: ETM Trace Packet Port 8 */
-#define AT91_PD21_RTS0		(1 << 21)	/* A: USART Ready To Send 0 */
-#define AT91_PD21_TPK9		(1 << 21)	/* B: ETM Trace Packet Port 9 */
-#define AT91_PD22_RTS1		(1 << 22)	/* A: USART Ready To Send 1 */
-#define AT91_PD22_TPK10		(1 << 22)	/* B: ETM Trace Packet Port 10 */
-#define AT91_PD23_RTS2		(1 << 23)	/* A: USART Ready To Send 2 */
-#define AT91_PD23_TPK11		(1 << 23)	/* B: ETM Trace Packet Port 11 */
-#define AT91_PD24_RTS3		(1 << 24)	/* A: USART Ready To Send 3 */
-#define AT91_PD24_TPK12		(1 << 24)	/* B: ETM Trace Packet Port 12 */
-#define AT91_PD25_DTR1		(1 << 25)	/* A: USART Data Terminal Ready 1 */
-#define AT91_PD25_TPK13		(1 << 25)	/* B: ETM Trace Packet Port 13 */
-#define AT91_PD26_TPK14		(1 << 26)	/* B: ETM Trace Packet Port 14 */
-#define AT91_PD27_TPK15		(1 << 27)	/* B: ETM Trace Packet Port 15 */
-#endif
-
 #endif
diff --git a/include/asm-arm/arch-at91/at91sam9260.h b/include/asm-arm/arch-at91/at91sam9260.h
index 2cadebc..0427f86 100644
--- a/include/asm-arm/arch-at91/at91sam9260.h
+++ b/include/asm-arm/arch-at91/at91sam9260.h
@@ -117,13 +117,4 @@
 #define AT91SAM9XE_SRAM_BASE	0x00300000	/* Internal SRAM base address */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
-
 #endif
diff --git a/include/asm-arm/arch-at91/at91sam9261.h b/include/asm-arm/arch-at91/at91sam9261.h
index 01b58ff..9eb4595 100644
--- a/include/asm-arm/arch-at91/at91sam9261.h
+++ b/include/asm-arm/arch-at91/at91sam9261.h
@@ -98,195 +98,4 @@
 #define AT91SAM9261_LCDC_BASE	0x00600000	/* LDC controller */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_SPI0_MISO	(1 <<  0)	/* A: SPI0 Master In Slave */
-#define AT91_PA0_MCDA0		(1 <<  0)	/* B: Multimedia Card A Data 0 */
-#define AT91_PA1_SPI0_MOSI	(1 <<  1)	/* A: SPI0 Master Out Slave */
-#define AT91_PA1_MCCDA		(1 <<  1)	/* B: Multimedia Card A Command */
-#define AT91_PA2_SPI0_SPCK	(1 <<  2)	/* A: SPI0 Serial Clock */
-#define AT91_PA2_MCCK		(1 <<  2)	/* B: Multimedia Card Clock */
-#define AT91_PA3_SPI0_NPCS0	(1 <<  3)	/* A: SPI0 Peripheral Chip Select 0 */
-#define AT91_PA4_SPI0_NPCS1	(1 <<  4)	/* A: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA4_MCDA1		(1 <<  4)	/* B: Multimedia Card A Data 1 */
-#define AT91_PA5_SPI0_NPCS2	(1 <<  5)	/* A: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA5_MCDA2		(1 <<  5)	/* B: Multimedia Card A Data 2 */
-#define AT91_PA6_SPI0_NPCS3	(1 <<  6)	/* A: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA6_MCDA3		(1 <<  6)	/* B: Multimedia Card A Data 3 */
-#define AT91_PA7_TWD		(1 <<  7)	/* A: TWI Two-wire Serial Data */
-#define AT91_PA7_PCK0		(1 <<  7)	/* B: PMC Programmable clock Output 0 */
-#define AT91_PA8_TWCK		(1 <<  8)	/* A: TWI Two-wire Serial Clock */
-#define AT91_PA8_PCK1		(1 <<  8)	/* B: PMC Programmable clock Output 1 */
-#define AT91_PA9_DRXD		(1 <<  9)	/* A: DBGU Debug Receive Data */
-#define AT91_PA9_PCK2		(1 <<  9)	/* B: PMC Programmable clock Output 2 */
-#define AT91_PA10_DTXD		(1 << 10)	/* A: DBGU Debug Transmit Data */
-#define AT91_PA10_PCK3		(1 << 10)	/* B: PMC Programmable clock Output 3 */
-#define AT91_PA11_TSYNC		(1 << 11)	/* A: Trace Synchronization Signal */
-#define AT91_PA11_SCK1		(1 << 11)	/* B: USART1 Serial Clock */
-#define AT91_PA12_TCLK		(1 << 12)	/* A: Trace Clock */
-#define AT91_PA12_RTS1		(1 << 12)	/* B: USART1 Ready To Send */
-#define AT91_PA13_TPS0		(1 << 13)	/* A: Trace ARM Pipeline Status 0 */
-#define AT91_PA13_CTS1		(1 << 13)	/* B: USART1 Clear To Send */
-#define AT91_PA14_TPS1		(1 << 14)	/* A: Trace ARM Pipeline Status 1 */
-#define AT91_PA14_SCK2		(1 << 14)	/* B: USART2 Serial Clock */
-#define AT91_PA15_TPS2		(1 << 15)	/* A: Trace ARM Pipeline Status 2 */
-#define AT91_PA15_RTS2		(1 << 15)	/* B: USART2 Ready To Send */
-#define AT91_PA16_TPK0		(1 << 16)	/* A: Trace Packet Port 0 */
-#define AT91_PA16_CTS2		(1 << 16)	/* B: USART2 Clear To Send */
-#define AT91_PA17_TPK1		(1 << 17)	/* A: Trace Packet Port 1 */
-#define AT91_PA17_TF1		(1 << 17)	/* B: SSC1 Transmit Frame Sync */
-#define AT91_PA18_TPK2		(1 << 18)	/* A: Trace Packet Port 2 */
-#define AT91_PA18_TK1		(1 << 18)	/* B: SSC1 Transmit Clock */
-#define AT91_PA19_TPK3		(1 << 19)	/* A: Trace Packet Port 3 */
-#define AT91_PA19_TD1		(1 << 19)	/* B: SSC1 Transmit Data */
-#define AT91_PA20_TPK4		(1 << 20)	/* A: Trace Packet Port 4 */
-#define AT91_PA20_RD1		(1 << 20)	/* B: SSC1 Receive Data */
-#define AT91_PA21_TPK5		(1 << 21)	/* A: Trace Packet Port 5 */
-#define AT91_PA21_RK1		(1 << 21)	/* B: SSC1 Receive Clock */
-#define AT91_PA22_TPK6		(1 << 22)	/* A: Trace Packet Port 6 */
-#define AT91_PA22_RF1		(1 << 22)	/* B: SSC1 Receive Frame Sync */
-#define AT91_PA23_TPK7		(1 << 23)	/* A: Trace Packet Port 7 */
-#define AT91_PA23_RTS0		(1 << 23)	/* B: USART0 Ready To Send */
-#define AT91_PA24_TPK8		(1 << 24)	/* A: Trace Packet Port 8 */
-#define AT91_PA24_SPI1_NPCS1	(1 << 24)	/* B: SPI1 Peripheral Chip Select 1 */
-#define AT91_PA25_TPK9		(1 << 25)	/* A: Trace Packet Port 9 */
-#define AT91_PA25_SPI1_NPCS2	(1 << 25)	/* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PA26_TPK10		(1 << 26)	/* A: Trace Packet Port 10 */
-#define AT91_PA26_SPI1_NPCS3	(1 << 26)	/* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PA27_TPK11		(1 << 27)	/* A: Trace Packet Port 11 */
-#define AT91_PA27_SPI0_NPCS1	(1 << 27)	/* B: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA28_TPK12		(1 << 28)	/* A: Trace Packet Port 12 */
-#define AT91_PA28_SPI0_NPCS2	(1 << 28)	/* B: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA29_TPK13		(1 << 29)	/* A: Trace Packet Port 13 */
-#define AT91_PA29_SPI0_NPCS3	(1 << 29)	/* B: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA30_TPK14		(1 << 30)	/* A: Trace Packet Port 14 */
-#define AT91_PA30_A23		(1 << 30)	/* B: Address Bus bit 23 */
-#define AT91_PA31_TPK15		(1 << 31)	/* A: Trace Packet Port 15 */
-#define AT91_PA31_A24		(1 << 31)	/* B: Address Bus bit 24 */
-
-#define AT91_PB0_LCDVSYNC	(1 <<  0)	/* A: LCD Vertical Synchronization */
-#define AT91_PB1_LCDHSYNC	(1 <<  1)	/* A: LCD Horizontal Synchronization */
-#define AT91_PB2_LCDDOTCK	(1 <<  2)	/* A: LCD Dot Clock */
-#define AT91_PB2_PCK0		(1 <<  2)	/* B: PMC Programmable clock Output 0 */
-#define AT91_PB3_LCDDEN		(1 <<  3)	/* A: LCD Data Enable */
-#define AT91_PB4_LCDCC		(1 <<  4)	/* A: LCD Contrast Control */
-#define AT91_PB4_LCDD2		(1 <<  4)	/* B: LCD Data Bus Bit 2 */
-#define AT91_PB5_LCDD0		(1 <<  5)	/* A: LCD Data Bus Bit 0 */
-#define AT91_PB5_LCDD3		(1 <<  5)	/* B: LCD Data Bus Bit 3 */
-#define AT91_PB6_LCDD1		(1 <<  6)	/* A: LCD Data Bus Bit 1 */
-#define AT91_PB6_LCDD4		(1 <<  6)	/* B: LCD Data Bus Bit 4 */
-#define AT91_PB7_LCDD2		(1 <<  7)	/* A: LCD Data Bus Bit 2 */
-#define AT91_PB7_LCDD5		(1 <<  7)	/* B: LCD Data Bus Bit 5 */
-#define AT91_PB8_LCDD3		(1 <<  8)	/* A: LCD Data Bus Bit 3 */
-#define AT91_PB8_LCDD6		(1 <<  8)	/* B: LCD Data Bus Bit 6 */
-#define AT91_PB9_LCDD4		(1 <<  9)	/* A: LCD Data Bus Bit 4 */
-#define AT91_PB9_LCDD7		(1 <<  9)	/* B: LCD Data Bus Bit 7 */
-#define AT91_PB10_LCDD5		(1 << 10)	/* A: LCD Data Bus Bit 5 */
-#define AT91_PB10_LCDD10	(1 << 10)	/* B: LCD Data Bus Bit 10 */
-#define AT91_PB11_LCDD6		(1 << 11)	/* A: LCD Data Bus Bit 6 */
-#define AT91_PB11_LCDD11	(1 << 11)	/* B: LCD Data Bus Bit 11 */
-#define AT91_PB12_LCDD7		(1 << 12)	/* A: LCD Data Bus Bit 7 */
-#define AT91_PB12_LCDD12	(1 << 12)	/* B: LCD Data Bus Bit 12 */
-#define AT91_PB13_LCDD8		(1 << 13)	/* A: LCD Data Bus Bit 8 */
-#define AT91_PB13_LCDD13	(1 << 13)	/* B: LCD Data Bus Bit 13 */
-#define AT91_PB14_LCDD9		(1 << 14)	/* A: LCD Data Bus Bit 9 */
-#define AT91_PB14_LCDD14	(1 << 14)	/* B: LCD Data Bus Bit 14 */
-#define AT91_PB15_LCDD10	(1 << 15)	/* A: LCD Data Bus Bit 10 */
-#define AT91_PB15_LCDD15	(1 << 15)	/* B: LCD Data Bus Bit 15 */
-#define AT91_PB16_LCDD11	(1 << 16)	/* A: LCD Data Bus Bit 11 */
-#define AT91_PB16_LCDD19	(1 << 16)	/* B: LCD Data Bus Bit 19 */
-#define AT91_PB17_LCDD12	(1 << 17)	/* A: LCD Data Bus Bit 12 */
-#define AT91_PB17_LCDD20	(1 << 17)	/* B: LCD Data Bus Bit 20 */
-#define AT91_PB18_LCDD13	(1 << 18)	/* A: LCD Data Bus Bit 13 */
-#define AT91_PB18_LCDD21	(1 << 18)	/* B: LCD Data Bus Bit 21 */
-#define AT91_PB19_LCDD14	(1 << 19)	/* A: LCD Data Bus Bit 14 */
-#define AT91_PB19_LCDD22	(1 << 19)	/* B: LCD Data Bus Bit 22 */
-#define AT91_PB20_LCDD15	(1 << 20)	/* A: LCD Data Bus Bit 15 */
-#define AT91_PB20_LCDD23	(1 << 20)	/* B: LCD Data Bus Bit 23 */
-#define AT91_PB21_TF0		(1 << 21)	/* A: SSC0 Transmit Frame Sync */
-#define AT91_PB21_LCDD16	(1 << 21)	/* B: LCD Data Bus Bit 16 */
-#define AT91_PB22_TK0		(1 << 22)	/* A: SSC0 Transmit Clock */
-#define AT91_PB22_LCDD17	(1 << 22)	/* B: LCD Data Bus Bit 17 */
-#define AT91_PB23_TD0		(1 << 23)	/* A: SSC0 Transmit Data */
-#define AT91_PB23_LCDD18	(1 << 23)	/* B: LCD Data Bus Bit 18 */
-#define AT91_PB24_RD0		(1 << 24)	/* A: SSC0 Receive Data */
-#define AT91_PB24_LCDD19	(1 << 24)	/* B: LCD Data Bus Bit 19 */
-#define AT91_PB25_RK0		(1 << 25)	/* A: SSC0 Receive Clock */
-#define AT91_PB25_LCDD20	(1 << 25)	/* B: LCD Data Bus Bit 20 */
-#define AT91_PB26_RF0		(1 << 26)	/* A: SSC0 Receive Frame Sync */
-#define AT91_PB26_LCDD21	(1 << 26)	/* B: LCD Data Bus Bit 21 */
-#define AT91_PB27_SPI1_NPCS1	(1 << 27)	/* A: SPI1 Peripheral Chip Select 1 */
-#define AT91_PB27_LCDD22	(1 << 27)	/* B: LCD Data Bus Bit 22 */
-#define AT91_PB28_SPI1_NPCS0	(1 << 28)	/* A: SPI1 Peripheral Chip Select 0 */
-#define AT91_PB28_LCDD23	(1 << 28)	/* B: LCD Data Bus Bit 23 */
-#define AT91_PB29_SPI1_SPCK	(1 << 29)	/* A: SPI1 Serial Clock */
-#define AT91_PB29_IRQ2		(1 << 29)	/* B: Interrupt input 2 */
-#define AT91_PB30_SPI1_MISO	(1 << 30)	/* A: SPI1 Master In Slave */
-#define AT91_PB30_IRQ1		(1 << 30)	/* B: Interrupt input 1 */
-#define AT91_PB31_SPI1_MOSI	(1 << 31)	/* A: SPI1 Master Out Slave */
-#define AT91_PB31_PCK2		(1 << 31)	/* B: PMC Programmable clock Output 2 */
-
-#define AT91_PC0_SMOE		(1 << 0)	/* A: SmartMedia Output Enable */
-#define AT91_PC0_NCS6		(1 << 0)	/* B: Chip Select 6 */
-#define AT91_PC1_SMWE		(1 << 1)	/* A: SmartMedia Write Enable */
-#define AT91_PC1_NCS7		(1 << 1)	/* B: Chip Select 7 */
-#define AT91_PC2_NWAIT		(1 << 2)	/* A: NWAIT */
-#define AT91_PC2_IRQ0		(1 << 2)	/* B: Interrupt input 0 */
-#define AT91_PC3_A25_CFRNW	(1 << 3)	/* A: Address Bus[25] / Compact Flash Read Not Write */
-#define AT91_PC4_NCS4_CFCS0	(1 << 4)	/* A: Chip Select 4 / CompactFlash Chip Select 0 */
-#define AT91_PC5_NCS5_CFCS1	(1 << 5)	/* A: Chip Select 5 / CompactFlash Chip Select 1 */
-#define AT91_PC6_CFCE1		(1 << 6)	/* A: CompactFlash Chip Enable 1 */
-#define AT91_PC7_CFCE2		(1 << 7)	/* A: CompactFlash Chip Enable 2 */
-#define AT91_PC8_TXD0		(1 << 8)	/* A: USART0 Transmit Data */
-#define AT91_PC8_PCK2		(1 << 8)	/* B: PMC Programmable clock Output 2 */
-#define AT91_PC9_RXD0		(1 << 9)	/* A: USART0 Receive Data */
-#define AT91_PC9_PCK3		(1 << 9)	/* B: PMC Programmable clock Output 3 */
-#define AT91_PC10_RTS0		(1 << 10)	/* A: USART0 Ready To Send */
-#define AT91_PC10_SCK0		(1 << 10)	/* B: USART0 Serial Clock */
-#define AT91_PC11_CTS0		(1 << 11)	/* A: USART0 Clear To Send */
-#define AT91_PC11_FIQ		(1 << 11)	/* B: AIC Fast Interrupt Input */
-#define AT91_PC12_TXD1		(1 << 12)	/* A: USART1 Transmit Data */
-#define AT91_PC12_NCS6		(1 << 12)	/* B: Chip Select 6 */
-#define AT91_PC13_RXD1		(1 << 13)	/* A: USART1 Receive Data */
-#define AT91_PC13_NCS7		(1 << 13)	/* B: Chip Select 7 */
-#define AT91_PC14_TXD2		(1 << 14)	/* A: USART2 Transmit Data */
-#define AT91_PC14_SPI1_NPCS2	(1 << 14)	/* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PC15_RXD2		(1 << 15)	/* A: USART2 Receive Data */
-#define AT91_PC15_SPI1_NPCS3	(1 << 15)	/* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PC16_D16		(1 << 16)	/* A: Data Bus [16] */
-#define AT91_PC16_TCLK0		(1 << 16)	/* B: Timer Counter 0 external clock input */
-#define AT91_PC17_D17		(1 << 17)	/* A: Data Bus [17] */
-#define AT91_PC17_TCLK1		(1 << 17)	/* B: Timer Counter 1 external clock input */
-#define AT91_PC18_D18		(1 << 18)	/* A: Data Bus [18] */
-#define AT91_PC18_TCLK2		(1 << 18)	/* B: Timer Counter 2 external clock input */
-#define AT91_PC19_D19		(1 << 19)	/* A: Data Bus [19] */
-#define AT91_PC19_TIOA0		(1 << 19)	/* B: Timer Counter 0 Multipurpose Timer I/O Pin A */
-#define AT91_PC20_D20		(1 << 20)	/* A: Data Bus [20] */
-#define AT91_PC20_TIOB0		(1 << 20)	/* B: Timer Counter 0 Multipurpose Timer I/O Pin B */
-#define AT91_PC21_D21		(1 << 21)	/* A: Data Bus [21] */
-#define AT91_PC21_TIOA1		(1 << 21)	/* B: Timer Counter 1 Multipurpose Timer I/O Pin A */
-#define AT91_PC22_D22		(1 << 22)	/* A: Data Bus [22] */
-#define AT91_PC22_TIOB1		(1 << 22)	/* B: Timer Counter 1 Multipurpose Timer I/O Pin B */
-#define AT91_PC23_D23		(1 << 23)	/* A: Data Bus [23] */
-#define AT91_PC23_TIOA2		(1 << 23)	/* B: Timer Counter 2 Multipurpose Timer I/O Pin A */
-#define AT91_PC24_D24		(1 << 24)	/* A: Data Bus [24] */
-#define AT91_PC24_TIOB2		(1 << 24)	/* B: Timer Counter 2 Multipurpose Timer I/O Pin B */
-#define AT91_PC25_D25		(1 << 25)	/* A: Data Bus [25] */
-#define AT91_PC25_TF2		(1 << 25)	/* B: SSC2 Transmit Frame Sync */
-#define AT91_PC26_D26		(1 << 26)	/* A: Data Bus [26] */
-#define AT91_PC26_TK2		(1 << 26)	/* B: SSC2 Transmit Clock */
-#define AT91_PC27_D27		(1 << 27)	/* A: Data Bus [27] */
-#define AT91_PC27_TD2		(1 << 27)	/* B: SSC2 Transmit Data */
-#define AT91_PC28_D28		(1 << 28)	/* A: Data Bus [28] */
-#define AT91_PC28_RD2		(1 << 28)	/* B: SSC2 Receive Data */
-#define AT91_PC29_D29		(1 << 29)	/* A: Data Bus [29] */
-#define AT91_PC29_RK2		(1 << 29)	/* B: SSC2 Receive Clock */
-#define AT91_PC30_D30		(1 << 30)	/* A: Data Bus [30] */
-#define AT91_PC30_RF2		(1 << 30)	/* B: SSC2 Receive Frame Sync */
-#define AT91_PC31_D31		(1 << 31)	/* A: Data Bus [31] */
-#define AT91_PC31_PCK1		(1 << 31)	/* B: PMC Programmable clock Output 1 */
-#endif
-
 #endif
diff --git a/include/asm-arm/arch-at91/at91sam9263.h b/include/asm-arm/arch-at91/at91sam9263.h
index f4af68a..115c47a 100644
--- a/include/asm-arm/arch-at91/at91sam9263.h
+++ b/include/asm-arm/arch-at91/at91sam9263.h
@@ -119,13 +119,5 @@
 #define AT91SAM9263_DMAC_BASE	0x00800000	/* DMA Controller */
 #define AT91SAM9263_UHP_BASE	0x00a00000	/* USB Host controller */
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
 
 #endif
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 7a34a5b..0ce6ee9 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -121,7 +121,7 @@
  /* AC97 */
 struct atmel_ac97_data {
 	u8		reset_pin;	/* reset */
-}
+};
 extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
 
  /* LEDs */
diff --git a/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
index d464ca5..7ef4eeb 100644
--- a/include/asm-arm/arch-at91/cpu.h
+++ b/include/asm-arm/arch-at91/cpu.h
@@ -68,4 +68,10 @@
 #define cpu_is_at91sam9263()	(0)
 #endif
 
+/*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at32ap7000()	(0)
+
 #endif
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
index de6494a..30de404 100644
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -297,7 +297,7 @@
 #define SAR(x)  __REG2( IMX_DMAC_BASE + 0x80, (x) << 6)	/* Source Address Registers */
 #define DAR(x)  __REG2( IMX_DMAC_BASE + 0x84, (x) << 6)	/* Destination Address Registers */
 #define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6)	/* Count Registers */
-#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)	/* Control Registers */
+#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)	/* Control Registers */
 #define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6)	/* Request source select Registers */
 #define BLR(x)  __REG2( IMX_DMAC_BASE + 0x94, (x) << 6)	/* Burst length Registers */
 #define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)	/* Request timeout Registers */
diff --git a/include/asm-arm/arch-integrator/platform.h b/include/asm-arm/arch-integrator/platform.h
index 96ad3d2..83c4c1c 100644
--- a/include/asm-arm/arch-integrator/platform.h
+++ b/include/asm-arm/arch-integrator/platform.h
@@ -17,7 +17,7 @@
  *                 from .s file by awk -f s2h.awk
  */
 /**************************************************************************
- * * Copyright © ARM Limited 1998.  All rights reserved.
+ * * Copyright © ARM Limited 1998.  All rights reserved.
  * ***********************************************************************/
 /* ************************************************************************
  *
diff --git a/include/asm-arm/arch-iop32x/glantank.h b/include/asm-arm/arch-iop32x/glantank.h
index 3b06561..bf0665a 100644
--- a/include/asm-arm/arch-iop32x/glantank.h
+++ b/include/asm-arm/arch-iop32x/glantank.h
@@ -1,5 +1,5 @@
 /*
- * include/asm/arch-iop32x/glantank.h
+ * include/asm-arm/arch-iop32x/glantank.h
  *
  * IO-Data GLAN Tank board registers
  */
diff --git a/include/asm-arm/arch-iop32x/n2100.h b/include/asm-arm/arch-iop32x/n2100.h
index fed31a6..77a8af4 100644
--- a/include/asm-arm/arch-iop32x/n2100.h
+++ b/include/asm-arm/arch-iop32x/n2100.h
@@ -1,5 +1,5 @@
 /*
- * include/asm/arch-iop32x/n2100.h
+ * include/asm-arm/arch-iop32x/n2100.h
  *
  * Thecus N2100 board registers
  */
diff --git a/include/asm-arm/arch-omap/aic23.h b/include/asm-arm/arch-omap/aic23.h
index 6513065..aec2d65 100644
--- a/include/asm-arm/arch-omap/aic23.h
+++ b/include/asm-arm/arch-omap/aic23.h
@@ -110,7 +110,7 @@
 #define TLV320AIC23ID1                  (0x1a)	// cs low
 #define TLV320AIC23ID2                  (0x1b)	// cs high
 
-void tlv320aic23_power_up(void);
-void tlv320aic23_power_down(void);
+void aic23_power_up(void);
+void aic23_power_down(void);
 
 #endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-omap/board-apollon.h b/include/asm-arm/arch-omap/board-apollon.h
index de0c5b7..dcb587b 100644
--- a/include/asm-arm/arch-omap/board-apollon.h
+++ b/include/asm-arm/arch-omap/board-apollon.h
@@ -30,16 +30,7 @@
 #define __ASM_ARCH_OMAP_APOLLON_H
 
 /* Placeholder for APOLLON specific defines */
-/* GPMC CS0 */
-#define APOLLON_CS0_BASE		0x00000000
-/* GPMC CS1 */
-#define APOLLON_CS1_BASE		0x08000000
-#define APOLLON_ETHR_START		(APOLLON_CS1_BASE + 0x300)
 #define APOLLON_ETHR_GPIO_IRQ		74
-/* GPMC CS2 - reserved for OneNAND */
-#define APOLLON_CS2_BASE		0x10000000
-/* GPMC CS3 - reserved for NOR or NAND */
-#define APOLLON_CS3_BASE		0x18000000
 
 #endif /*  __ASM_ARCH_OMAP_APOLLON_H */
 
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
index 7ef664b..7e0efef 100644
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -30,9 +30,6 @@
 #define __ASM_ARCH_OMAP_H4_H
 
 /* Placeholder for H4 specific defines */
-/* GPMC CS1 */
-#define OMAP24XX_ETHR_START             0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ		92
-#define H4_CS0_BASE			0x04000000
 #endif /*  __ASM_ARCH_OMAP_H4_H */
 
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index edf1dc6..031672c 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -4,7 +4,7 @@
  *  Information structures for board-specific data
  *
  *  Copyright (C) 2004	Nokia Corporation
- *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
  */
 
 #ifndef _OMAP_BOARD_H
@@ -12,6 +12,8 @@
 
 #include <linux/types.h>
 
+#include <asm/arch/gpio-switch.h>
+
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK		0x4f01
 #define OMAP_TAG_MMC		0x4f02
@@ -99,26 +101,31 @@
 struct omap_lcd_config {
 	char panel_name[16];
 	char ctrl_name[16];
+	s16  nreset_gpio;
+	u8   data_lines;
+};
+
+struct device;
+struct fb_info;
+struct omap_backlight_config {
+	int default_intensity;
+	int (*set_power)(struct device *dev, int state);
+	int (*check_fb)(struct fb_info *fb);
 };
 
 struct omap_fbmem_config {
-	u32 fb_sram_start;
-	u32 fb_sram_size;
-	u32 fb_sdram_start;
-	u32 fb_sdram_size;
+	u32 start;
+	u32 size;
 };
 
-/* Cover:
- *      high -> closed
- *      low  -> open
- * Connection:
- *      high -> connected
- *      low  -> disconnected
- */
-#define OMAP_GPIO_SWITCH_TYPE_COVER		0x0000
-#define OMAP_GPIO_SWITCH_TYPE_CONNECTION	0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED		0x0001
-#define OMAP_GPIO_SWITCH_FLAG_OUTPUT		0x0002
+struct omap_pwm_led_platform_data {
+	const char *name;
+	int intensity_timer;
+	int blink_timer;
+	void (*set_power)(struct omap_pwm_led_platform_data *self, int on_off);
+};
+
+/* See include/asm-arm/arch-omap/gpio-switch.h for definitions */
 struct omap_gpio_switch_config {
 	char name[12];
 	u16 gpio;
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index d591d05..f777419 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -2,7 +2,7 @@
  *  linux/include/asm-arm/arch-omap/dma.h
  *
  *  Copyright (C) 2003 Nokia Corporation
- *  Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *  Author: Juha Yrjölä <juha.yrjola@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
deleted file mode 100644
index 06dad83..0000000
--- a/include/asm-arm/arch-omap/dsp.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * linux/include/asm-arm/arch-omap/dsp.h
- *
- * Header for OMAP DSP driver
- *
- * Copyright (C) 2002-2005 Nokia Corporation
- *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * 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
- *
- * 2005/06/01:  DSP Gateway version 3.3
- */
-
-#ifndef ASM_ARCH_DSP_H
-#define ASM_ARCH_DSP_H
-
-
-/*
- * for /dev/dspctl/ctl
- */
-#define OMAP_DSP_IOCTL_RESET			1
-#define OMAP_DSP_IOCTL_RUN			2
-#define OMAP_DSP_IOCTL_SETRSTVECT		3
-#define OMAP_DSP_IOCTL_CPU_IDLE			4
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON		5
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF	6
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON		7
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF	8
-#define OMAP_DSP_IOCTL_GBL_IDLE			9
-#define OMAP_DSP_IOCTL_DSPCFG			10
-#define OMAP_DSP_IOCTL_DSPUNCFG			11
-#define OMAP_DSP_IOCTL_TASKCNT			12
-#define OMAP_DSP_IOCTL_POLL			13
-#define OMAP_DSP_IOCTL_REGMEMR			40
-#define OMAP_DSP_IOCTL_REGMEMW			41
-#define OMAP_DSP_IOCTL_REGIOR			42
-#define OMAP_DSP_IOCTL_REGIOW			43
-#define OMAP_DSP_IOCTL_GETVAR			44
-#define OMAP_DSP_IOCTL_SETVAR			45
-#define OMAP_DSP_IOCTL_RUNLEVEL			50
-#define OMAP_DSP_IOCTL_SUSPEND			51
-#define OMAP_DSP_IOCTL_RESUME			52
-#define OMAP_DSP_IOCTL_FBEN			53
-#define OMAP_DSP_IOCTL_FBDIS			54
-#define OMAP_DSP_IOCTL_MBSEND			99
-
-/*
- * for taskdev
- * (ioctls below should be >= 0x10000)
- */
-#define OMAP_DSP_TASK_IOCTL_BFLSH	0x10000
-#define OMAP_DSP_TASK_IOCTL_SETBSZ	0x10001
-#define OMAP_DSP_TASK_IOCTL_LOCK	0x10002
-#define OMAP_DSP_TASK_IOCTL_UNLOCK	0x10003
-#define OMAP_DSP_TASK_IOCTL_GETNAME	0x10004
-
-/*
- * for /dev/dspctl/mem
- */
-#define OMAP_DSP_MEM_IOCTL_EXMAP	1
-#define OMAP_DSP_MEM_IOCTL_EXUNMAP	2
-#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH	3
-#define OMAP_DSP_MEM_IOCTL_FBEXPORT	5
-#define OMAP_DSP_MEM_IOCTL_MMUITACK	7
-#define OMAP_DSP_MEM_IOCTL_MMUINIT	9
-#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE	11
-#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE	12
-
-struct omap_dsp_mapinfo {
-	unsigned long dspadr;
-	unsigned long size;
-};
-
-/*
- * for /dev/dspctl/twch
- */
-#define OMAP_DSP_TWCH_IOCTL_MKDEV	1
-#define OMAP_DSP_TWCH_IOCTL_RMDEV	2
-#define OMAP_DSP_TWCH_IOCTL_TADD	11
-#define OMAP_DSP_TWCH_IOCTL_TDEL	12
-#define OMAP_DSP_TWCH_IOCTL_TKILL	13
-
-#define OMAP_DSP_DEVSTATE_NOTASK	0x00000001
-#define OMAP_DSP_DEVSTATE_ATTACHED	0x00000002
-#define OMAP_DSP_DEVSTATE_GARBAGE	0x00000004
-#define OMAP_DSP_DEVSTATE_INVALID	0x00000008
-#define OMAP_DSP_DEVSTATE_ADDREQ	0x00000100
-#define OMAP_DSP_DEVSTATE_DELREQ	0x00000200
-#define OMAP_DSP_DEVSTATE_ADDFAIL	0x00001000
-#define OMAP_DSP_DEVSTATE_ADDING	0x00010000
-#define OMAP_DSP_DEVSTATE_DELING	0x00020000
-#define OMAP_DSP_DEVSTATE_KILLING	0x00040000
-#define OMAP_DSP_DEVSTATE_STATE_MASK	0x7fffffff
-#define OMAP_DSP_DEVSTATE_STALE		0x80000000
-
-struct omap_dsp_taddinfo {
-	unsigned char minor;
-	unsigned long taskadr;
-};
-#define OMAP_DSP_TADD_ABORTADR	0xffffffff
-
-
-/*
- * error cause definition (for error detection device)
- */
-#define OMAP_DSP_ERRDT_WDT	0x00000001
-#define OMAP_DSP_ERRDT_MMU	0x00000002
-
-
-/*
- * mailbox protocol definitions
- */
-
-struct omap_dsp_mailbox_cmd {
-	unsigned short cmd;
-	unsigned short data;
-};
-
-struct omap_dsp_reginfo {
-	unsigned short adr;
-	unsigned short val;
-};
-
-struct omap_dsp_varinfo {
-	unsigned char varid;
-	unsigned short val[0];
-};
-
-#define OMAP_DSP_MBPROT_REVISION	0x0019
-
-#define OMAP_DSP_MBCMD_WDSND	0x10
-#define OMAP_DSP_MBCMD_WDREQ	0x11
-#define OMAP_DSP_MBCMD_BKSND	0x20
-#define OMAP_DSP_MBCMD_BKREQ	0x21
-#define OMAP_DSP_MBCMD_BKYLD	0x23
-#define OMAP_DSP_MBCMD_BKSNDP	0x24
-#define OMAP_DSP_MBCMD_BKREQP	0x25
-#define OMAP_DSP_MBCMD_TCTL	0x30
-#define OMAP_DSP_MBCMD_TCTLDATA	0x31
-#define OMAP_DSP_MBCMD_POLL	0x32
-#define OMAP_DSP_MBCMD_WDT	0x50	/* v3.3: obsolete */
-#define OMAP_DSP_MBCMD_RUNLEVEL	0x51
-#define OMAP_DSP_MBCMD_PM	0x52
-#define OMAP_DSP_MBCMD_SUSPEND	0x53
-#define OMAP_DSP_MBCMD_KFUNC	0x54
-#define OMAP_DSP_MBCMD_TCFG	0x60
-#define OMAP_DSP_MBCMD_TADD	0x62
-#define OMAP_DSP_MBCMD_TDEL	0x63
-#define OMAP_DSP_MBCMD_TSTOP	0x65
-#define OMAP_DSP_MBCMD_DSPCFG	0x70
-#define OMAP_DSP_MBCMD_REGRW	0x72
-#define OMAP_DSP_MBCMD_GETVAR	0x74
-#define OMAP_DSP_MBCMD_SETVAR	0x75
-#define OMAP_DSP_MBCMD_ERR	0x78
-#define OMAP_DSP_MBCMD_DBG	0x79
-
-#define OMAP_DSP_MBCMD_TCTL_TINIT	0x0000
-#define OMAP_DSP_MBCMD_TCTL_TEN		0x0001
-#define OMAP_DSP_MBCMD_TCTL_TDIS	0x0002
-#define OMAP_DSP_MBCMD_TCTL_TCLR	0x0003
-#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE	0x0004
-
-#define OMAP_DSP_MBCMD_RUNLEVEL_USER		0x01
-#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER		0x0e
-#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY	0x10
-
-#define OMAP_DSP_MBCMD_PM_DISABLE	0x00
-#define OMAP_DSP_MBCMD_PM_ENABLE	0x01
-
-#define OMAP_DSP_MBCMD_KFUNC_FBCTL	0x00
-#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR	0x01
-
-#define OMAP_DSP_MBCMD_FBCTL_UPD	0x0000
-#define OMAP_DSP_MBCMD_FBCTL_ENABLE	0x0002
-#define OMAP_DSP_MBCMD_FBCTL_DISABLE	0x0003
-
-#define OMAP_DSP_MBCMD_AUDIO_PWR_UP	0x0000
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1	0x0001
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2	0x0002
-
-#define OMAP_DSP_MBCMD_TDEL_SAFE	0x0000
-#define OMAP_DSP_MBCMD_TDEL_KILL	0x0001
-
-#define OMAP_DSP_MBCMD_DSPCFG_REQ	0x00
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH	0x28
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL	0x29
-#define OMAP_DSP_MBCMD_DSPCFG_PROTREV	0x70
-#define OMAP_DSP_MBCMD_DSPCFG_ABORT	0x78
-#define OMAP_DSP_MBCMD_DSPCFG_LAST	0x80
-
-#define OMAP_DSP_MBCMD_REGRW_MEMR	0x00
-#define OMAP_DSP_MBCMD_REGRW_MEMW	0x01
-#define OMAP_DSP_MBCMD_REGRW_IOR	0x02
-#define OMAP_DSP_MBCMD_REGRW_IOW	0x03
-#define OMAP_DSP_MBCMD_REGRW_DATA	0x04
-
-#define OMAP_DSP_MBCMD_VARID_ICRMASK	0x00
-#define OMAP_DSP_MBCMD_VARID_LOADINFO	0x01
-
-#define OMAP_DSP_TTYP_ARCV	0x0001
-#define OMAP_DSP_TTYP_ASND	0x0002
-#define OMAP_DSP_TTYP_BKMD	0x0004
-#define OMAP_DSP_TTYP_BKDM	0x0008
-#define OMAP_DSP_TTYP_PVMD	0x0010
-#define OMAP_DSP_TTYP_PVDM	0x0020
-
-#define OMAP_DSP_EID_BADTID	0x10
-#define OMAP_DSP_EID_BADTCN	0x11
-#define OMAP_DSP_EID_BADBID	0x20
-#define OMAP_DSP_EID_BADCNT	0x21
-#define OMAP_DSP_EID_NOTLOCKED	0x22
-#define OMAP_DSP_EID_STVBUF	0x23
-#define OMAP_DSP_EID_BADADR	0x24
-#define OMAP_DSP_EID_BADTCTL	0x30
-#define OMAP_DSP_EID_BADPARAM	0x50
-#define OMAP_DSP_EID_FATAL	0x58
-#define OMAP_DSP_EID_NOMEM	0xc0
-#define OMAP_DSP_EID_NORES	0xc1
-#define OMAP_DSP_EID_IPBFULL	0xc2
-#define OMAP_DSP_EID_WDT	0xd0
-#define OMAP_DSP_EID_TASKNOTRDY	0xe0
-#define OMAP_DSP_EID_TASKBSY	0xe1
-#define OMAP_DSP_EID_TASKERR	0xef
-#define OMAP_DSP_EID_BADCFGTYP	0xf0
-#define OMAP_DSP_EID_DEBUG	0xf8
-#define OMAP_DSP_EID_BADSEQ	0xfe
-#define OMAP_DSP_EID_BADCMD	0xff
-
-#define OMAP_DSP_TNM_LEN	16
-
-#define OMAP_DSP_TID_FREE	0xff
-#define OMAP_DSP_TID_ANON	0xfe
-
-#define OMAP_DSP_BID_NULL	0xffff
-#define OMAP_DSP_BID_PVT	0xfffe
-
-#endif /* ASM_ARCH_DSP_H */
diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h
index 16a459d..c61f868 100644
--- a/include/asm-arm/arch-omap/dsp_common.h
+++ b/include/asm-arm/arch-omap/dsp_common.h
@@ -1,38 +1,34 @@
 /*
- * linux/include/asm-arm/arch-omap/dsp_common.h
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
  *
- * Header for OMAP DSP subsystem control
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
  *
- * Copyright (C) 2004,2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
  *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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 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.
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  *
- * 2005/06/03:  DSP Gateway version 3.3
  */
 
 #ifndef ASM_ARCH_DSP_COMMON_H
 #define ASM_ARCH_DSP_COMMON_H
 
+#ifdef CONFIG_ARCH_OMAP1
 extern void omap_dsp_request_mpui(void);
 extern void omap_dsp_release_mpui(void);
 extern int omap_dsp_request_mem(void);
 extern int omap_dsp_release_mem(void);
-
-extern void (*omap_dsp_audio_pwr_up_request)(int stage);
-extern void (*omap_dsp_audio_pwr_down_request)(int stage);
+#endif
 
 #endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/gpio-switch.h b/include/asm-arm/arch-omap/gpio-switch.h
new file mode 100644
index 0000000..10da0e0
--- /dev/null
+++ b/include/asm-arm/arch-omap/gpio-switch.h
@@ -0,0 +1,54 @@
+/*
+ * GPIO switch definitions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * 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 __ASM_ARCH_OMAP_GPIO_SWITCH_H
+#define __ASM_ARCH_OMAP_GPIO_SWITCH_H
+
+#include <linux/types.h>
+
+/* Cover:
+ *	high -> closed
+ *	low  -> open
+ * Connection:
+ *	high -> connected
+ *	low  -> disconnected
+ * Activity:
+ *	high -> active
+ *	low  -> inactive
+ *
+ */
+#define OMAP_GPIO_SWITCH_TYPE_COVER		0x0000
+#define OMAP_GPIO_SWITCH_TYPE_CONNECTION	0x0001
+#define OMAP_GPIO_SWITCH_TYPE_ACTIVITY		0x0002
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED		0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT		0x0002
+
+struct omap_gpio_switch {
+	const char *name;
+	s16 gpio;
+	unsigned flags:4;
+	unsigned type:4;
+
+	/* Time in ms to debounce when transitioning from
+	 * inactive state to active state. */
+	u16 debounce_rising;
+	/* Same for transition from active to inactive state. */
+	u16 debounce_falling;
+
+	/* notify board-specific code about state changes */
+	void (* notify)(void *data, int state);
+	void *notify_data;
+};
+
+/* Call at init time only */
+extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+					int count);
+
+#endif
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h
index 590917e..97b397d 100644
--- a/include/asm-arm/arch-omap/gpio.h
+++ b/include/asm-arm/arch-omap/gpio.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2003-2005 Nokia Corporation
  *
- * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/include/asm-arm/arch-omap/gpmc.h b/include/asm-arm/arch-omap/gpmc.h
index 7c03ef6..995cc83 100644
--- a/include/asm-arm/arch-omap/gpmc.h
+++ b/include/asm-arm/arch-omap/gpmc.h
@@ -87,5 +87,7 @@
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
+extern int gpmc_cs_set_reserved(int cs, int reserved);
+extern int gpmc_cs_reserved(int cs);
 
 #endif
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 481048d..e225f4f 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -267,6 +267,15 @@
 #define OMAP_LPG2_PMR			(OMAP_LPG2_BASE + 0x04)
 
 /*
+ * ----------------------------------------------------------------------------
+ * Pulse-Width Light
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_PWL_BASE			0xfffb5800
+#define OMAP_PWL_ENABLE			(OMAP_PWL_BASE + 0x00)
+#define OMAP_PWL_CLK_ENABLE		(OMAP_PWL_BASE + 0x04)
+
+/*
  * ---------------------------------------------------------------------------
  * Processor specific defines
  * ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/hwa742.h b/include/asm-arm/arch-omap/hwa742.h
new file mode 100644
index 0000000..577f492
--- /dev/null
+++ b/include/asm-arm/arch-omap/hwa742.h
@@ -0,0 +1,12 @@
+#ifndef _HWA742_H
+#define _HWA742_H
+
+struct hwa742_platform_data {
+	void		(*power_up)(struct device *dev);
+	void		(*power_down)(struct device *dev);
+	unsigned long	(*get_clock_rate)(struct device *dev);
+
+	unsigned	te_connected:1;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h
index 78f68e6..4aca7e3 100644
--- a/include/asm-arm/arch-omap/io.h
+++ b/include/asm-arm/arch-omap/io.h
@@ -77,6 +77,17 @@
 #define io_p2v(pa)	((pa) + IO_OFFSET)	/* Works for L3 and L4 */
 #define io_v2p(va)	((va) - IO_OFFSET)	/* Works for L3 and L4 */
 
+/* DSP */
+#define DSP_MEM_24XX_PHYS	OMAP24XX_DSP_MEM_BASE	/* 0x58000000 */
+#define DSP_MEM_24XX_VIRT	0xe0000000
+#define DSP_MEM_24XX_SIZE	0x28000
+#define DSP_IPI_24XX_PHYS	OMAP24XX_DSP_IPI_BASE	/* 0x59000000 */
+#define DSP_IPI_24XX_VIRT	0xe1000000
+#define DSP_IPI_24XX_SIZE	SZ_4K
+#define DSP_MMU_24XX_PHYS	OMAP24XX_DSP_MMU_BASE	/* 0x5a000000 */
+#define DSP_MMU_24XX_VIRT	0xe2000000
+#define DSP_MMU_24XX_SIZE	SZ_4K
+
 #endif
 
 #ifndef __ASSEMBLER__
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index c5bb05a..3ede58b 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -37,8 +37,6 @@
 #define INT_DSP_MMU_ABORT	7
 #define INT_HOST		8
 #define INT_ABORT		9
-#define INT_DSP_MAILBOX1	10
-#define INT_DSP_MAILBOX2	11
 #define INT_BRIDGE_PRIV		13
 #define INT_GPIO_BANK1		14
 #define INT_UART3		15
@@ -63,6 +61,8 @@
 #define INT_1510_RES2		2
 #define INT_1510_SPI_TX		4
 #define INT_1510_SPI_RX		5
+#define INT_1510_DSP_MAILBOX1	10
+#define INT_1510_DSP_MAILBOX2	11
 #define INT_1510_RES12		12
 #define INT_1510_LB_MMU		17
 #define INT_1510_RES18		18
@@ -75,6 +75,8 @@
 #define INT_1610_IH2_FIQ	2
 #define INT_1610_McBSP2_TX	4
 #define INT_1610_McBSP2_RX	5
+#define INT_1610_DSP_MAILBOX1	10
+#define INT_1610_DSP_MAILBOX2	11
 #define INT_1610_LCD_LINE	12
 #define INT_1610_GPTIMER1	17
 #define INT_1610_GPTIMER2	18
@@ -131,11 +133,11 @@
 #define INT_RTC_TIMER		(25 + IH2_BASE)
 #define INT_RTC_ALARM		(26 + IH2_BASE)
 #define INT_MEM_STICK		(27 + IH2_BASE)
-#define INT_DSP_MMU		(28 + IH2_BASE)
 
 /*
  * OMAP-1510 specific IRQ numbers for interrupt handler 2
  */
+#define INT_1510_DSP_MMU	(28 + IH2_BASE)
 #define INT_1510_COM_SPI_RO	(31 + IH2_BASE)
 
 /*
@@ -146,6 +148,7 @@
 #define INT_1610_USB_OTG	(8 + IH2_BASE)
 #define INT_1610_SoSSI		(9 + IH2_BASE)
 #define INT_1610_SoSSI_MATCH	(19 + IH2_BASE)
+#define INT_1610_DSP_MMU	(28 + IH2_BASE)
 #define INT_1610_McBSP2RX_OF	(31 + IH2_BASE)
 #define INT_1610_STI		(32 + IH2_BASE)
 #define INT_1610_STI_WAKEUP	(33 + IH2_BASE)
@@ -239,10 +242,15 @@
 #define INT_24XX_SDMA_IRQ3	15
 #define INT_24XX_CAM_IRQ	24
 #define INT_24XX_DSS_IRQ	25
+#define INT_24XX_MAIL_U0_MPU	26
+#define INT_24XX_DSP_UMA	27
+#define INT_24XX_DSP_MMU	28
 #define INT_24XX_GPIO_BANK1	29
 #define INT_24XX_GPIO_BANK2	30
 #define INT_24XX_GPIO_BANK3	31
 #define INT_24XX_GPIO_BANK4	32
+#define INT_24XX_GPIO_BANK5	33
+#define INT_24XX_MAIL_U3_MPU	34
 #define INT_24XX_GPTIMER1	37
 #define INT_24XX_GPTIMER2	38
 #define INT_24XX_GPTIMER3	39
@@ -262,6 +270,12 @@
 #define INT_24XX_UART1_IRQ	72
 #define INT_24XX_UART2_IRQ	73
 #define INT_24XX_UART3_IRQ	74
+#define INT_24XX_USB_IRQ_GEN	75
+#define INT_24XX_USB_IRQ_NISO	76
+#define INT_24XX_USB_IRQ_ISO	77
+#define INT_24XX_USB_IRQ_HGEN	78
+#define INT_24XX_USB_IRQ_HSOF	79
+#define INT_24XX_USB_IRQ_OTG	80
 #define INT_24XX_MMC_IRQ	83
 
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
deleted file mode 100644
index 004e67e..0000000
--- a/include/asm-arm/arch-omap/lcd_lph8923.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LCD_LPH8923_H
-#define __LCD_LPH8923_H
-
-enum lcd_lph8923_test_num {
-	LCD_LPH8923_TEST_RGB_LINES,
-};
-
-enum lcd_lph8923_test_result {
-	LCD_LPH8923_TEST_SUCCESS,
-	LCD_LPH8923_TEST_INVALID,
-	LCD_LPH8923_TEST_FAILED,
-};
-
-#endif
diff --git a/include/asm-arm/arch-omap/lcd_mipid.h b/include/asm-arm/arch-omap/lcd_mipid.h
new file mode 100644
index 0000000..f8fbc48
--- /dev/null
+++ b/include/asm-arm/arch-omap/lcd_mipid.h
@@ -0,0 +1,24 @@
+#ifndef __LCD_MIPID_H
+#define __LCD_MIPID_H
+
+enum mipid_test_num {
+	MIPID_TEST_RGB_LINES,
+};
+
+enum mipid_test_result {
+	MIPID_TEST_SUCCESS,
+	MIPID_TEST_INVALID,
+	MIPID_TEST_FAILED,
+};
+
+#ifdef __KERNEL__
+
+struct mipid_platform_data {
+	int	nreset_gpio;
+	int	data_lines;
+	void	(*shutdown)(struct mipid_platform_data *pdata);
+};
+
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-omap/led.h b/include/asm-arm/arch-omap/led.h
new file mode 100644
index 0000000..f3acae2
--- /dev/null
+++ b/include/asm-arm/arch-omap/led.h
@@ -0,0 +1,24 @@
+/*
+ *  linux/include/asm-arm/arch-omap/led.h
+ *
+ *  Copyright (C) 2006 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.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.
+ */
+#ifndef ASMARM_ARCH_LED_H
+#define ASMARM_ARCH_LED_H
+
+struct omap_led_config {
+	struct led_classdev	cdev;
+	s16			gpio;
+};
+
+struct omap_led_platform_data {
+	s16			nr_leds;
+	struct omap_led_config	*leds;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/mailbox.h b/include/asm-arm/arch-omap/mailbox.h
new file mode 100644
index 0000000..4bf0909
--- /dev/null
+++ b/include/asm-arm/arch-omap/mailbox.h
@@ -0,0 +1,73 @@
+/* mailbox.h */
+
+#ifndef MAILBOX_H
+#define MAILBOX_H
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/blkdev.h>
+
+typedef u32 mbox_msg_t;
+typedef void (mbox_receiver_t)(mbox_msg_t msg);
+struct omap_mbox;
+
+typedef int __bitwise omap_mbox_irq_t;
+#define IRQ_TX ((__force omap_mbox_irq_t) 1)
+#define IRQ_RX ((__force omap_mbox_irq_t) 2)
+
+typedef int __bitwise omap_mbox_type_t;
+#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1)
+#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2)
+
+struct omap_mbox_ops {
+	omap_mbox_type_t	type;
+	int		(*startup)(struct omap_mbox *mbox);
+	void		(*shutdown)(struct omap_mbox *mbox);
+	/* fifo */
+	mbox_msg_t	(*fifo_read)(struct omap_mbox *mbox);
+	void		(*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
+	int		(*fifo_empty)(struct omap_mbox *mbox);
+	int		(*fifo_full)(struct omap_mbox *mbox);
+	/* irq */
+	void		(*enable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+	void		(*disable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+	void		(*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+	int		(*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+};
+
+struct omap_mbox_queue {
+	spinlock_t		lock;
+	request_queue_t		*queue;
+	struct work_struct	work;
+	int	(*callback)(void *);
+	struct omap_mbox	*mbox;
+};
+
+struct omap_mbox {
+	char			*name;
+	unsigned int		irq;
+
+	struct omap_mbox_queue	*txq, *rxq;
+
+	struct omap_mbox_ops	*ops;
+
+	mbox_msg_t		seq_snd, seq_rcv;
+
+	struct device		dev;
+
+	struct omap_mbox	*next;
+	void			*priv;
+
+	void			(*err_notify)(void);
+};
+
+int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg, void *);
+void omap_mbox_init_seq(struct omap_mbox *);
+
+struct omap_mbox *omap_mbox_get(const char *);
+void omap_mbox_put(struct omap_mbox *);
+
+int omap_mbox_register(struct omap_mbox *);
+int omap_mbox_unregister(struct omap_mbox *);
+
+#endif /* MAILBOX_H */
diff --git a/include/asm-arm/arch-omap/mcspi.h b/include/asm-arm/arch-omap/mcspi.h
index 9e7f40a..1254e49 100644
--- a/include/asm-arm/arch-omap/mcspi.h
+++ b/include/asm-arm/arch-omap/mcspi.h
@@ -2,7 +2,6 @@
 #define _OMAP2_MCSPI_H
 
 struct omap2_mcspi_platform_config {
-	unsigned long	base;
 	unsigned short	num_cs;
 };
 
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h
index 48fabc4..14cba97 100644
--- a/include/asm-arm/arch-omap/memory.h
+++ b/include/asm-arm/arch-omap/memory.h
@@ -86,5 +86,18 @@
 
 #endif	/* CONFIG_ARCH_OMAP15XX */
 
+/* Override the ARM default */
+#ifdef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+
+#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0)
+#undef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 2
+#endif
+
+#define CONSISTENT_DMA_SIZE \
+	(((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+
+#endif
+
 #endif
 
diff --git a/include/asm-arm/arch-omap/menelaus.h b/include/asm-arm/arch-omap/menelaus.h
index 88cd4c8..82d276a 100644
--- a/include/asm-arm/arch-omap/menelaus.h
+++ b/include/asm-arm/arch-omap/menelaus.h
@@ -7,10 +7,19 @@
 #ifndef __ASM_ARCH_MENELAUS_H
 #define __ASM_ARCH_MENELAUS_H
 
-extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
-				  unsigned long data);
-extern void menelaus_mmc_remove(void);
-extern void menelaus_mmc_opendrain(int enable);
+extern int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+					  void *data);
+extern void menelaus_unregister_mmc_callback(void);
+extern int menelaus_set_mmc_opendrain(int slot, int enable);
+extern int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_on);
+
+extern int menelaus_set_vmem(unsigned int mV);
+extern int menelaus_set_vio(unsigned int mV);
+extern int menelaus_set_vmmc(unsigned int mV);
+extern int menelaus_set_vaux(unsigned int mV);
+extern int menelaus_set_vdcdc(int dcdc, unsigned int mV);
+extern int menelaus_set_slot_sel(int enable);
+extern int menelaus_get_slot_pin_states(void);
 
 #if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
 #define omap_has_menelaus()	1
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
index f0c7f0f..f7f5cdf 100644
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -159,15 +159,6 @@
 #define UART3_MVR               (OMAP_UART3_BASE + 0x50)
 
 /*
- * ----------------------------------------------------------------------------
- * Pulse-Width Light
- * ----------------------------------------------------------------------------
- */
-#define OMAP16XX_PWL_BASE	(0xfffb5800)
-#define OMAP16XX_PWL_ENABLE	(OMAP16XX_PWL_BASE + 0x00)
-#define OMAP16XX_PWL_CLK_ENABLE	(OMAP16XX_PWL_BASE + 0x04)
-
-/*
  * ---------------------------------------------------------------------------
  * Watchdog timer
  * ---------------------------------------------------------------------------
@@ -199,5 +190,8 @@
 #define WSPR_DISABLE_0         (0x0000aaaa)
 #define WSPR_DISABLE_1         (0x00005555)
 
+/* Mailbox */
+#define OMAP16XX_MAILBOX_BASE	(0xfffcf000)
+
 #endif /*  __ASM_ARCH_OMAP16XX_H */
 
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h
index 6e59805..708b2fa 100644
--- a/include/asm-arm/arch-omap/omap24xx.h
+++ b/include/asm-arm/arch-omap/omap24xx.h
@@ -20,5 +20,14 @@
 #define OMAP24XX_PRCM_BASE	(L4_24XX_BASE + 0x8000)
 #define OMAP24XX_SDRC_BASE	(L3_24XX_BASE + 0x9000)
 
+/* DSP SS */
+#define OMAP24XX_DSP_BASE	0x58000000
+#define OMAP24XX_DSP_MEM_BASE	(OMAP24XX_DSP_BASE + 0x0)
+#define OMAP24XX_DSP_IPI_BASE	(OMAP24XX_DSP_BASE + 0x1000000)
+#define OMAP24XX_DSP_MMU_BASE	(OMAP24XX_DSP_BASE + 0x2000000)
+
+/* Mailbox */
+#define OMAP24XX_MAILBOX_BASE	(L4_24XX_BASE + 0x94000)
+
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h
index fccdb3d..46d7a4f 100644
--- a/include/asm-arm/arch-omap/omapfb.h
+++ b/include/asm-arm/arch-omap/omapfb.h
@@ -24,6 +24,9 @@
 #ifndef __OMAPFB_H
 #define __OMAPFB_H
 
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 /* IOCTL commands. */
 
 #define OMAP_IOW(num, dtype)	_IOW('O', num, dtype)
@@ -35,26 +38,46 @@
 #define OMAPFB_SYNC_GFX		OMAP_IO(37)
 #define OMAPFB_VSYNC		OMAP_IO(38)
 #define OMAPFB_SET_UPDATE_MODE	OMAP_IOW(40, int)
-#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
-#define OMAPFB_GET_CAPS		OMAP_IOR(42, unsigned long)
+#define OMAPFB_GET_CAPS		OMAP_IOR(42, struct omapfb_caps)
 #define OMAPFB_GET_UPDATE_MODE	OMAP_IOW(43, int)
 #define OMAPFB_LCD_TEST		OMAP_IOW(45, int)
 #define OMAPFB_CTRL_TEST	OMAP_IOW(46, int)
-#define OMAPFB_UPDATE_WINDOW	OMAP_IOW(47, struct omapfb_update_window)
-#define OMAPFB_SETUP_PLANE	OMAP_IOW(48, struct omapfb_setup_plane)
-#define OMAPFB_ENABLE_PLANE	OMAP_IOW(49, struct omapfb_enable_plane)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
 #define OMAPFB_SET_COLOR_KEY	OMAP_IOW(50, struct omapfb_color_key)
+#define OMAPFB_GET_COLOR_KEY	OMAP_IOW(51, struct omapfb_color_key)
+#define OMAPFB_SETUP_PLANE	OMAP_IOW(52, struct omapfb_plane_info)
+#define OMAPFB_QUERY_PLANE	OMAP_IOW(53, struct omapfb_plane_info)
+#define OMAPFB_UPDATE_WINDOW	OMAP_IOW(54, struct omapfb_update_window)
+#define OMAPFB_SETUP_MEM	OMAP_IOW(55, struct omapfb_mem_info)
+#define OMAPFB_QUERY_MEM	OMAP_IOW(56, struct omapfb_mem_info)
 
 #define OMAPFB_CAPS_GENERIC_MASK	0x00000fff
 #define OMAPFB_CAPS_LCDC_MASK		0x00fff000
 #define OMAPFB_CAPS_PANEL_MASK		0xff000000
 
 #define OMAPFB_CAPS_MANUAL_UPDATE	0x00001000
+#define OMAPFB_CAPS_TEARSYNC		0x00002000
+#define OMAPFB_CAPS_PLANE_RELOCATE_MEM	0x00004000
+#define OMAPFB_CAPS_PLANE_SCALE		0x00008000
+#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE	0x00010000
+#define OMAPFB_CAPS_WINDOW_SCALE	0x00020000
+#define OMAPFB_CAPS_WINDOW_OVERLAY	0x00040000
 #define OMAPFB_CAPS_SET_BACKLIGHT	0x01000000
 
 /* Values from DSP must map to lower 16-bits */
-#define OMAPFB_FORMAT_MASK         0x00ff
-#define OMAPFB_FORMAT_FLAG_DOUBLE  0x0100
+#define OMAPFB_FORMAT_MASK		0x00ff
+#define OMAPFB_FORMAT_FLAG_DOUBLE	0x0100
+#define OMAPFB_FORMAT_FLAG_TEARSYNC	0x0200
+#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC	0x0400
+#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY	0x0800
+#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY	0x1000
+
+#define OMAPFB_EVENT_READY	1
+#define OMAPFB_EVENT_DISABLED	2
+
+#define OMAPFB_MEMTYPE_SDRAM		0
+#define OMAPFB_MEMTYPE_SRAM		1
+#define OMAPFB_MEMTYPE_MAX		1
 
 enum omapfb_color_format {
 	OMAPFB_COLOR_RGB565 = 0,
@@ -64,17 +87,23 @@
 	OMAPFB_COLOR_CLUT_4BPP,
 	OMAPFB_COLOR_CLUT_2BPP,
 	OMAPFB_COLOR_CLUT_1BPP,
+	OMAPFB_COLOR_RGB444,
+	OMAPFB_COLOR_YUY422,
 };
 
 struct omapfb_update_window {
 	__u32 x, y;
 	__u32 width, height;
 	__u32 format;
+	__u32 out_x, out_y;
+	__u32 out_width, out_height;
+	__u32 reserved[8];
 };
 
 struct omapfb_update_window_old {
 	__u32 x, y;
 	__u32 width, height;
+	__u32 format;
 };
 
 enum omapfb_plane {
@@ -88,18 +117,28 @@
 	OMAPFB_CHANNEL_OUT_DIGIT,
 };
 
-struct omapfb_setup_plane {
-	__u8  plane;
+struct omapfb_plane_info {
+	__u32 pos_x;
+	__u32 pos_y;
+	__u8  enabled;
 	__u8  channel_out;
-	__u32 offset;
-	__u32 pos_x, pos_y;
-	__u32 width, height;
-	__u32 color_mode;
+	__u8  mirror;
+	__u8  reserved1;
+	__u32 out_width;
+	__u32 out_height;
+	__u32 reserved2[12];
 };
 
-struct omapfb_enable_plane {
-	__u8  plane;
-	__u8  enable;
+struct omapfb_mem_info {
+	__u32 size;
+	__u8  type;
+	__u8  reserved[3];
+};
+
+struct omapfb_caps {
+	__u32 ctrl;
+	__u32 plane_color;
+	__u32 wnd_color;
 };
 
 enum omapfb_color_key_type {
@@ -141,6 +180,9 @@
 
 #define OMAP_LCDC_PANEL_TFT		0x0100
 
+#define OMAPFB_PLANE_XRES_MIN		8
+#define OMAPFB_PLANE_YRES_MIN		8
+
 #ifdef CONFIG_ARCH_OMAP1
 #define OMAPFB_PLANE_NUM		1
 #else
@@ -169,19 +211,19 @@
 	int		pcd;		/* pixel clock divider.
 					   Obsolete use pixel_clock instead */
 
-	int		(*init)		(struct omapfb_device *fbdev);
-	void		(*cleanup)	(void);
-	int		(*enable)	(void);
-	void		(*disable)	(void);
-	unsigned long	(*get_caps)	(void);
-	int		(*set_bklight_level)(unsigned int level);
-	unsigned int	(*get_bklight_level)(void);
-	unsigned int	(*get_bklight_max)  (void);
-	int		(*run_test)	(int test_num);
+	int		(*init)		(struct lcd_panel *panel,
+					 struct omapfb_device *fbdev);
+	void		(*cleanup)	(struct lcd_panel *panel);
+	int		(*enable)	(struct lcd_panel *panel);
+	void		(*disable)	(struct lcd_panel *panel);
+	unsigned long	(*get_caps)	(struct lcd_panel *panel);
+	int		(*set_bklight_level)(struct lcd_panel *panel,
+					     unsigned int level);
+	unsigned int	(*get_bklight_level)(struct lcd_panel *panel);
+	unsigned int	(*get_bklight_max)  (struct lcd_panel *panel);
+	int		(*run_test)	(struct lcd_panel *panel, int test_num);
 };
 
-struct omapfb_device;
-
 struct extif_timings {
 	int cs_on_time;
 	int cs_off_time;
@@ -202,9 +244,10 @@
 };
 
 struct lcd_ctrl_extif {
-	int  (*init)		(void);
+	int  (*init)		(struct omapfb_device *fbdev);
 	void (*cleanup)		(void);
 	void (*get_clk_info)	(u32 *clk_period, u32 *max_clk_div);
+	unsigned long (*get_max_tx_rate)(void);
 	int  (*convert_timings)	(struct extif_timings *timings);
 	void (*set_timings)	(const struct extif_timings *timings);
 	void (*set_bits_per_cycle)(int bpc);
@@ -213,31 +256,48 @@
 	void (*write_data)	(const void *buf, unsigned int len);
 	void (*transfer_area)	(int width, int height,
 				 void (callback)(void * data), void *data);
+	int  (*setup_tearsync)	(unsigned pin_cnt,
+				 unsigned hs_pulse_time, unsigned vs_pulse_time,
+				 int hs_pol_inv, int vs_pol_inv, int div);
+	int  (*enable_tearsync) (int enable, unsigned line);
+
 	unsigned long		max_transmit_size;
 };
 
 struct omapfb_notifier_block {
 	struct notifier_block	nb;
 	void			*data;
+	int			plane_idx;
 };
 
-typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
-					   unsigned long event,
-					   struct omapfb_device *fbdev);
+typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
+					  unsigned long event,
+					  void *fbi);
+
+struct omapfb_mem_region {
+	dma_addr_t	paddr;
+	void		*vaddr;
+	unsigned long	size;
+	u8		type;		/* OMAPFB_PLANE_MEM_* */
+	unsigned	alloc:1;	/* allocated by the driver */
+	unsigned	map:1;		/* kernel mapped by the driver */
+};
+
+struct omapfb_mem_desc {
+	int				region_cnt;
+	struct omapfb_mem_region	region[OMAPFB_PLANE_NUM];
+};
 
 struct lcd_ctrl {
 	const char	*name;
 	void		*data;
 
 	int		(*init)		  (struct omapfb_device *fbdev,
-					   int ext_mode, int req_vram_size);
+					   int ext_mode,
+					   struct omapfb_mem_desc *req_md);
 	void		(*cleanup)	  (void);
 	void		(*bind_client)	  (struct omapfb_notifier_block *nb);
-	void		(*get_vram_layout)(unsigned long *size,
-					   void **virt_base,
-					   dma_addr_t *phys_base);
-	int		(*mmap)		  (struct vm_area_struct *vma);
-	unsigned long	(*get_caps)	  (void);
+	void		(*get_caps)	  (int plane, struct omapfb_caps *caps);
 	int		(*set_update_mode)(enum omapfb_update_mode mode);
 	enum omapfb_update_mode (*get_update_mode)(void);
 	int		(*setup_plane)	  (int plane, int channel_out,
@@ -245,8 +305,16 @@
 					   int screen_width,
 					   int pos_x, int pos_y, int width,
 					   int height, int color_mode);
+	int		(*setup_mem)	  (int plane, size_t size,
+					   int mem_type, unsigned long *paddr);
+	int		(*mmap)		  (struct fb_info *info,
+					   struct vm_area_struct *vma);
+	int		(*set_scale)	  (int plane,
+					   int orig_width, int orig_height,
+					   int out_width, int out_height);
 	int		(*enable_plane)	  (int plane, int enable);
-	int		(*update_window)  (struct omapfb_update_window *win,
+	int		(*update_window)  (struct fb_info *fbi,
+					   struct omapfb_update_window *win,
 					   void (*callback)(void *),
 					   void *callback_data);
 	void		(*sync)		  (void);
@@ -257,7 +325,7 @@
 					   u16 blue, u16 transp,
 					   int update_hw_mem);
 	int		(*set_color_key)  (struct omapfb_color_key *ck);
-
+	int		(*get_color_key)  (struct omapfb_color_key *ck);
 };
 
 enum omapfb_state {
@@ -266,19 +334,20 @@
 	OMAPFB_ACTIVE	= 100
 };
 
+struct omapfb_plane_struct {
+	int				idx;
+	struct omapfb_plane_info	info;
+	enum omapfb_color_format	color_mode;
+	struct omapfb_device		*fbdev;
+};
+
 struct omapfb_device {
 	int			state;
 	int                     ext_lcdc;               /* Using external
                                                            LCD controller */
 	struct mutex		rqueue_mutex;
 
-	void			*vram_virt_base;
-	dma_addr_t		vram_phys_base;
-	unsigned long		vram_size;
-
-	int			color_mode;
 	int			palette_size;
-	int			mirror;
 	u32			pseudo_palette[17];
 
 	struct lcd_panel	*panel;			/* LCD panel */
@@ -286,19 +355,19 @@
 	struct lcd_ctrl		*int_ctrl;		/* internal LCD ctrl */
 	struct lcd_ctrl_extif	*ext_if;		/* LCD ctrl external
 							   interface */
-	struct fb_info		*fb_info;
-
 	struct device		*dev;
+	struct fb_var_screeninfo	new_var;	/* for mode changes */
+
+	struct omapfb_mem_desc		mem_desc;
+	struct fb_info			*fb_info[OMAPFB_PLANE_NUM];
 };
 
 struct omapfb_platform_data {
-	struct omap_lcd_config   lcd;
-	struct omap_fbmem_config fbmem;
+	struct omap_lcd_config		lcd;
+	struct omapfb_mem_desc		mem_desc;
+	void				*ctrl_platform_data;
 };
 
-#define OMAPFB_EVENT_READY	1
-#define OMAPFB_EVENT_DISABLED	2
-
 #ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
 #else
@@ -310,15 +379,16 @@
 extern void omapfb_notify_clients(struct omapfb_device *fbdev,
 				  unsigned long event);
 extern int  omapfb_register_client(struct omapfb_notifier_block *nb,
-				    omapfb_notifier_callback_t callback,
-				    void *callback_data);
+				   omapfb_notifier_callback_t callback,
+				   void *callback_data);
 extern int  omapfb_unregister_client(struct omapfb_notifier_block *nb);
-extern int  omapfb_update_window_async(struct omapfb_update_window *win,
-					void (*callback)(void *),
-					void *callback_data);
+extern int  omapfb_update_window_async(struct fb_info *fbi,
+				       struct omapfb_update_window *win,
+				       void (*callback)(void *),
+				       void *callback_data);
 
-/* in arch/arm/plat-omap/devices.c */
-extern void omapfb_reserve_mem(void);
+/* in arch/arm/plat-omap/fb.c */
+extern void omapfb_set_ctrl_platform_data(void *pdata);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h
index 6fc0dd5..bb9bb3f 100644
--- a/include/asm-arm/arch-omap/sram.h
+++ b/include/asm-arm/arch-omap/sram.h
@@ -20,9 +20,6 @@
 				      u32 mem_type);
 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
-extern unsigned long omap_fb_sram_start;
-extern unsigned long omap_fb_sram_size;
-
 /* Do not use these */
 extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
 extern unsigned long sram_reprogram_clock_sz;
diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h
index 054fb9a..99ae9ea 100644
--- a/include/asm-arm/arch-omap/usb.h
+++ b/include/asm-arm/arch-omap/usb.h
@@ -7,9 +7,27 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define OTG_BASE			0xfffb0400
-#define UDC_BASE			0xfffb4000
-#define OMAP_OHCI_BASE			0xfffba000
+#define OMAP1_OTG_BASE			0xfffb0400
+#define OMAP1_UDC_BASE			0xfffb4000
+#define OMAP1_OHCI_BASE			0xfffba000
+
+#define OMAP2_OHCI_BASE			0x4805e000
+#define OMAP2_UDC_BASE			0x4805e200
+#define OMAP2_OTG_BASE			0x4805e300
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#define OTG_BASE			OMAP1_OTG_BASE
+#define UDC_BASE			OMAP1_UDC_BASE
+#define OMAP_OHCI_BASE			OMAP1_OHCI_BASE
+
+#else
+
+#define OTG_BASE			OMAP2_OTG_BASE
+#define UDC_BASE			OMAP2_UDC_BASE
+#define OMAP_OHCI_BASE			OMAP2_OHCI_BASE
+
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -28,6 +46,7 @@
 #	define	 HST_IDLE_EN		(1 << 14)
 #	define	 DEV_IDLE_EN		(1 << 13)
 #	define	 OTG_RESET_DONE		(1 << 2)
+#	define	 OTG_SOFT_RESET		(1 << 1)
 #define OTG_SYSCON_2_REG		OTG_REG32(0x08)
 #	define	 OTG_EN			(1 << 31)
 #	define	 USBX_SYNCHRO		(1 << 30)
@@ -103,6 +122,7 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* OMAP1 */
 #define	USB_TRANSCEIVER_CTRL_REG	__REG32(0xfffe1000 + 0x0064)
 #	define	CONF_USB2_UNI_R		(1 << 8)
 #	define	CONF_USB1_UNI_R		(1 << 7)
@@ -111,7 +131,17 @@
 #	define	CONF_USB_PWRDN_DM_R	(1 << 2)
 #	define	CONF_USB_PWRDN_DP_R	(1 << 1)
 
-
-
+/* OMAP2 */
+#define	CONTROL_DEVCONF_REG		__REG32(L4_24XX_BASE + 0x0274)
+#	define	USB_UNIDIR			0x0
+#	define	USB_UNIDIR_TLL			0x1
+#	define	USB_BIDIR			0x2
+#	define	USB_BIDIR_TLL			0x3
+#	define	USBT0WRMODEI(x)		((x) << 22)
+#	define	USBT1WRMODEI(x)		((x) << 20)
+#	define	USBT2WRMODEI(x)		((x) << 18)
+#	define	USBT2TLL5PI		(1 << 17)
+#	define	USB0PUENACTLOI		(1 << 16)
+#	define	USBSTANDBYCTRL		(1 << 15)
 
 #endif	/* __ASM_ARCH_OMAP_USB_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-power.h b/include/asm-arm/arch-s3c2410/regs-power.h
index 6c319ea..94ff965 100644
--- a/include/asm-arm/arch-s3c2410/regs-power.h
+++ b/include/asm-arm/arch-s3c2410/regs-power.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-power.h
+/* linux/include/asm-arm/arch-s3c2410/regs-power.h
  *
  * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
  *		      http://armlinux.simtec.co.uk/
diff --git a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
index ff0536d..cd9e265 100644
--- a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
+/* linux/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
  *
  * Copyright (c) 2007 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
diff --git a/include/asm-arm/arch-s3c2410/regs-watchdog.h b/include/asm-arm/arch-s3c2410/regs-watchdog.h
index f4fff44..a9c5d49 100644
--- a/include/asm-arm/arch-s3c2410/regs-watchdog.h
+++ b/include/asm-arm/arch-s3c2410/regs-watchdog.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-watchdog.h
+/* linux/include/asm-arm/arch-s3c2410/regs-watchdog.h
  *
  * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
  *		      http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/udc.h b/include/asm-arm/arch-s3c2410/udc.h
index e59ec33..b8aa6cb 100644
--- a/include/asm-arm/arch-s3c2410/udc.h
+++ b/include/asm-arm/arch-s3c2410/udc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/udc.h
+/* linux/include/asm-arm/arch-s3c2410/udc.h
  *
  * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
  *
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index afad32c..d1294a4 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -102,6 +102,14 @@
 //# endif
 #endif
 
+#if defined(CONFIG_CPU_V7)
+//# ifdef _CACHE
+#  define MULTI_CACHE 1
+//# else
+//#  define _CACHE v7
+//# endif
+#endif
+
 #if !defined(_CACHE) && !defined(MULTI_CACHE)
 #error Unknown cache maintainence model
 #endif
@@ -418,11 +426,19 @@
  */
 #define flush_icache_page(vma,page)	do { } while (0)
 
-#define __cacheid_present(val)		(val != read_cpuid(CPUID_ID))
-#define __cacheid_vivt(val)		((val & (15 << 25)) != (14 << 25))
-#define __cacheid_vipt(val)		((val & (15 << 25)) == (14 << 25))
-#define __cacheid_vipt_nonaliasing(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25))
-#define __cacheid_vipt_aliasing(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+#define __cacheid_present(val)			(val != read_cpuid(CPUID_ID))
+#define __cacheid_type_v7(val)			((val & (7 << 29)) == (4 << 29))
+
+#define __cacheid_vivt_prev7(val)		((val & (15 << 25)) != (14 << 25))
+#define __cacheid_vipt_prev7(val)		((val & (15 << 25)) == (14 << 25))
+#define __cacheid_vipt_nonaliasing_prev7(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25))
+#define __cacheid_vipt_aliasing_prev7(val)	((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+
+#define __cacheid_vivt(val)			(__cacheid_type_v7(val) ? 0 : __cacheid_vivt_prev7(val))
+#define __cacheid_vipt(val)			(__cacheid_type_v7(val) ? 1 : __cacheid_vipt_prev7(val))
+#define __cacheid_vipt_nonaliasing(val)		(__cacheid_type_v7(val) ? 1 : __cacheid_vipt_nonaliasing_prev7(val))
+#define __cacheid_vipt_aliasing(val)		(__cacheid_type_v7(val) ? 0 : __cacheid_vipt_aliasing_prev7(val))
+#define __cacheid_vivt_asid_tagged_instr(val)	(__cacheid_type_v7(val) ? ((val & (3 << 14)) == (1 << 14)) : 0)
 
 #if defined(CONFIG_CPU_CACHE_VIVT) && !defined(CONFIG_CPU_CACHE_VIPT)
 
@@ -430,6 +446,7 @@
 #define cache_is_vipt()			0
 #define cache_is_vipt_nonaliasing()	0
 #define cache_is_vipt_aliasing()	0
+#define icache_is_vivt_asid_tagged()	0
 
 #elif defined(CONFIG_CPU_CACHE_VIPT)
 
@@ -447,6 +464,12 @@
 		__cacheid_vipt_aliasing(__val);				\
 	})
 
+#define icache_is_vivt_asid_tagged()					\
+	({								\
+		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
+		__cacheid_vivt_asid_tagged_instr(__val);		\
+	})
+
 #else
 
 #define cache_is_vivt()							\
@@ -475,6 +498,13 @@
 		 __cacheid_vipt_aliasing(__val);			\
 	})
 
+#define icache_is_vivt_asid_tagged()					\
+	({								\
+		unsigned int __val = read_cpuid(CPUID_CACHETYPE);	\
+		__cacheid_present(__val) &&				\
+		 __cacheid_vivt_asid_tagged_instr(__val);		\
+	})
+
 #endif
 
 #endif
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
index abfb75b..c8b5d0d 100644
--- a/include/asm-arm/dma-mapping.h
+++ b/include/asm-arm/dma-mapping.h
@@ -445,7 +445,7 @@
  *
  * The dmabounce routines call this function whenever a dma-mapping
  * is requested to determine whether a given buffer needs to be bounced
- * or not. The function must return 0 if the the buffer is OK for
+ * or not. The function must return 0 if the buffer is OK for
  * DMA access and 1 if the buffer needs to be bounced.
  *
  */
diff --git a/include/asm-arm/glue.h b/include/asm-arm/glue.h
index 0cc5d3b..22274ce 100644
--- a/include/asm-arm/glue.h
+++ b/include/asm-arm/glue.h
@@ -38,6 +38,7 @@
  *	  v5tej_early	- ARMv5 with Thumb and Java early abort handler
  *	  xscale	- ARMv5 with Thumb with Xscale extensions
  *	  v6_early	- ARMv6 generic early abort handler
+ *	  v7_early	- ARMv7 generic early abort handler
  */
 #undef CPU_ABORT_HANDLER
 #undef MULTI_ABORT
@@ -106,6 +107,14 @@
 # endif
 #endif
 
+#ifdef CONFIG_CPU_ABRT_EV7
+# ifdef CPU_ABORT_HANDLER
+#  define MULTI_ABORT 1
+# else
+#  define CPU_ABORT_HANDLER v7_early_abort
+# endif
+#endif
+
 #ifndef CPU_ABORT_HANDLER
 #error Unknown data abort handler type
 #endif
diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
index f8755c8..4981ad4 100644
--- a/include/asm-arm/mmu_context.h
+++ b/include/asm-arm/mmu_context.h
@@ -36,8 +36,9 @@
  * The context ID is used by debuggers and trace logic, and
  * should be unique within all running processes.
  */
-#define ASID_BITS	8
-#define ASID_MASK	((~0) << ASID_BITS)
+#define ASID_BITS		8
+#define ASID_MASK		((~0) << ASID_BITS)
+#define ASID_FIRST_VERSION	(1 << ASID_BITS)
 
 extern unsigned int cpu_last_asid;
 
@@ -96,8 +97,7 @@
 #ifdef CONFIG_MMU
 	unsigned int cpu = smp_processor_id();
 
-	if (prev != next) {
-		cpu_set(cpu, next->cpu_vm_mask);
+	if (!cpu_test_and_set(cpu, next->cpu_vm_mask) || prev != next) {
 		check_context(next);
 		cpu_switch_mm(next->pgd, next);
 		if (cache_is_vivt())
diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h
index ea7e54c..5599d4e 100644
--- a/include/asm-arm/proc-fns.h
+++ b/include/asm-arm/proc-fns.h
@@ -193,6 +193,14 @@
 #   define CPU_NAME cpu_v6
 #  endif
 # endif
+# ifdef CONFIG_CPU_V7
+#  ifdef CPU_NAME
+#   undef  MULTI_CPU
+#   define MULTI_CPU
+#  else
+#   define CPU_NAME cpu_v7
+#  endif
+# endif
 #endif
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index f2da3b6..6f8e6a6 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -14,6 +14,7 @@
 #define CPU_ARCH_ARMv5TE	6
 #define CPU_ARCH_ARMv5TEJ	7
 #define CPU_ARCH_ARMv6		8
+#define CPU_ARCH_ARMv7		9
 
 /*
  * CR1 bits (CP#15 CR1)
@@ -155,7 +156,11 @@
 #define vectors_high()	(0)
 #endif
 
-#if defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ >= 6
+#if __LINUX_ARM_ARCH__ >= 7
+#define isb() __asm__ __volatile__ ("isb" : : : "memory")
+#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
+#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
+#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
 #define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
 				    : : "r" (0) : "memory")
 #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
diff --git a/include/asm-arm26/io.h b/include/asm-arm26/io.h
index 2aa033b..a5a7a4d 100644
--- a/include/asm-arm26/io.h
+++ b/include/asm-arm26/io.h
@@ -321,7 +321,7 @@
 
 #define mmiowb()
 
-/* the following macro is depreciated */
+/* the following macro is deprecated */
 #define ioaddr(port)                    __ioaddr((port))
 
 /*
diff --git a/include/asm-arm26/memory.h b/include/asm-arm26/memory.h
index a65f10b..7c1e5be 100644
--- a/include/asm-arm26/memory.h
+++ b/include/asm-arm26/memory.h
@@ -60,7 +60,7 @@
 /*
  * Virtual <-> DMA view memory address translations
  * Again, these are *only* valid on the kernel direct mapped RAM
- * memory.  Use of these is *depreciated*.
+ * memory.  Use of these is *deprecated*.
  */
 #define virt_to_bus(x)		((unsigned long)(x))
 #define bus_to_virt(x)		((void *)((unsigned long)(x)))
@@ -93,7 +93,7 @@
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 
 /*
- * We should really eliminate virt_to_bus() here - it's depreciated.
+ * We should really eliminate virt_to_bus() here - it's deprecated.
  */
 #define page_to_bus(page)	(page_address(page))
 
diff --git a/include/asm-arm26/setup.h b/include/asm-arm26/setup.h
index 1a867b4..10fd07c 100644
--- a/include/asm-arm26/setup.h
+++ b/include/asm-arm26/setup.h
@@ -70,7 +70,7 @@
 /* describes where the compressed ramdisk image lives */
 /*
  * this one accidentally used virtual addresses - as such,
- * its depreciated.
+ * it's deprecated.
  */
 #define ATAG_INITRD	0x54410005
 
diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
new file mode 100644
index 0000000..2bdc5bd
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/cpu.h
@@ -0,0 +1,33 @@
+/*
+ * AVR32 and (fake) AT91 CPU identification
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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 __ASM_ARCH_CPU_H
+#define __ASM_ARCH_CPU_H
+
+/*
+ * Only AT32AP7000 is defined for now. We can identify the specific
+ * chip at runtime, but I'm not sure if it's really worth it.
+ */
+#ifdef CONFIG_CPU_AT32AP7000
+# define cpu_is_at32ap7000()	(1)
+#else
+# define cpu_is_at32ap7000()	(0)
+#endif
+
+/*
+ * Since this is AVR32, we will never run on any AT91 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at91rm9200()	(0)
+#define cpu_is_at91sam9xe()	(0)
+#define cpu_is_at91sam9260()	(0)
+#define cpu_is_at91sam9261()	(0)
+#define cpu_is_at91sam9263()	(0)
+
+#endif /* __ASM_ARCH_CPU_H */
diff --git a/include/asm-avr32/setup.h b/include/asm-avr32/setup.h
index 1ff1a21..b0828d4 100644
--- a/include/asm-avr32/setup.h
+++ b/include/asm-avr32/setup.h
@@ -110,7 +110,7 @@
 	int	(*parse)(struct tag *);
 };
 
-#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
+#define __tag __attribute_used__ __attribute__((__section__(".taglist.init")))
 #define __tagtable(tag, fn)						\
 	static struct tagtable __tagtable_##fn __tag = { tag, fn }
 
diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h
index 8f51204..2418cce 100644
--- a/include/asm-avr32/unistd.h
+++ b/include/asm-avr32/unistd.h
@@ -295,8 +295,10 @@
 #define __NR_shmdt		276
 #define __NR_shmctl		277
 
+#define __NR_utimensat		278
+
 #ifdef __KERNEL__
-#define NR_syscalls		278
+#define NR_syscalls		279
 
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-blackfin/processor.h b/include/asm-blackfin/processor.h
index 997465c..0336ff1 100644
--- a/include/asm-blackfin/processor.h
+++ b/include/asm-blackfin/processor.h
@@ -58,10 +58,10 @@
 	(_regs)->pc = (_pc);						\
 	if (current->mm)						\
 		(_regs)->p5 = current->mm->start_data;			\
-	current->thread_info->l1_task_info.stack_start			\
+	task_thread_info(current)->l1_task_info.stack_start		\
 		= (void *)current->mm->context.stack_start;		\
-	current->thread_info->l1_task_info.lowest_sp = (void *)(_usp);	       	\
-	memcpy(L1_SCRATCH_TASK_INFO, &current->thread_info->l1_task_info,	\
+	task_thread_info(current)->l1_task_info.lowest_sp = (void *)(_usp); \
+	memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info, \
 		sizeof(*L1_SCRATCH_TASK_INFO));				\
 	wrusp(_usp);							\
 } while(0)
diff --git a/include/asm-blackfin/system.h b/include/asm-blackfin/system.h
index b5bf6e7..5e5f1a0 100644
--- a/include/asm-blackfin/system.h
+++ b/include/asm-blackfin/system.h
@@ -239,9 +239,9 @@
 
 #define switch_to(prev,next,last) \
 do {    \
-	memcpy (&prev->thread_info->l1_task_info, L1_SCRATCH_TASK_INFO, \
+	memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \
 		sizeof *L1_SCRATCH_TASK_INFO); \
-	memcpy (L1_SCRATCH_TASK_INFO, &next->thread_info->l1_task_info, \
+	memcpy (L1_SCRATCH_TASK_INFO, &task_thread_info(next)->l1_task_info, \
 		sizeof *L1_SCRATCH_TASK_INFO); \
 	(last) = resume (prev, next);   \
 } while (0)
diff --git a/include/asm-frv/tlb.h b/include/asm-frv/tlb.h
index f94fe5c..cd458eb 100644
--- a/include/asm-frv/tlb.h
+++ b/include/asm-frv/tlb.h
@@ -3,7 +3,11 @@
 
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_MMU
+extern void check_pgt_cache(void);
+#else
 #define check_pgt_cache() do {} while(0)
+#endif
 
 /*
  * we don't need any special per-pte or per-vma handling...
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index 584c041..d0ea678 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -186,8 +186,8 @@
 #define __NR_rt_sigtimedwait	177
 #define __NR_rt_sigqueueinfo	178
 #define __NR_rt_sigsuspend	179
-#define __NR_pread		180
-#define __NR_pwrite		181
+#define __NR_pread64		180
+#define __NR_pwrite64		181
 #define __NR_chown		182
 #define __NR_getcwd		183
 #define __NR_capget		184
@@ -316,10 +316,20 @@
 #define __NR_faccessat		307
 #define __NR_pselect6		308
 #define __NR_ppoll		309
+#define __NR_unshare		310
+#define __NR_set_robust_list	311
+#define __NR_get_robust_list	312
+#define __NR_splice		313
+#define __NR_sync_file_range	314
+#define __NR_tee		315
+#define __NR_vmsplice		316
+#define __NR_move_pages		317
+#define __NR_getcpu		318
+#define __NR_epoll_pwait	319
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 310
+#define NR_syscalls 320
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h
index 7833931..cd8a964 100644
--- a/include/asm-generic/bitops/atomic.h
+++ b/include/asm-generic/bitops/atomic.h
@@ -58,7 +58,7 @@
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 273b506..a20fe98 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -27,7 +27,7 @@
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-i386/boot.h b/include/asm-i386/boot.h
index e7686d0..bd024ab 100644
--- a/include/asm-i386/boot.h
+++ b/include/asm-i386/boot.h
@@ -12,7 +12,7 @@
 #define EXTENDED_VGA	0xfffe		/* 80x50 mode */
 #define ASK_VGA		0xfffd		/* ask for it at bootup */
 
-/* Physical address where kenrel should be loaded. */
+/* Physical address where kernel should be loaded. */
 #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
 				+ (CONFIG_PHYSICAL_ALIGN - 1)) \
 				& ~(CONFIG_PHYSICAL_ALIGN - 1))
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 3503ad6..118e981 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -122,21 +122,21 @@
 	__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0)
 #define alloc_bootmem_node(pgdat, x)					\
 ({									\
-	struct pglist_data  __attribute__ ((unused))			\
+	struct pglist_data  __maybe_unused			\
 				*__alloc_bootmem_node__pgdat = (pgdat);	\
 	__alloc_bootmem_node(NODE_DATA(0), (x), SMP_CACHE_BYTES,	\
 						__pa(MAX_DMA_ADDRESS));	\
 })
 #define alloc_bootmem_pages_node(pgdat, x)				\
 ({									\
-	struct pglist_data  __attribute__ ((unused))			\
+	struct pglist_data  __maybe_unused			\
 				*__alloc_bootmem_node__pgdat = (pgdat);	\
 	__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE,		\
 						__pa(MAX_DMA_ADDRESS))	\
 })
 #define alloc_bootmem_low_pages_node(pgdat, x)				\
 ({									\
-	struct pglist_data  __attribute__ ((unused))			\
+	struct pglist_data  __maybe_unused			\
 				*__alloc_bootmem_node__pgdat = (pgdat);	\
 	__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0);		\
 })
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 26861df..df21ea0 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -86,62 +86,50 @@
 
 #define rdmsr(msr,val1,val2)						\
 	do {								\
-		unsigned long long __val = native_read_msr(msr);	\
-		val1 = __val;						\
-		val2 = __val >> 32;					\
+		u64 __val = native_read_msr(msr);			\
+		(val1) = (u32)__val;					\
+		(val2) = (u32)(__val >> 32);				\
 	} while(0)
 
-#define wrmsr(msr,val1,val2)						\
-	native_write_msr(msr, ((unsigned long long)val2 << 32) | val1)
-
-#define rdmsrl(msr,val)					\
-	do {						\
-		(val) = native_read_msr(msr);		\
-	} while(0)
-
-static inline void wrmsrl (unsigned long msr, unsigned long long val)
+static inline void wrmsr(u32 __msr, u32 __low, u32 __high)
 {
-	unsigned long lo, hi;
-	lo = (unsigned long) val;
-	hi = val >> 32;
-	wrmsr (msr, lo, hi);
+	native_write_msr(__msr, ((u64)__high << 32) | __low);
 }
 
+#define rdmsrl(msr,val)							\
+	((val) = native_read_msr(msr))
+
+#define wrmsrl(msr,val)	native_write_msr(msr, val)
+
 /* wrmsr with exception handling */
-#define wrmsr_safe(msr,val1,val2)						\
-	(native_write_msr_safe(msr, ((unsigned long long)val2 << 32) | val1))
+static inline int wrmsr_safe(u32 __msr, u32 __low, u32 __high)
+{
+	return native_write_msr_safe(__msr, ((u64)__high << 32) | __low);
+}
 
 /* rdmsr with exception handling */
 #define rdmsr_safe(msr,p1,p2)						\
 	({								\
 		int __err;						\
-		unsigned long long __val = native_read_msr_safe(msr, &__err);\
-		(*p1) = __val;						\
-		(*p2) = __val >> 32;					\
+		u64 __val = native_read_msr_safe(msr, &__err);		\
+		(*p1) = (u32)__val;					\
+		(*p2) = (u32)(__val >> 32);				\
 		__err;							\
 	})
 
-#define rdtsc(low,high)						\
-	do {							\
-		u64 _l = native_read_tsc();			\
-		(low) = (u32)_l;				\
-		(high) = _l >> 32;				\
-	} while(0)
-
 #define rdtscl(low)						\
-	do {							\
-		(low) = native_read_tsc();			\
-	} while(0)
+	((low) = (u32)native_read_tsc())
 
-#define rdtscll(val) ((val) = native_read_tsc())
+#define rdtscll(val)						\
+	((val) = native_read_tsc())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
 
 #define rdpmc(counter,low,high)					\
 	do {							\
 		u64 _l = native_read_pmc();			\
-		low = (u32)_l;					\
-		high = _l >> 32;				\
+		(low)  = (u32)_l;				\
+		(high) = (u32)(_l >> 32);			\
 	} while(0)
 #endif	/* !CONFIG_PARAVIRT */
 
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index e2e7f98..bc5c12c 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -560,11 +560,6 @@
 {
 	return PVOP_CALL0(u64, read_tsc);
 }
-#define rdtsc(low,high) do {			\
-	u64 _l = paravirt_read_tsc();		\
-	low = (u32)_l;				\
-	high = _l >> 32;			\
-} while(0)
 
 #define rdtscl(low) do {			\
 	u64 _l = paravirt_read_tsc();		\
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 090abc1..0c71327 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -124,20 +124,6 @@
 	return cpus_weight(cpu_callout_map);
 }
 
-#ifdef CONFIG_X86_LOCAL_APIC
-
-#ifdef APIC_DEFINITION
-extern int hard_smp_processor_id(void);
-#else
-#include <mach_apicdef.h>
-static inline int hard_smp_processor_id(void)
-{
-	/* we don't want to mark this access volatile - bad code generation */
-	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
-}
-#endif
-#endif
-
 extern int safe_smp_processor_id(void);
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
@@ -152,10 +138,31 @@
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
-#endif
+#endif /* CONFIG_SMP */
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#ifdef APIC_DEFINITION
+extern int hard_smp_processor_id(void);
+#else
+#include <mach_apicdef.h>
+static inline int hard_smp_processor_id(void)
+{
+	/* we don't want to mark this access volatile - bad code generation */
+	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
+#endif /* APIC_DEFINITION */
+
+#else /* CONFIG_X86_LOCAL_APIC */
+
+#ifndef CONFIG_SMP
+#define hard_smp_processor_id()		0
+#endif
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
 extern u8 apicid_2_node[];
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/sync_bitops.h b/include/asm-i386/sync_bitops.h
index 7d72351..cbce08a 100644
--- a/include/asm-i386/sync_bitops.h
+++ b/include/asm-i386/sync_bitops.h
@@ -24,7 +24,7 @@
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non-x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index bf01d4b..4cb0f91 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -172,7 +172,7 @@
 #define TS_USEDFPU		0x0001	/* FPU was used by this task this quantum (SMP) */
 #define TS_POLLING		0x0002	/* True if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index 27f9df6..c054d7a 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -66,6 +66,7 @@
 #define IA64_PERFMON_VECTOR		0xee	/* performanc monitor interrupt vector */
 #define IA64_TIMER_VECTOR		0xef	/* use highest-prio group 15 interrupt for timer */
 #define	IA64_MCA_WAKEUP_VECTOR		0xf0	/* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
+#define IA64_IPI_LOCAL_TLB_FLUSH	0xfc	/* SMP flush local TLB */
 #define IA64_IPI_RESCHEDULE		0xfd	/* SMP reschedule */
 #define IA64_IPI_VECTOR			0xfe	/* inter-processor interrupt vector */
 
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 20f98f1..421cb6b 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -83,7 +83,7 @@
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
 				  unsigned long trigger);
 extern void iosapic_unregister_intr (unsigned int irq);
-extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
+extern void __devinit iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
 				      unsigned long polarity,
 				      unsigned long trigger);
 extern int __init iosapic_register_platform_intr (u32 int_type,
diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
index 60fd4ae..c600249 100644
--- a/include/asm-ia64/smp.h
+++ b/include/asm-ia64/smp.h
@@ -38,6 +38,8 @@
 	return lid.f.id << 8 | lid.f.eid;
 }
 
+#define hard_smp_processor_id()		ia64_get_lid()
+
 #ifdef CONFIG_SMP
 
 #define XTP_OFFSET		0x1e0008
@@ -110,8 +112,6 @@
 		writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
 }
 
-#define hard_smp_processor_id()		ia64_get_lid()
-
 /* Upping and downing of CPUs */
 extern int __cpu_disable (void);
 extern void __cpu_die (unsigned int cpu);
@@ -128,7 +128,7 @@
 extern void identify_siblings (struct cpuinfo_ia64 *);
 extern int is_multithreading_enabled(void);
 
-#else
+#else /* CONFIG_SMP */
 
 #define cpu_logical_id(i)		0
 #define cpu_physical_id(i)		ia64_get_lid()
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index 2c4004e..291e8ce 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -106,6 +106,7 @@
 /* interrupt handling */
 #define SAL_INTR_ALLOC		1
 #define SAL_INTR_FREE		2
+#define SAL_INTR_REDIRECT	3
 
 /*
  * operations available on the generic SN_SAL_SYSCTL_OP
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 91698599..7d0241d 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -85,6 +85,7 @@
 #define TIF_SYSCALL_TRACE	3	/* syscall trace active */
 #define TIF_SYSCALL_AUDIT	4	/* syscall auditing active */
 #define TIF_SINGLESTEP		5	/* restore singlestep on return to user mode */
+#define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE		17
 #define TIF_MCA_INIT		18	/* this task is processing MCA or INIT */
@@ -96,6 +97,7 @@
 #define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_SYSCALL_TRACEAUDIT	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
+#define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
@@ -104,12 +106,12 @@
 #define _TIF_FREEZE		(1 << TIF_FREEZE)
 
 /* "work to do on user-return" bits */
-#define TIF_ALLWORK_MASK	(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define TIF_ALLWORK_MASK	(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_RESTORE_SIGMASK)
 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */
 #define TIF_WORK_MASK		(TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 
 #define TS_POLLING		1 	/* true if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* _ASM_IA64_THREAD_INFO_H */
diff --git a/include/asm-ia64/tlbflush.h b/include/asm-ia64/tlbflush.h
index cf9acb9..e37f9fb 100644
--- a/include/asm-ia64/tlbflush.h
+++ b/include/asm-ia64/tlbflush.h
@@ -27,9 +27,11 @@
 #ifdef CONFIG_SMP
   extern void smp_flush_tlb_all (void);
   extern void smp_flush_tlb_mm (struct mm_struct *mm);
+  extern void smp_flush_tlb_cpumask (cpumask_t xcpumask);
 # define flush_tlb_all()	smp_flush_tlb_all()
 #else
 # define flush_tlb_all()	local_flush_tlb_all()
+# define smp_flush_tlb_cpumask(m) local_flush_tlb_all()
 #endif
 
 static inline void
@@ -94,6 +96,15 @@
 	 */
 }
 
+/*
+ * Flush the local TLB. Invoked from another cpu using an IPI.
+ */
+#ifdef CONFIG_SMP
+void smp_local_flush_tlb(void);
+#else
+#define smp_local_flush_tlb()
+#endif
+
 #define flush_tlb_kernel_range(start, end)	flush_tlb_all()	/* XXX fix me */
 
 #endif /* _ASM_IA64_TLBFLUSH_H */
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index a9e1fa4..861c8ec 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -283,7 +283,8 @@
 #define __NR_readlinkat			1291
 #define __NR_fchmodat			1292
 #define __NR_faccessat			1293
-/* 1294, 1295 reserved for pselect/ppoll */
+#define __NR_pselect6			1294
+#define __NR_ppoll			1295
 #define __NR_unshare			1296
 #define __NR_splice			1297
 #define __NR_set_robust_list		1298
@@ -300,6 +301,7 @@
 #define NR_syscalls			281 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 #ifdef CONFIG_IA32_SUPPORT
 # define __ARCH_WANT_SYS_FADVISE64
@@ -310,6 +312,7 @@
 # define __ARCH_WANT_SYS_OLDUMOUNT
 # define __ARCH_WANT_SYS_SIGPENDING
 # define __ARCH_WANT_SYS_SIGPROCMASK
+# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 # define __ARCH_WANT_COMPAT_SYS_TIME
 #endif
 
diff --git a/include/asm-m32r/smp.h b/include/asm-m32r/smp.h
index abd937a..078e1a5 100644
--- a/include/asm-m32r/smp.h
+++ b/include/asm-m32r/smp.h
@@ -108,6 +108,10 @@
 #define IPI_SHIFT	(0)
 #define NR_IPIS		(8)
 
-#endif	/* CONFIG_SMP */
+#else	/* CONFIG_SMP */
+
+#define hard_smp_processor_id()		0
+
+#endif /* CONFIG_SMP */
 
 #endif	/* _ASM_M32R_SMP_H */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 06cdece..f62f5c9 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -136,7 +136,7 @@
 	"add3	"reg0", "addr", #0x2000;		\n\t"	\
 	"ld	"reg0", @"reg0";			\n\t"	\
 	"unlock	"reg0", @"reg1";			\n\t"
-	/* FIXME: This workaround code cannot handle kenrel modules
+	/* FIXME: This workaround code cannot handle kernel modules
 	 * correctly under SMP environment.
 	 */
 #else	/* CONFIG_CHIP_M32700_TS1 */
diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h
index f28acd0..6211363 100644
--- a/include/asm-m68k/atarihw.h
+++ b/include/asm-m68k/atarihw.h
@@ -2,7 +2,7 @@
 ** linux/atarihw.h -- This header defines some macros and pointers for
 **                    the various Atari custom hardware registers.
 **
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Bj”rn Brauel
 **
 ** 5/1/94 Roman Hodek:
 **   Added definitions for TT specific chips.
diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h
index 0ed454f..ce6c445 100644
--- a/include/asm-m68k/atariints.h
+++ b/include/asm-m68k/atariints.h
@@ -1,7 +1,7 @@
 /*
 ** atariints.h -- Atari Linux interrupt handling structs and prototypes
 **
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Bj”rn Brauel
 **
 ** 5/2/94 Roman Hodek:
 **   TT interrupt definitions added.
diff --git a/include/asm-m68k/scatterlist.h b/include/asm-m68k/scatterlist.h
index 8e61226..24887a2 100644
--- a/include/asm-m68k/scatterlist.h
+++ b/include/asm-m68k/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _M68K_SCATTERLIST_H
 #define _M68K_SCATTERLIST_H
 
+#include <linux/types.h>
+
 struct scatterlist {
 	struct page *page;
 	unsigned int offset;
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index c4d622a..d635a37 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -37,17 +37,17 @@
 #define init_stack		(init_thread_union.stack)
 
 #define task_thread_info(tsk)	(&(tsk)->thread.info)
-#define task_stack_page(tsk)	((void *)(tsk)->thread_info)
+#define task_stack_page(tsk)	((tsk)->stack)
 #define current_thread_info()	task_thread_info(current)
 
 #define __HAVE_THREAD_FUNCTIONS
 
 #define setup_thread_stack(p, org) ({			\
-	*(struct task_struct **)(p)->thread_info = (p);	\
+	*(struct task_struct **)(p)->stack = (p);	\
 	task_thread_info(p)->task = (p);		\
 })
 
-#define end_of_stack(p) ((unsigned long *)(p)->thread_info + 1)
+#define end_of_stack(p) ((unsigned long *)(p)->stack + 1)
 
 /* entry.S relies on these definitions!
  * bits 0-7 are tested at every exception exit
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index c7c945b..dbf834f 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -254,7 +254,7 @@
 extern char arcs_cmdline[CL_SIZE];
 
 /*
- * Registers a0, a1, a3 and a4 as passed to the kenrel entry by firmware
+ * Registers a0, a1, a3 and a4 as passed to the kernel entry by firmware
  */
 extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 30f23a2..3713d25 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -55,7 +55,7 @@
 	if (cpu_has_dsp)						\
 		__save_dsp(prev);					\
 	next->thread.emulated_fp = 0;					\
-	(last) = resume(prev, next, next->thread_info);			\
+	(last) = resume(prev, next, task_thread_info(next));		\
 	if (cpu_has_dsp)						\
 		__restore_dsp(current);					\
 } while(0)
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index fe85790..11f4222 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -152,7 +152,7 @@
 
 static inline int __is_compat_task(struct task_struct *t)
 {
-	return test_ti_thread_flag(t->thread_info, TIF_32BIT);
+	return test_ti_thread_flag(task_thread_info(t), TIF_32BIT);
 }
 
 static inline int is_compat_task(void)
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
index 6739457..e2ca55b 100644
--- a/include/asm-powerpc/mmu-hash64.h
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -350,10 +350,13 @@
 
 typedef struct {
 	mm_context_id_t id;
-	u16 user_psize;			/* page size index */
-	u16 sllp;			/* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
-	u16 low_htlb_areas, high_htlb_areas;
+	u16 user_psize;		/* page size index */
+
+#ifdef CONFIG_PPC_MM_SLICES
+	u64 low_slices_psize;	/* SLB page size encodings */
+	u64 high_slices_psize;  /* 4 bits per slice for now */
+#else
+	u16 sllp;		/* SLB page size encoding */
 #endif
 	unsigned long vdso_base;
 } mm_context_t;
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index cf95274..c6a5b17 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -83,8 +83,8 @@
 
 	mm_context_t context;
 	u16 vmalloc_sllp;
-	u16 slb_cache[SLB_CACHE_ENTRIES];
 	u16 slb_cache_ptr;
+	u16 slb_cache[SLB_CACHE_ENTRIES];
 
 	/*
 	 * then miscellaneous read-write fields
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
index eab779c..3448a3d 100644
--- a/include/asm-powerpc/page_64.h
+++ b/include/asm-powerpc/page_64.h
@@ -88,58 +88,56 @@
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_PPC_MM_SLICES
 
-#define HTLB_AREA_SHIFT		40
-#define HTLB_AREA_SIZE		(1UL << HTLB_AREA_SHIFT)
-#define GET_HTLB_AREA(x)	((x) >> HTLB_AREA_SHIFT)
+#define SLICE_LOW_SHIFT		28
+#define SLICE_HIGH_SHIFT	40
 
-#define LOW_ESID_MASK(addr, len)    \
-	(((1U << (GET_ESID(min((addr)+(len)-1, 0x100000000UL))+1)) \
-	  - (1U << GET_ESID(min((addr), 0x100000000UL)))) & 0xffff)
-#define HTLB_AREA_MASK(addr, len)   (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
-		                      - (1U << GET_HTLB_AREA(addr))) & 0xffff)
+#define SLICE_LOW_TOP		(0x100000000ul)
+#define SLICE_NUM_LOW		(SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
+#define SLICE_NUM_HIGH		(PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
+
+#define GET_LOW_SLICE_INDEX(addr)	((addr) >> SLICE_LOW_SHIFT)
+#define GET_HIGH_SLICE_INDEX(addr)	((addr) >> SLICE_HIGH_SHIFT)
+
+#ifndef __ASSEMBLY__
+
+struct slice_mask {
+	u16 low_slices;
+	u16 high_slices;
+};
+
+struct mm_struct;
+
+extern unsigned long slice_get_unmapped_area(unsigned long addr,
+					     unsigned long len,
+					     unsigned long flags,
+					     unsigned int psize,
+					     int topdown,
+					     int use_cache);
+
+extern unsigned int get_slice_psize(struct mm_struct *mm,
+				    unsigned long addr);
+
+extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
+extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
 
 #define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+extern int is_hugepage_only_range(struct mm_struct *m,
+				  unsigned long addr,
+				  unsigned long len);
+
+#endif /* __ASSEMBLY__ */
+#else
+#define slice_init()
+#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
 #define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
 #define ARCH_HAS_SETCLEAR_HUGE_PTE
-
-#define touches_hugepage_low_range(mm, addr, len) \
-	(((addr) < 0x100000000UL) \
-	 && (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas))
-#define touches_hugepage_high_range(mm, addr, len) \
-	((((addr) + (len)) > 0x100000000UL) \
-	  && (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas))
-
-#define __within_hugepage_low_range(addr, len, segmask) \
-	( (((addr)+(len)) <= 0x100000000UL) \
-	  && ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask)))
-#define within_hugepage_low_range(addr, len) \
-	__within_hugepage_low_range((addr), (len), \
-				    current->mm->context.low_htlb_areas)
-#define __within_hugepage_high_range(addr, len, zonemask) \
-	( ((addr) >= 0x100000000UL) \
-	  && ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask)))
-#define within_hugepage_high_range(addr, len) \
-	__within_hugepage_high_range((addr), (len), \
-				    current->mm->context.high_htlb_areas)
-
-#define is_hugepage_only_range(mm, addr, len) \
-	(touches_hugepage_high_range((mm), (addr), (len)) || \
-	  touches_hugepage_low_range((mm), (addr), (len)))
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
-#define in_hugepage_area(context, addr) \
-	(cpu_has_feature(CPU_FTR_16M_PAGE) && \
-	 ( ( (addr) >= 0x100000000UL) \
-	   ? ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) \
-	   : ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) )
-
-#else /* !CONFIG_HUGETLB_PAGE */
-
-#define in_hugepage_area(mm, addr)	0
-
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #ifdef MODULE
diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h
index 30b50cf..d9a3a8c 100644
--- a/include/asm-powerpc/pgalloc-64.h
+++ b/include/asm-powerpc/pgalloc-64.h
@@ -14,18 +14,11 @@
 
 extern struct kmem_cache *pgtable_cache[];
 
-#ifdef CONFIG_PPC_64K_PAGES
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PGD_CACHE_NUM	2
-#define HUGEPTE_CACHE_NUM 3
-#else
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PUD_CACHE_NUM	1
-#define PGD_CACHE_NUM	0
-#define HUGEPTE_CACHE_NUM 2
-#endif
+#define PGD_CACHE_NUM		0
+#define PUD_CACHE_NUM		1
+#define PMD_CACHE_NUM		1
+#define HUGEPTE_CACHE_NUM	2
+#define PTE_NONCACHE_NUM	3  /* from GFP rather than kmem_cache */
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
@@ -91,8 +84,7 @@
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 					  unsigned long address)
 {
-	return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
-				GFP_KERNEL|__GFP_REPEAT);
+        return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
@@ -103,12 +95,12 @@
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-	kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
+	free_page((unsigned long)pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	pte_free_kernel(page_address(ptepage));
+	__free_page(ptepage);
 }
 
 #define PGF_CACHENUM_MASK	0x3
@@ -130,14 +122,17 @@
 	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
 	int cachenum = pgf.val & PGF_CACHENUM_MASK;
 
-	kmem_cache_free(pgtable_cache[cachenum], p);
+	if (cachenum == PTE_NONCACHE_NUM)
+		free_page((unsigned long)p);
+	else
+		kmem_cache_free(pgtable_cache[cachenum], p);
 }
 
 extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
 
 #define __pte_free_tlb(tlb, ptepage)	\
 	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-		PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
+		PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1))
 #define __pmd_free_tlb(tlb, pmd) 	\
 	pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
 		PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
index 1744d6a..add5481 100644
--- a/include/asm-powerpc/pgtable-4k.h
+++ b/include/asm-powerpc/pgtable-4k.h
@@ -80,7 +80,11 @@
 
 #define pte_iterate_hashed_end() } while(0)
 
-#define pte_pagesize_index(pte)	MMU_PAGE_4K
+#ifdef CONFIG_PPC_HAS_HASH_64K
+#define pte_pagesize_index(mm, addr, pte)	get_slice_psize(mm, addr)
+#else
+#define pte_pagesize_index(mm, addr, pte)	MMU_PAGE_4K
+#endif
 
 /*
  * 4-level page tables related bits
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 16ef497..31cbd3d 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -35,6 +35,11 @@
 #define _PAGE_HPTE_SUB0	0x08000000 /* combo only: first sub page */
 #define _PAGE_COMBO	0x10000000 /* this is a combo 4k page */
 #define _PAGE_4K_PFN	0x20000000 /* PFN is for a single 4k page */
+
+/* Note the full page bits must be in the same location as for normal
+ * 4k pages as the same asssembly will be used to insert 64K pages
+ * wether the kernel has CONFIG_PPC_64K_PAGES or not
+ */
 #define _PAGE_F_SECOND  0x00008000 /* full page: hidx bits */
 #define _PAGE_F_GIX     0x00007000 /* full page: hidx bits */
 
@@ -88,7 +93,7 @@
 
 #define pte_iterate_hashed_end() } while(0); } } while(0)
 
-#define pte_pagesize_index(pte)	\
+#define pte_pagesize_index(mm, addr, pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
 #define remap_4k_pfn(vma, addr, pfn, prot)				\
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index d74b296..6dcd7a8 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -64,7 +64,7 @@
  * eeh_slot_error_detail -- record and EEH error condition to the log
  * @severity: 1 if temporary, 2 if permanent failure.
  *
- * Obtains the the EEH error details from the RTAS subsystem,
+ * Obtains the EEH error details from the RTAS subsystem,
  * and then logs these details with the RTAS error log system.
  */
 void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 01717f2..d037f50 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -83,6 +83,7 @@
 
 #else
 /* for UP */
+#define hard_smp_processor_id()		0
 #define smp_setup_cpu_maps()
 
 #endif /* CONFIG_SMP */
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index 02e56a6..c48ae18 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -235,6 +235,12 @@
  */
 struct spu_state {
 	struct spu_lscsa *lscsa;
+#ifdef CONFIG_SPU_FS_64K_LS
+	int		use_big_pages;
+	/* One struct page per 64k page */
+#define SPU_LSCSA_NUM_BIG_PAGES	(sizeof(struct spu_lscsa) / 0x10000)
+	struct page	*lscsa_pages[SPU_LSCSA_NUM_BIG_PAGES];
+#endif
 	struct spu_problem_collapsed prob;
 	struct spu_priv1_collapsed priv1;
 	struct spu_priv2_collapsed priv2;
@@ -247,12 +253,14 @@
 	spinlock_t register_lock;
 };
 
-extern void spu_init_csa(struct spu_state *csa);
+extern int spu_init_csa(struct spu_state *csa);
 extern void spu_fini_csa(struct spu_state *csa);
 extern int spu_save(struct spu_state *prev, struct spu *spu);
 extern int spu_restore(struct spu_state *new, struct spu *spu);
 extern int spu_switch(struct spu_state *prev, struct spu_state *new,
 		      struct spu *spu);
+extern int spu_alloc_lscsa(struct spu_state *csa);
+extern void spu_free_lscsa(struct spu_state *csa);
 
 #endif /* !__SPU__ */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h
index 833a8af..1ad4eed 100644
--- a/include/asm-ppc/hydra.h
+++ b/include/asm-ppc/hydra.h
@@ -8,7 +8,7 @@
  *	Macintosh Technology in the Common Hardware Reference Platform
  *	Apple Computer, Inc.
  *
- *	© Copyright 1995 Apple Computer, Inc. All rights reserved.
+ *	© Copyright 1995 Apple Computer, Inc. All rights reserved.
  *
  *  It's available online from http://chrp.apple.com/MacTech.pdf.
  *  You can obtain paper copies of this book from computer bookstores or by
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 0a28e6d..76e424f 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -110,6 +110,7 @@
 	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 }
 
+#define hard_smp_processor_id()		0
 #define smp_cpu_not_running(cpu)	1
 #define smp_setup_cpu_possible_map()	do { } while (0)
 #endif
diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
index 794c36d..46f925c 100644
--- a/include/asm-sh/bug.h
+++ b/include/asm-sh/bug.h
@@ -1,12 +1,12 @@
 #ifndef __ASM_SH_BUG_H
 #define __ASM_SH_BUG_H
 
+#define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
+
 #ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
 #define HAVE_ARCH_WARN_ON
 
-#define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
-
 /**
  * _EMIT_BUG_ENTRY
  * %1 - __FILE__
diff --git a/include/asm-sh/cpu-features.h b/include/asm-sh/cpu-features.h
index 4bccd7c0..86308aa 100644
--- a/include/asm-sh/cpu-features.h
+++ b/include/asm-sh/cpu-features.h
@@ -20,5 +20,6 @@
 #define CPU_HAS_PTEA		0x0020	/* PTEA register */
 #define CPU_HAS_LLSC		0x0040	/* movli.l/movco.l */
 #define CPU_HAS_L2_CACHE	0x0080	/* Secondary cache / URAM */
+#define CPU_HAS_OP32		0x0100	/* 32-bit instruction support */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h
index 954801b..3a66dc4 100644
--- a/include/asm-sh/cpu-sh3/dma.h
+++ b/include/asm-sh/cpu-sh3/dma.h
@@ -26,7 +26,7 @@
 	XMIT_SZ_128BIT,
 };
 
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
 	[XMIT_SZ_8BIT]		= 0,
 	[XMIT_SZ_16BIT]		= 1,
 	[XMIT_SZ_32BIT]		= 2,
diff --git a/include/asm-sh/cpu-sh4/dma-sh7780.h b/include/asm-sh/cpu-sh4/dma-sh7780.h
index 6c90d28..71b426a 100644
--- a/include/asm-sh/cpu-sh4/dma-sh7780.h
+++ b/include/asm-sh/cpu-sh4/dma-sh7780.h
@@ -28,7 +28,7 @@
 /*
  * The DMA count is defined as the number of bytes to transfer.
  */
-static unsigned int __attribute__ ((used)) ts_shift[] = {
+static unsigned int ts_shift[] __maybe_unused = {
 	[XMIT_SZ_8BIT]		= 0,
 	[XMIT_SZ_16BIT]		= 1,
 	[XMIT_SZ_32BIT]		= 2,
diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
index c135e9c..36e26a9 100644
--- a/include/asm-sh/cpu-sh4/dma.h
+++ b/include/asm-sh/cpu-sh4/dma.h
@@ -53,7 +53,7 @@
 /*
  * The DMA count is defined as the number of bytes to transfer.
  */
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
 	[XMIT_SZ_64BIT]		= 3,
 	[XMIT_SZ_8BIT]		= 0,
 	[XMIT_SZ_16BIT]		= 1,
diff --git a/include/asm-sh/dmabrg.h b/include/asm-sh/dmabrg.h
new file mode 100644
index 0000000..c5edba2
--- /dev/null
+++ b/include/asm-sh/dmabrg.h
@@ -0,0 +1,23 @@
+/*
+ * SH7760 DMABRG (USB/Audio) support
+ */
+
+#ifndef _DMABRG_H_
+#define _DMABRG_H_
+
+/* IRQ sources */
+#define DMABRGIRQ_USBDMA	0
+#define DMABRGIRQ_USBDMAERR	1
+#define DMABRGIRQ_A0TXF		2
+#define DMABRGIRQ_A0TXH		3
+#define DMABRGIRQ_A0RXF		4
+#define DMABRGIRQ_A0RXH		5
+#define DMABRGIRQ_A1TXF		6
+#define DMABRGIRQ_A1TXH		7
+#define DMABRGIRQ_A1RXF		8
+#define DMABRGIRQ_A1RXH		9
+
+extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *);
+extern void dmabrg_free_irq(unsigned int);
+
+#endif
diff --git a/include/asm-sh/edosk7705.h b/include/asm-sh/edosk7705.h
index a1089a6..5bdc9d9 100644
--- a/include/asm-sh/edosk7705.h
+++ b/include/asm-sh/edosk7705.h
@@ -1,5 +1,5 @@
 /*
- * include/asm-sh/edosk7705/io.h
+ * include/asm-sh/edosk7705.h
  *
  * Modified version of io_se.h for the EDOSK7705 specific functions.
  *
diff --git a/include/asm-sh/kdebug.h b/include/asm-sh/kdebug.h
index 493c206..16578b7 100644
--- a/include/asm-sh/kdebug.h
+++ b/include/asm-sh/kdebug.h
@@ -2,20 +2,6 @@
 #define __ASM_SH_KDEBUG_H
 
 #include <linux/notifier.h>
-#include <asm-generic/kdebug.h>
-
-struct pt_regs;
-
-struct die_args {
-	struct pt_regs *regs;
-	int trapnr;
-};
-
-int register_die_notifier(struct notifier_block *nb);
-int unregister_die_notifier(struct notifier_block *nb);
-int register_page_fault_notifier(struct notifier_block *nb);
-int unregister_page_fault_notifier(struct notifier_block *nb);
-extern struct atomic_notifier_head shdie_chain;
 
 /* Grossly misnamed. */
 enum die_val {
@@ -23,14 +9,7 @@
 	DIE_PAGE_FAULT,
 };
 
-static inline int notify_die(enum die_val val, struct pt_regs *regs,
-			     int trap, int sig)
-{
-	struct die_args args = {
-		.regs = regs,
-		.trapnr = trap,
-	};
+int register_page_fault_notifier(struct notifier_block *nb);
+int unregister_page_fault_notifier(struct notifier_block *nb);
 
-	return atomic_notifier_call_chain(&shdie_chain, val, &args);
-}
 #endif /* __ASM_SH_KDEBUG_H */
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
index 888e452..18b613c 100644
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -1,6 +1,12 @@
 #ifndef __ASM_SH_PGALLOC_H
 #define __ASM_SH_PGALLOC_H
 
+#include <linux/quicklist.h>
+#include <asm/page.h>
+
+#define QUICK_PGD 0	/* We preserve special mappings over free */
+#define QUICK_PT 1	/* Other page table pages that are zero on free */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
 				       pte_t *pte)
 {
@@ -13,48 +19,49 @@
 	set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
 }
 
+static inline void pgd_ctor(void *x)
+{
+	pgd_t *pgd = x;
+
+	memcpy(pgd + USER_PTRS_PER_PGD,
+	       swapper_pg_dir + USER_PTRS_PER_PGD,
+	       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
 /*
  * Allocate and free page tables.
  */
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
-
-	if (pgd) {
-		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-		memcpy(pgd + USER_PTRS_PER_PGD,
-		       swapper_pg_dir + USER_PTRS_PER_PGD,
-		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-	}
-
-	return pgd;
+	return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
 static inline void pgd_free(pgd_t *pgd)
 {
-	free_page((unsigned long)pgd);
+	quicklist_free(QUICK_PGD, NULL, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 					  unsigned long address)
 {
-	return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+	return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
 					 unsigned long address)
 {
-	return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+	void *pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+	return pg ? virt_to_page(pg) : NULL;
 }
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-	free_page((unsigned long)pte);
+	quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-	__free_page(pte);
+	quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
 #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
@@ -66,6 +73,11 @@
 
 #define pmd_free(x)			do { } while (0)
 #define __pmd_free_tlb(tlb,x)		do { } while (0)
-#define check_pgt_cache()		do { } while (0)
+
+static inline void check_pgt_cache(void)
+{
+	quicklist_trim(QUICK_PGD, NULL, 25, 16);
+	quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 
 #endif /* __ASM_SH_PGALLOC_H */
diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h
index 6b5e4dd..2d712e7 100644
--- a/include/asm-sh/snapgear.h
+++ b/include/asm-sh/snapgear.h
@@ -1,5 +1,5 @@
 /*
- * include/asm-sh/snapgear/io.h
+ * include/asm-sh/snapgear.h
  *
  * Modified version of io_se.h for the snapgear-specific functions.
  *
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index e7e96ee..82f3e22 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -255,6 +255,15 @@
 	return set_exception_table_vec(evt >> 5, handler);
 }
 
+/*
+ * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
+ */
+#ifdef CONFIG_CPU_SH2A
+extern unsigned int instruction_size(unsigned int insn);
+#else
+#define instruction_size(insn)	(2)
+#endif
+
 /* XXX
  * disable hlt during certain critical i/o operations
  */
diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h
index 17b5e76..701ba84 100644
--- a/include/asm-sh/timer.h
+++ b/include/asm-sh/timer.h
@@ -2,12 +2,14 @@
 #define __ASM_SH_TIMER_H
 
 #include <linux/sysdev.h>
+#include <linux/clocksource.h>
 #include <asm/cpu/timer.h>
 
 struct sys_timer_ops {
 	int (*init)(void);
 	int (*start)(void);
 	int (*stop)(void);
+	cycle_t (*read)(void);
 #ifndef CONFIG_GENERIC_TIME
 	unsigned long (*get_offset)(void);
 #endif
@@ -18,29 +20,8 @@
 
 	struct sys_device	dev;
 	struct sys_timer_ops	*ops;
-
-#ifdef CONFIG_NO_IDLE_HZ
-	struct dyn_tick_timer	*dyn_tick;
-#endif
 };
 
-#ifdef CONFIG_NO_IDLE_HZ
-#define DYN_TICK_ENABLED	(1 << 1)
-
-struct dyn_tick_timer {
-	spinlock_t	lock;
-	unsigned int	state;			/* Current state */
-	int		(*enable)(void);	/* Enables dynamic tick */
-	int		(*disable)(void);	/* Disables dynamic tick */
-	void		(*reprogram)(unsigned long); /* Reprograms the timer */
-	int		(*handler)(int, void *);
-};
-
-void timer_dyn_reprogram(void);
-#else
-#define timer_dyn_reprogram()	do { } while (0)
-#endif
-
 #define TICK_SIZE (tick_nsec / 1000)
 
 extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer;
@@ -58,5 +39,7 @@
 
 /* arch/sh/kernel/time.c */
 void handle_timer_tick(void);
+extern unsigned long sh_hpt_frequency;
+extern struct clocksource clocksource_sh;
 
 #endif /* __ASM_SH_TIMER_H */
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 49be50a..af71e37 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -85,7 +85,7 @@
 #define __NR_sigpending		 73
 #define __NR_sethostname	 74
 #define __NR_setrlimit		 75
-#define __NR_getrlimit	 	 76	/* Back compatible 2Gig limited rlimit */
+#define __NR_getrlimit		 76	/* Back compatible 2Gig limited rlimit */
 #define __NR_getrusage		 77
 #define __NR_gettimeofday	 78
 #define __NR_settimeofday	 79
@@ -328,8 +328,9 @@
 #define __NR_move_pages		317
 #define __NR_getcpu		318
 #define __NR_epoll_pwait	319
+#define __NR_utimensat		320
 
-#define NR_syscalls 320
+#define NR_syscalls 321
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
index b9da9a6..b3f4922 100644
--- a/include/asm-sparc/smp.h
+++ b/include/asm-sparc/smp.h
@@ -165,6 +165,7 @@
 
 #else /* SMP */
 
+#define hard_smp_processor_id()		0
 #define smp_setup_cpu_possible_map() do { } while (0)
 
 #endif /* !(SMP) */
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index e43ed1d..da9bdc5 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -326,8 +326,9 @@
 #define __NR_move_pages		307
 #define __NR_getcpu		308
 #define __NR_epoll_pwait	309
+#define __NR_utimensat		310
 
-#define NR_SYSCALLS		310
+#define NR_SYSCALLS		311
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index f8032e7..627e339 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -7,8 +7,19 @@
 
 struct pt_regs;
 
-extern int register_page_fault_notifier(struct notifier_block *);
-extern int unregister_page_fault_notifier(struct notifier_block *);
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation.  Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
 
 extern void bad_trap(struct pt_regs *, long);
 
@@ -20,7 +31,6 @@
 	DIE_DIE,
 	DIE_TRAP,
 	DIE_TRAP_TL1,
-	DIE_GPF,
 	DIE_CALL,
 	DIE_PAGE_FAULT,
 };
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index becc38f..a331b7b 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -43,4 +43,5 @@
 
 extern int kprobe_exceptions_notify(struct notifier_block *self,
 				    unsigned long val, void *data);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 #endif /* _SPARC64_KPROBES_H */
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
deleted file mode 100644
index c008cecc..0000000
--- a/include/asm-sparc64/pbm.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/* pbm.h: UltraSparc PCI controller software state.
- *
- * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef __SPARC64_PBM_H
-#define __SPARC64_PBM_H
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/msi.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/iommu.h>
-
-/* The abstraction used here is that there are PCI controllers,
- * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
- * underneath.  Each PCI bus module uses an IOMMU (shared by both
- * PBMs of a controller, or per-PBM), and if a streaming buffer
- * is present, each PCI bus module has it's own. (ie. the IOMMU
- * might be shared between PBMs, the STC is never shared)
- * Furthermore, each PCI bus module controls it's own autonomous
- * PCI bus.
- */
-
-extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
-
-#define PCI_STC_FLUSHFLAG_INIT(STC) \
-	(*((STC)->strbuf_flushflag) = 0UL)
-#define PCI_STC_FLUSHFLAG_SET(STC) \
-	(*((STC)->strbuf_flushflag) != 0UL)
-
-/* There can be quite a few ranges and interrupt maps on a PCI
- * segment.  Thus...
- */
-#define PROM_PCIRNG_MAX		64
-#define PROM_PCIIMAP_MAX	64
-
-struct pci_controller_info;
-
-struct pci_pbm_info {
-	/* PCI controller we sit under. */
-	struct pci_controller_info	*parent;
-
-	/* Physical address base of controller registers. */
-	unsigned long			controller_regs;
-
-	/* Physical address base of PBM registers. */
-	unsigned long			pbm_regs;
-
-	/* Physical address of DMA sync register, if any.  */
-	unsigned long			sync_reg;
-
-	/* Opaque 32-bit system bus Port ID. */
-	u32				portid;
-
-	/* Opaque 32-bit handle used for hypervisor calls.  */
-	u32				devhandle;
-
-	/* Chipset version information. */
-	int				chip_type;
-#define PBM_CHIP_TYPE_SABRE		1
-#define PBM_CHIP_TYPE_PSYCHO		2
-#define PBM_CHIP_TYPE_SCHIZO		3
-#define PBM_CHIP_TYPE_SCHIZO_PLUS	4
-#define PBM_CHIP_TYPE_TOMATILLO		5
-	int				chip_version;
-	int				chip_revision;
-
-	/* Name used for top-level resources. */
-	char				*name;
-
-	/* OBP specific information. */
-	struct device_node		*prom_node;
-	u64				ino_bitmap;
-
-	/* PBM I/O and Memory space resources. */
-	struct resource			io_space;
-	struct resource			mem_space;
-
-	/* Base of PCI Config space, can be per-PBM or shared. */
-	unsigned long			config_space;
-
-	/* State of 66MHz capabilities on this PBM. */
-	int				is_66mhz_capable;
-	int				all_devs_66mhz;
-
-#ifdef CONFIG_PCI_MSI
-	/* MSI info.  */
-	u32				msiq_num;
-	u32				msiq_ent_count;
-	u32				msiq_first;
-	u32				msiq_first_devino;
-	u32				msi_num;
-	u32				msi_first;
-	u32				msi_data_mask;
-	u32				msix_data_width;
-	u64				msi32_start;
-	u64				msi64_start;
-	u32				msi32_len;
-	u32				msi64_len;
-	void				*msi_queues;
-	unsigned long			*msi_bitmap;
-#endif /* !(CONFIG_PCI_MSI) */
-
-	/* This PBM's streaming buffer. */
-	struct strbuf			stc;
-
-	/* IOMMU state, potentially shared by both PBM segments. */
-	struct iommu			*iommu;
-
-	/* Now things for the actual PCI bus probes. */
-	unsigned int			pci_first_busno;
-	unsigned int			pci_last_busno;
-	struct pci_bus			*pci_bus;
-};
-
-struct pci_controller_info {
-	/* List of all PCI controllers. */
-	struct pci_controller_info	*next;
-
-	/* Each controller gets a unique index, used mostly for
-	 * error logging purposes.
-	 */
-	int				index;
-
-	/* The PCI bus modules controlled by us. */
-	struct pci_pbm_info		pbm_A;
-	struct pci_pbm_info		pbm_B;
-
-	/* Operations which are controller specific. */
-	void (*scan_bus)(struct pci_controller_info *);
-
-#ifdef CONFIG_PCI_MSI
-	int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
-			     struct msi_desc *entry);
-	void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
-#endif
-
-	/* Now things for the actual PCI bus probes. */
-	struct pci_ops			*pci_ops;
-	unsigned int			pci_first_busno;
-	unsigned int			pci_last_busno;
-};
-
-#endif /* !(__SPARC64_PBM_H) */
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index cca5480..869d16f 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -48,6 +48,7 @@
 
 #else
 
+#define hard_smp_processor_id()		0
 #define smp_setup_cpu_possible_map() do { } while (0)
 #define boot_cpu_id	(0)
 
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index e2dcb87..fcd62759 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -328,8 +328,9 @@
 #define __NR_move_pages		307
 #define __NR_getcpu		308
 #define __NR_epoll_pwait	309
+#define __NR_utimensat		310
 
-#define NR_SYSCALLS		310
+#define NR_SYSCALLS		311
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
diff --git a/include/asm-um/required-features.h b/include/asm-um/required-features.h
new file mode 100644
index 0000000..dfb967b
--- /dev/null
+++ b/include/asm-um/required-features.h
@@ -0,0 +1,9 @@
+#ifndef __UM_REQUIRED_FEATURES_H
+#define __UM_REQUIRED_FEATURES_H
+
+/*
+ * Nothing to see, just need something for the i386 and x86_64 asm
+ * headers to include.
+ */
+
+#endif
diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h
index ca55226..84f8cf2 100644
--- a/include/asm-um/smp.h
+++ b/include/asm-um/smp.h
@@ -24,6 +24,10 @@
 
 extern struct task_struct *idle_threads[NR_CPUS];
 
+#else
+
+#define hard_smp_processor_id()		0
+
 #endif
 
 #endif
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index d570442..3f303d2 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -57,12 +57,6 @@
 
 #define raw_smp_processor_id() read_pda(cpunumber)
 
-static inline int hard_smp_processor_id(void)
-{
-	/* we don't want to mark this access volatile - bad code generation */
-	return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
-}
-
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
 extern void prefill_possible_map(void);
@@ -71,7 +65,13 @@
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
-#endif
+#endif /* CONFIG_SMP */
+
+static inline int hard_smp_processor_id(void)
+{
+	/* we don't want to mark this access volatile - bad code generation */
+	return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
+}
 
 /*
  * Some lowlevel functions might want to know about
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index b7b8021..ead9f9a 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -39,7 +39,7 @@
 		       [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
 		       [ti_flags] "i" (offsetof(struct thread_info, flags)),\
 		       [tif_fork] "i" (TIF_FORK),			  \
-		       [thread_info] "i" (offsetof(struct task_struct, thread_info)), \
+		       [thread_info] "i" (offsetof(struct task_struct, stack)), \
 		       [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent))   \
 		     : "memory", "cc" __EXTRA_CLOBBER)
     
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 74a6c74..10bb5a8 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -162,7 +162,7 @@
 #define TS_COMPAT		0x0002	/* 32bit syscall active */
 #define TS_POLLING		0x0004	/* true if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-xtensa/platform-iss/simcall.h b/include/asm-xtensa/platform-iss/simcall.h
index 6acb572..b7952c0 100644
--- a/include/asm-xtensa/platform-iss/simcall.h
+++ b/include/asm-xtensa/platform-iss/simcall.h
@@ -1,5 +1,5 @@
 /*
- * include/asm-xtensa/platform-iss/hardware.h
+ * include/asm-xtensa/platform-iss/simcall.h
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff --git a/include/linux/aio.h b/include/linux/aio.h
index a30ef13..43dc2eb 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -226,7 +226,8 @@
 		__put_ioctx(kioctx);					\
 } while (0)
 
-#define in_aio() !is_sync_wait(current->io_wait)
+#define in_aio() (unlikely(!is_sync_wait(current->io_wait)))
+
 /* may be used for debugging */
 #define warn_if_async()							\
 do {									\
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index a686eab..db5b00a 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -854,7 +854,7 @@
 
 struct work_struct;
 int kblockd_schedule_work(struct work_struct *work);
-void kblockd_flush(void);
+void kblockd_flush_work(struct work_struct *work);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
 	MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 2665ca0..bf297b0 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -49,6 +49,7 @@
  * @shift:		cycle to nanosecond divisor (power of two)
  * @flags:		flags describing special properties
  * @vread:		vsyscall based read
+ * @resume:		resume function for the clocksource, if necessary
  * @cycle_interval:	Used internally by timekeeping core, please ignore.
  * @xtime_interval:	Used internally by timekeeping core, please ignore.
  */
@@ -65,6 +66,7 @@
 	u32 shift;
 	unsigned long flags;
 	cycle_t (*vread)(void);
+	void (*resume)(void);
 
 	/* timekeeping specific data, ignore */
 	cycle_t cycle_interval;
@@ -209,6 +211,7 @@
 extern int clocksource_register(struct clocksource*);
 extern struct clocksource* clocksource_get_next(void);
 extern void clocksource_change_rating(struct clocksource *cs, int rating);
+extern void clocksource_resume(void);
 
 #ifdef CONFIG_GENERIC_TIME_VSYSCALL
 extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index ccd863d..70a157a 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -253,5 +253,8 @@
 			const compat_sigset_t __user *sigmask,
 			compat_size_t sigsetsize);
 
+asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename,
+				struct compat_timespec __user *t, int flags);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index a9f7947..03ec231 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -40,3 +40,4 @@
 #define  noinline			__attribute__((noinline))
 #define __attribute_pure__		__attribute__((pure))
 #define __attribute_const__		__attribute__((__const__))
+#define __maybe_unused			__attribute__((unused))
diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
index ecd621f..a9e2863 100644
--- a/include/linux/compiler-gcc3.h
+++ b/include/linux/compiler-gcc3.h
@@ -4,9 +4,11 @@
 #include <linux/compiler-gcc.h>
 
 #if __GNUC_MINOR__ >= 3
-# define __attribute_used__	__attribute__((__used__))
+# define __used			__attribute__((__used__))
+# define __attribute_used__	__used				/* deprecated */
 #else
-# define __attribute_used__	__attribute__((__unused__))
+# define __used			__attribute__((__unused__))
+# define __attribute_used__	__used				/* deprecated */
 #endif
 
 #if __GNUC_MINOR__ >= 4
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index fd0cc7c..a03e9398 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -12,7 +12,8 @@
 # define __inline		__inline	__attribute__((always_inline))
 #endif
 
-#define __attribute_used__	__attribute__((__used__))
+#define __used			__attribute__((__used__))
+#define __attribute_used__	__used			/* deprecated */
 #define __must_check 		__attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
 #define __always_inline		inline __attribute__((always_inline))
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 3b6949b..498c3592 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -108,15 +108,30 @@
  * Allow us to avoid 'defined but not used' warnings on functions and data,
  * as well as force them to be emitted to the assembly file.
  *
- * As of gcc 3.3, static functions that are not marked with attribute((used))
- * may be elided from the assembly file.  As of gcc 3.3, static data not so
+ * As of gcc 3.4, static functions that are not marked with attribute((used))
+ * may be elided from the assembly file.  As of gcc 3.4, static data not so
  * marked will not be elided, but this may change in a future gcc version.
  *
+ * NOTE: Because distributions shipped with a backported unit-at-a-time
+ * compiler in gcc 3.3, we must define __used to be __attribute__((used))
+ * for gcc >=3.3 instead of 3.4.
+ *
  * In prior versions of gcc, such functions and data would be emitted, but
  * would be warned about except with attribute((unused)).
+ *
+ * Mark functions that are referenced only in inline assembly as __used so
+ * the code is emitted even though it appears to be unreferenced.
  */
 #ifndef __attribute_used__
-# define __attribute_used__	/* unimplemented */
+# define __attribute_used__	/* deprecated */
+#endif
+
+#ifndef __used
+# define __used			/* unimplemented */
+#endif
+
+#ifndef __maybe_unused
+# define __maybe_unused		/* unimplemented */
 #endif
 
 /*
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 4395e52..7894dd0 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -54,7 +54,7 @@
 	/*
 	 * Was i_next_alloc_goal in ext3_inode_info
 	 * is the *physical* companion to i_next_alloc_block.
-	 * it the the physical block number of the block which was most-recentl
+	 * it the physical block number of the block which was most-recentl
 	 * allocated to this file.  This give us the goal (target) for the next
 	 * allocation when we detect linearly ascending requests.
 	 */
diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
index bb42379..d5b177e 100644
--- a/include/linux/ext4_fs_i.h
+++ b/include/linux/ext4_fs_i.h
@@ -52,7 +52,7 @@
 	/*
 	 * Was i_next_alloc_goal in ext4_inode_info
 	 * is the *physical* companion to i_next_alloc_block.
-	 * it the the physical block number of the block which was most-recentl
+	 * it the physical block number of the block which was most-recentl
 	 * allocated to this file.  This give us the goal (target) for the next
 	 * allocation when we detect linearly ascending requests.
 	 */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index dff7a728..c654d0e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -868,7 +868,7 @@
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 820125c..899fc7f 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -3,6 +3,8 @@
 
 #include <linux/sched.h>
 
+union ktime;
+
 /* Second argument to futex syscall */
 
 
@@ -15,6 +17,19 @@
 #define FUTEX_LOCK_PI		6
 #define FUTEX_UNLOCK_PI		7
 #define FUTEX_TRYLOCK_PI	8
+#define FUTEX_CMP_REQUEUE_PI	9
+
+#define FUTEX_PRIVATE_FLAG	128
+#define FUTEX_CMD_MASK		~FUTEX_PRIVATE_FLAG
+
+#define FUTEX_WAIT_PRIVATE	(FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_PRIVATE	(FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_REQUEUE_PRIVATE	(FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_OP_PRIVATE	(FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
+#define FUTEX_LOCK_PI_PRIVATE	(FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_UNLOCK_PI_PRIVATE	(FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
@@ -83,9 +98,14 @@
 #define FUTEX_OWNER_DIED	0x40000000
 
 /*
+ * Some processes have been requeued on this PI-futex
+ */
+#define FUTEX_WAITER_REQUEUED	0x20000000
+
+/*
  * The rest of the robust-futex field is for the TID:
  */
-#define FUTEX_TID_MASK		0x3fffffff
+#define FUTEX_TID_MASK		0x0fffffff
 
 /*
  * This limit protects against a deliberately circular list.
@@ -94,7 +114,7 @@
 #define ROBUST_LIST_LIMIT	2048
 
 #ifdef __KERNEL__
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
 	      u32 __user *uaddr2, u32 val2, u32 val3);
 
 extern int
@@ -106,9 +126,20 @@
  * Don't rearrange members without looking at hash_futex().
  *
  * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
- * We set bit 0 to indicate if it's an inode-based key.
- */
+ * We use the two low order bits of offset to tell what is the kind of key :
+ *  00 : Private process futex (PTHREAD_PROCESS_PRIVATE)
+ *       (no reference on an inode or mm)
+ *  01 : Shared futex (PTHREAD_PROCESS_SHARED)
+ *	mapped on a file (reference on the underlying inode)
+ *  10 : Shared futex (PTHREAD_PROCESS_SHARED)
+ *       (but private mapping on an mm, and reference taken on it)
+*/
+
+#define FUT_OFF_INODE    1 /* We set bit 0 if key has a reference on inode */
+#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
+
 union futex_key {
+	u32 __user *uaddr;
 	struct {
 		unsigned long pgoff;
 		struct inode *inode;
@@ -125,7 +156,8 @@
 		int offset;
 	} both;
 };
-int get_futex_key(u32 __user *uaddr, union futex_key *key);
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *shared,
+		  union futex_key *key);
 void get_futex_key_refs(union futex_key *key);
 void drop_futex_key_refs(union futex_key *key);
 
diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
index 80764f4..886f5fa 100644
--- a/include/linux/generic_acl.h
+++ b/include/linux/generic_acl.h
@@ -1,5 +1,5 @@
 /*
- * fs/generic_acl.c
+ * include/linux/generic_acl.h
  *
  * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
  *
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 2c65da7..f589559 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -413,6 +413,7 @@
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
 extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
 extern void delete_partition(struct gendisk *, int);
+extern void printk_all_partitions(void);
 
 extern struct gendisk *alloc_disk_node(int minors, int node_id);
 extern struct gendisk *alloc_disk(int minors);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 97a36c3..0d2ef0b 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -176,10 +176,6 @@
 #define free_page(addr) free_pages((addr),0)
 
 void page_alloc_init(void);
-#ifdef CONFIG_NUMA
-void drain_node_pages(int node);
-#else
-static inline void drain_node_pages(int node) { };
-#endif
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
 
 #endif /* __LINUX_GFP_H */
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index a515eb0..98e2cce 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -94,17 +94,26 @@
 
 /*
  * Same but also flushes aliased cache contents to RAM.
+ *
+ * This must be a macro because KM_USER0 and friends aren't defined if
+ * !CONFIG_HIGHMEM
  */
-static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
+#define zero_user_page(page, offset, size, km_type)		\
+	do {							\
+		void *kaddr;					\
+								\
+		BUG_ON((offset) + (size) > PAGE_SIZE);		\
+								\
+		kaddr = kmap_atomic(page, km_type);		\
+		memset((char *)kaddr + (offset), 0, (size));	\
+		flush_dcache_page(page);			\
+		kunmap_atomic(kaddr, (km_type));		\
+	} while (0)
+
+static inline void __deprecated memclear_highpage_flush(struct page *page,
+			unsigned int offset, unsigned int size)
 {
-	void *kaddr;
-
-	BUG_ON(offset + size > PAGE_SIZE);
-
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset((char *)kaddr + offset, 0, size);
-	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
+	zero_user_page(page, offset, size, KM_USER0);
 }
 
 #ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index 9ee0f80..111334f 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -18,7 +18,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
 #ifndef _LINUX_I2C_ALGO_BIT_H
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
index 994eb86..77afbb6 100644
--- a/include/linux/i2c-algo-pcf.h
+++ b/include/linux/i2c-algo-pcf.h
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
 #ifndef _LINUX_I2C_ALGO_PCF_H
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 418dfb5..df4e6a5 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -223,8 +223,9 @@
 /*
  * Register new hardware with ide
  */
-int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
-int ide_register_hw_with_fixup(hw_regs_t *, struct hwif_s **, void (*)(struct hwif_s *));
+int ide_register_hw(hw_regs_t *, int, struct hwif_s **);
+int ide_register_hw_with_fixup(hw_regs_t *, int, struct hwif_s **,
+			       void (*)(struct hwif_s *));
 
 /*
  * Set up hw_regs_t structure before calling ide_register_hw (optional)
@@ -559,9 +560,10 @@
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
 	void		*driver_data;	/* extra driver data */
 	struct hd_driveid	*id;	/* drive model identification info */
+#ifdef CONFIG_IDE_PROC_FS
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
-
+#endif
 	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
 
 	unsigned long sleep;		/* sleep until this time */
@@ -601,16 +603,12 @@
 	unsigned remap_0_to_1	: 1;	/* 0=noremap, 1=remap 0->1 (for EZDrive) */
 	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
 	unsigned vdma		: 1;	/* 1=doing PIO over DMA 0=doing normal DMA */
-	unsigned addressing;		/*      : 3;
-					 *  0=28-bit
-					 *  1=48-bit
-					 *  2=48-bit doing 28-bit
-					 *  3=64-bit
-					 */
 	unsigned scsi		: 1;	/* 0=default, 1=ide-scsi emulation */
 	unsigned sleeping	: 1;	/* 1=sleeping & sleep field valid */
 	unsigned post_reset	: 1;
+	unsigned udma33_warned	: 1;
 
+	u8	addressing;	/* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */
         u8	quirk_list;	/* considered quirky, set for a specific host */
         u8	init_speed;	/* transfer rate set at boot */
         u8	current_speed;	/* current transfer rate set */
@@ -717,11 +715,8 @@
 	int	(*quirkproc)(ide_drive_t *);
 	/* driver soft-power interface */
 	int	(*busproc)(ide_drive_t *, int);
-//	/* host rate limiter */
-//	u8	(*ratemask)(ide_drive_t *);
-//	/* device rate limiter */
-//	u8	(*ratefilter)(ide_drive_t *, u8);
 #endif
+	u8 (*udma_filter)(ide_drive_t *);
 
 	void (*ata_input_data)(ide_drive_t *, void *, u32);
 	void (*ata_output_data)(ide_drive_t *, void *, u32);
@@ -866,16 +861,22 @@
 	unsigned char cmd_buf[4];
 } ide_hwgroup_t;
 
-/* structure attached to the request for IDE_TASK_CMDS */
+typedef struct ide_driver_s ide_driver_t;
 
+extern struct semaphore ide_setting_sem;
+
+int set_io_32bit(ide_drive_t *, int);
+int set_pio_mode(ide_drive_t *, int);
+int set_using_dma(ide_drive_t *, int);
+
+#ifdef CONFIG_IDE_PROC_FS
 /*
  * configurable drive settings
  */
 
 #define TYPE_INT	0
-#define TYPE_INTA	1
-#define TYPE_BYTE	2
-#define TYPE_SHORT	3
+#define TYPE_BYTE	1
+#define TYPE_SHORT	2
 
 #define SETTING_READ	(1 << 0)
 #define SETTING_WRITE	(1 << 1)
@@ -885,8 +886,6 @@
 typedef struct ide_settings_s {
 	char			*name;
 	int			rw;
-	int			read_ioctl;
-	int			write_ioctl;
 	int			data_type;
 	int			min;
 	int			max;
@@ -898,12 +897,7 @@
 	struct ide_settings_s	*next;
 } ide_settings_t;
 
-extern struct semaphore ide_setting_sem;
-extern int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set);
-extern ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name);
-extern int ide_read_setting(ide_drive_t *t, ide_settings_t *setting);
-extern int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val);
-extern void ide_add_generic_settings(ide_drive_t *drive);
+int ide_add_setting(ide_drive_t *, const char *, int, int, int, int, int, int, void *, ide_procset_t *set);
 
 /*
  * /proc/ide interface
@@ -915,15 +909,15 @@
 	write_proc_t	*write_proc;
 } ide_proc_entry_t;
 
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_ide_root;
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void ide_proc_register_port(ide_hwif_t *);
+void ide_proc_unregister_port(ide_hwif_t *);
+void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
+void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
 
-extern void proc_ide_create(void);
-extern void proc_ide_destroy(void);
-extern void create_proc_ide_interfaces(void);
-void destroy_proc_ide_interface(ide_hwif_t *);
-extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
-extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
+void ide_add_generic_settings(ide_drive_t *);
+
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -947,8 +941,13 @@
 	return len;			\
 }
 #else
-static inline void create_proc_ide_interfaces(void) { ; }
-static inline void destroy_proc_ide_interface(ide_hwif_t *hwif) { ; }
+static inline void proc_ide_create(void) { ; }
+static inline void proc_ide_destroy(void) { ; }
+static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+static inline void ide_add_generic_settings(ide_drive_t *drive) { ; }
 #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
@@ -991,7 +990,7 @@
  * The gendriver.owner field should be set to the module owner of this driver.
  * The gendriver.name field should be set to the name of this driver
  */
-typedef struct ide_driver_s {
+struct ide_driver_s {
 	const char			*version;
 	u8				media;
 	unsigned supports_dsc_overlap	: 1;
@@ -999,12 +998,14 @@
 	int		(*end_request)(ide_drive_t *, int, int);
 	ide_startstop_t	(*error)(ide_drive_t *, struct request *rq, u8, u8);
 	ide_startstop_t	(*abort)(ide_drive_t *, struct request *rq);
-	ide_proc_entry_t	*proc;
 	struct device_driver	gen_driver;
 	int		(*probe)(ide_drive_t *);
 	void		(*remove)(ide_drive_t *);
 	void		(*shutdown)(ide_drive_t *);
-} ide_driver_t;
+#ifdef CONFIG_IDE_PROC_FS
+	ide_proc_entry_t	*proc;
+#endif
+};
 
 #define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
 
@@ -1204,9 +1205,14 @@
 
 extern int ideprobe_init(void);
 
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 extern void ide_scan_pcibus(int scan_direction) __init;
 extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
 #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
+#else
+#define ide_pci_register_driver(d) pci_register_driver(d)
+#endif
+
 void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *);
 extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
 
@@ -1214,9 +1220,6 @@
 extern void default_hwif_mmiops(ide_hwif_t *);
 extern void default_hwif_transport(ide_hwif_t *);
 
-void ide_register_subdriver(ide_drive_t *, ide_driver_t *);
-void ide_unregister_subdriver(ide_drive_t *, ide_driver_t *);
-
 #define ON_BOARD		1
 #define NEVER_BOARD		0
 
@@ -1257,6 +1260,7 @@
 	unsigned int		extra;
 	struct ide_pci_device_s	*next;
 	u8			flags;
+	u8			udma_mask;
 } ide_pci_device_t;
 
 extern int ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
@@ -1278,6 +1282,8 @@
 int __ide_dma_bad_drive(ide_drive_t *);
 int __ide_dma_good_drive(ide_drive_t *);
 int ide_use_dma(ide_drive_t *);
+u8 ide_max_dma_mode(ide_drive_t *);
+int ide_tune_dma(ide_drive_t *);
 void ide_dma_off(ide_drive_t *);
 void ide_dma_verbose(ide_drive_t *);
 int ide_set_dma(ide_drive_t *);
@@ -1304,6 +1310,8 @@
 
 #else
 static inline int ide_use_dma(ide_drive_t *drive) { return 0; }
+static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
+static inline int ide_tune_dma(ide_drive_t *drive) { return 0; }
 static inline void ide_dma_off(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
@@ -1348,8 +1356,7 @@
 }
 
 /* ide-lib.c */
-extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
-extern u8 ide_rate_filter(u8 mode, u8 speed); 
+u8 ide_rate_filter(ide_drive_t *, u8);
 extern int ide_dma_enable(ide_drive_t *drive);
 extern char *ide_xfer_verbose(u8 xfer_rate);
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 7951023..45170b2 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -95,7 +95,7 @@
 #define INIT_TASK(tsk)	\
 {									\
 	.state		= 0,						\
-	.thread_info	= &init_thread_info,				\
+	.stack		= &init_thread_info,				\
 	.usage		= ATOMIC_INIT(2),				\
 	.flags		= 0,						\
 	.lock_depth	= -1,						\
diff --git a/include/linux/irda.h b/include/linux/irda.h
index 09d8f10..945ba31 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 1c65e7a..00dd957 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -30,4 +30,7 @@
 int kthread_stop(struct task_struct *k);
 int kthread_should_stop(void);
 
+int kthreadd(void *unused);
+extern struct task_struct *kthreadd_task;
+
 #endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 81bb9c7..c762954 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -43,7 +43,7 @@
  * plain scalar nanosecond based representation can be selected by the
  * config switch CONFIG_KTIME_SCALAR.
  */
-typedef union {
+union ktime {
 	s64	tv64;
 #if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
 	struct {
@@ -54,7 +54,9 @@
 # endif
 	} tv;
 #endif
-} ktime_t;
+};
+
+typedef union ktime ktime_t;		/* Kill this */
 
 #define KTIME_MAX			((s64)~((u64)1 << 63))
 #if (BITS_PER_LONG == 64)
diff --git a/include/linux/mca.h b/include/linux/mca.h
index 5cff292..3797270 100644
--- a/include/linux/mca.h
+++ b/include/linux/mca.h
@@ -94,6 +94,7 @@
 struct mca_driver {
 	const short		*id_table;
 	void			*driver_data;
+	int			integrated_id;
 	struct device_driver	driver;
 };
 #define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
@@ -125,6 +126,7 @@
 extern struct bus_type mca_bus_type;
 
 extern int mca_register_driver(struct mca_driver *drv);
+extern int mca_register_driver_integrated(struct mca_driver *, int);
 extern void mca_unregister_driver(struct mca_driver *drv);
 
 /* WARNING: only called by the boot time device setup */
diff --git a/include/linux/meye.h b/include/linux/meye.h
index 11ec45e..39fd9c8 100644
--- a/include/linux/meye.h
+++ b/include/linux/meye.h
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
  *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 2f1544e..d09b134 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -83,6 +83,9 @@
 
 struct per_cpu_pageset {
 	struct per_cpu_pages pcp[2];	/* 0: hot.  1: cold */
+#ifdef CONFIG_NUMA
+	s8 expire;
+#endif
 #ifdef CONFIG_SMP
 	s8 stat_threshold;
 	s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS];
diff --git a/include/linux/module.h b/include/linux/module.h
index 6d3dc9c..792d483 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -356,6 +356,9 @@
 	   keeping pointers to this stuff */
 	char *args;
 };
+#ifndef MODULE_ARCH_INIT
+#define MODULE_ARCH_INIT {}
+#endif
 
 /* FIXME: It'd be nice to isolate modules during init, too, so they
    aren't used before they (may) fail.  But presently too much code
diff --git a/include/linux/mount.h b/include/linux/mount.h
index dab69af..6d3047d 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -33,7 +33,7 @@
 
 #define MNT_SHARED	0x1000	/* if the vfsmount is a shared mount */
 #define MNT_UNBINDABLE	0x2000	/* if the vfsmount is a unbindable mount */
-#define MNT_PNODE_MASK	0x3000	/* propogation flag mask */
+#define MNT_PNODE_MASK	0x3000	/* propagation flag mask */
 
 struct vfsmount {
 	struct list_head mnt_hash;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 45d482c..fd64ccf 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -9,10 +9,6 @@
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
 
-#ifndef __KERNEL__
-#error This is a kernel header. Perhaps include mtd-user.h instead?
-#endif
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
@@ -137,9 +133,6 @@
 	int numeraseregions;
 	struct mtd_erase_region_info *eraseregions;
 
-	/* This really shouldn't be here. It can go away in 2.5 */
-	u_int32_t bank_size;
-
 	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
 	/* This stuff for eXecute-In-Place */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index cf197ad..d2365c8 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -560,6 +560,7 @@
  * @chip_delay:		R/B delay value in us
  * @options:		Option flags, e.g. 16bit buswidth
  * @ecclayout:		ecc layout info structure
+ * @part_probe_types:	NULL-terminated array of probe types
  * @priv:		hardware controller specific settings
  */
 struct platform_nand_chip {
@@ -570,6 +571,7 @@
 	struct nand_ecclayout	*ecclayout;
 	int			chip_delay;
 	unsigned int		options;
+	const char		**part_probe_types;
 	void			*priv;
 };
 
@@ -578,6 +580,8 @@
  * @hwcontrol:		platform specific hardware control structure
  * @dev_ready:		platform specific function to read ready/busy pin
  * @select_chip:	platform specific chip select function
+ * @cmd_ctrl:		platform specific function for controlling
+ *			ALE/CLE/nCE. Also used to write command and address
  * @priv:		private data to transport driver specific settings
  *
  * All fields are optional and depend on the hardware driver requirements
@@ -586,9 +590,21 @@
 	void		(*hwcontrol)(struct mtd_info *mtd, int cmd);
 	int		(*dev_ready)(struct mtd_info *mtd);
 	void		(*select_chip)(struct mtd_info *mtd, int chip);
+	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat,
+				    unsigned int ctrl);
 	void		*priv;
 };
 
+/**
+ * struct platform_nand_data - container structure for platform-specific data
+ * @chip:		chip level chip structure
+ * @ctrl:		controller level device structure
+ */
+struct platform_nand_data {
+	struct platform_nand_chip	chip;
+	struct platform_nand_ctrl	ctrl;
+};
+
 /* Some helpers to access the data structures */
 static inline
 struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index b81bc2a..0d50ea3 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -121,11 +121,12 @@
  * Also see Documentation/mutex-design.txt.
  */
 extern void fastcall mutex_lock(struct mutex *lock);
-extern int fastcall mutex_lock_interruptible(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass);
+extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
+					unsigned int subclass);
 #else
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
diff --git a/include/linux/nfs4_acl.h b/include/linux/nfs4_acl.h
index 409b6e0..c9c05a7 100644
--- a/include/linux/nfs4_acl.h
+++ b/include/linux/nfs4_acl.h
@@ -44,7 +44,6 @@
 #define NFS4_ACL_MAX 170
 
 struct nfs4_acl *nfs4_acl_new(int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
 int nfs4_acl_get_whotype(char *, u32);
 int nfs4_acl_write_who(int who, char *p);
 int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 10a43ed..9431101 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -112,32 +112,40 @@
 
 #ifdef __KERNEL__
 
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *,
-		struct notifier_block *);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *,
-		struct notifier_block *);
-extern int raw_notifier_chain_register(struct raw_notifier_head *,
-		struct notifier_block *);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
-		struct notifier_block *);
+extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+		struct notifier_block *nb);
+extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+		struct notifier_block *nb);
+extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+		struct notifier_block *nb);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+		struct notifier_block *nb);
 
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
-		struct notifier_block *);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *,
-		struct notifier_block *);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
-		struct notifier_block *);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
-		struct notifier_block *);
+extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+		struct notifier_block *nb);
+extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
+		struct notifier_block *nb);
+extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+		struct notifier_block *nb);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+		struct notifier_block *nb);
 
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
 		unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
+extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+	unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
 		unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *,
+extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+	unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
 		unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+	unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 		unsigned long val, void *v);
+extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+	unsigned long val, void *v, int nr_to_call, int *nr_calls);
 
 #define NOTIFY_DONE		0x0000		/* Don't care */
 #define NOTIFY_OK		0x0001		/* Suits me */
@@ -186,6 +194,20 @@
 #define CPU_DOWN_PREPARE	0x0005 /* CPU (unsigned)v going down */
 #define CPU_DOWN_FAILED		0x0006 /* CPU (unsigned)v NOT going down */
 #define CPU_DEAD		0x0007 /* CPU (unsigned)v dead */
+#define CPU_LOCK_ACQUIRE	0x0008 /* Acquire all hotcpu locks */
+#define CPU_LOCK_RELEASE	0x0009 /* Release all hotcpu locks */
+
+/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
+ * operation in progress
+ */
+#define CPU_TASKS_FROZEN	0x0010
+
+#define CPU_ONLINE_FROZEN	(CPU_ONLINE | CPU_TASKS_FROZEN)
+#define CPU_UP_PREPARE_FROZEN	(CPU_UP_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_UP_CANCELED_FROZEN	(CPU_UP_CANCELED | CPU_TASKS_FROZEN)
+#define CPU_DOWN_PREPARE_FROZEN	(CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_DOWN_FAILED_FROZEN	(CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
+#define CPU_DEAD_FROZEN		(CPU_DEAD | CPU_TASKS_FROZEN)
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 6e8fa30..87545e0 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -107,26 +107,11 @@
 #define PM_SUSPEND_ON		((__force suspend_state_t) 0)
 #define PM_SUSPEND_STANDBY	((__force suspend_state_t) 1)
 #define PM_SUSPEND_MEM		((__force suspend_state_t) 3)
-#define PM_SUSPEND_DISK		((__force suspend_state_t) 4)
-#define PM_SUSPEND_MAX		((__force suspend_state_t) 5)
-
-typedef int __bitwise suspend_disk_method_t;
-
-/* invalid must be 0 so struct pm_ops initialisers can leave it out */
-#define PM_DISK_INVALID		((__force suspend_disk_method_t) 0)
-#define	PM_DISK_PLATFORM	((__force suspend_disk_method_t) 1)
-#define	PM_DISK_SHUTDOWN	((__force suspend_disk_method_t) 2)
-#define	PM_DISK_REBOOT		((__force suspend_disk_method_t) 3)
-#define	PM_DISK_TEST		((__force suspend_disk_method_t) 4)
-#define	PM_DISK_TESTPROC	((__force suspend_disk_method_t) 5)
-#define	PM_DISK_MAX		((__force suspend_disk_method_t) 6)
+#define PM_SUSPEND_MAX		((__force suspend_state_t) 4)
 
 /**
  * struct pm_ops - Callbacks for managing platform dependent suspend states.
  * @valid: Callback to determine whether the given state can be entered.
- * 	If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
- *	always valid and never passed to this call. If not assigned,
- *	no suspend states are valid.
  *	Valid states are advertised in /sys/power/state but can still
  *	be rejected by prepare or enter if the conditions aren't right.
  *	There is a %pm_valid_only_mem function available that can be assigned
@@ -140,24 +125,12 @@
  *
  * @finish: Called when the system has left the given state and all devices
  *	are resumed. The return value is ignored.
- *
- * @pm_disk_mode: The generic code always allows one of the shutdown methods
- *	%PM_DISK_SHUTDOWN, %PM_DISK_REBOOT, %PM_DISK_TEST and
- *	%PM_DISK_TESTPROC. If this variable is set, the mode it is set
- *	to is allowed in addition to those modes and is also made default.
- *	When this mode is sent selected, the @prepare call will be called
- *	before suspending to disk (if present), the @enter call should be
- *	present and will be called after all state has been saved and the
- *	machine is ready to be powered off; the @finish callback is called
- *	after state has been restored. All these calls are called with
- *	%PM_SUSPEND_DISK as the state.
  */
 struct pm_ops {
 	int (*valid)(suspend_state_t state);
 	int (*prepare)(suspend_state_t state);
 	int (*enter)(suspend_state_t state);
 	int (*finish)(suspend_state_t state);
-	suspend_disk_method_t pm_disk_mode;
 };
 
 /**
@@ -276,8 +249,6 @@
 extern void device_resume(void);
 
 #ifdef CONFIG_PM
-extern suspend_disk_method_t pm_disk_mode;
-
 extern int device_suspend(pm_message_t state);
 extern int device_prepare_suspend(pm_message_t state);
 
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 0deb842..f9e77d2 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -87,10 +87,10 @@
  * management of their lifetimes must be completely managed by API users.
  *
  * For API usage, in general,
- * - any function _modifying_ the the tree or tags (inserting or deleting
+ * - any function _modifying_ the tree or tags (inserting or deleting
  *   items, setting or clearing tags must exclude other modifications, and
  *   exclude any functions reading the tree.
- * - any function _reading_ the the tree or tags (looking up items or tags,
+ * - any function _reading_ the tree or tags (looking up items or tags,
  *   gang lookups) must exclude modifications to the tree, but may occur
  *   concurrently with other readers.
  *
diff --git a/include/linux/relay.h b/include/linux/relay.h
index 759a0f9..6cd8c44 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/fs.h>
@@ -38,7 +39,7 @@
 	size_t subbufs_consumed;	/* count of sub-buffers consumed */
 	struct rchan *chan;		/* associated channel */
 	wait_queue_head_t read_wait;	/* reader wait queue */
-	struct delayed_work wake_readers; /* reader wake-up work struct */
+	struct timer_list timer; 	/* reader wake-up timer */
 	struct dentry *dentry;		/* channel file dentry */
 	struct kref kref;		/* channel buffer refcount */
 	struct page **page_array;	/* array of current buffer pages */
diff --git a/include/linux/rslib.h b/include/linux/rslib.h
index ace25ac..746580c 100644
--- a/include/linux/rslib.h
+++ b/include/linux/rslib.h
@@ -34,6 +34,7 @@
  * @prim:	Primitive element, index form
  * @iprim:	prim-th root of 1, index form
  * @gfpoly:	The primitive generator polynominal
+ * @gffunc:	Function to generate the field, if non-canonical representation
  * @users:	Users of this structure
  * @list:	List entry for the rs control list
 */
@@ -48,6 +49,7 @@
 	int 		prim;
 	int 		iprim;
 	int		gfpoly;
+	int		(*gffunc)(int);
 	int		users;
 	struct list_head list;
 };
@@ -77,6 +79,8 @@
 /* Create or get a matching rs control structure */
 struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
 			   int nroots);
+struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
+                                         int fcr, int prim, int nroots);
 
 /* Release a rs control structure */
 void free_rs(struct rs_control *rs);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3d95c48..17b72d8 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -817,7 +817,7 @@
 
 struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
-	struct thread_info *thread_info;
+	void *stack;
 	atomic_t usage;
 	unsigned int flags;	/* per process flags, defined below */
 	unsigned int ptrace;
@@ -1317,6 +1317,7 @@
 
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
+extern void ignore_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
 extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
 
@@ -1512,8 +1513,8 @@
 
 #ifndef __HAVE_THREAD_FUNCTIONS
 
-#define task_thread_info(task) (task)->thread_info
-#define task_stack_page(task) ((void*)((task)->thread_info))
+#define task_thread_info(task)	((struct thread_info *)(task)->stack)
+#define task_stack_page(task)	((task)->stack)
 
 static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
 {
@@ -1523,7 +1524,7 @@
 
 static inline unsigned long *end_of_stack(struct task_struct *p)
 {
-	return (unsigned long *)(p->thread_info + 1);
+	return (unsigned long *)(task_thread_info(p) + 1);
 }
 
 #endif
diff --git a/include/linux/security.h b/include/linux/security.h
index 47e82c1..9eb9e0f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -322,7 +322,7 @@
  *	@dir contains the inode structure of parent of the new file.
  *	@dentry contains the dentry structure of the new file.
  *	@mode contains the mode of the new file.
- *	@dev contains the the device number.
+ *	@dev contains the device number.
  *	Return 0 if permission is granted.
  * @inode_rename:
  *	Check for permission to rename a file or directory.
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 1474905..3fa0fab 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -243,6 +243,131 @@
 
 extern struct kmem_cache *sighand_cachep;
 
+/*
+ * In POSIX a signal is sent either to a specific thread (Linux task)
+ * or to the process as a whole (Linux thread group).  How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later.  When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ *   ignore	- Nothing Happens
+ *   terminate	- kill the process, i.e. all threads in the group,
+ * 		  similar to exit_group.  The group leader (only) reports
+ *		  WIFSIGNALED status to its parent.
+ *   coredump	- write a core dump file describing all threads using
+ *		  the same mm and then kill all those threads
+ *   stop 	- stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ *	+--------------------+------------------+
+ *	|  POSIX signal      |  default action  |
+ *	+--------------------+------------------+
+ *	|  SIGHUP            |  terminate	|
+ *	|  SIGINT            |	terminate	|
+ *	|  SIGQUIT           |	coredump 	|
+ *	|  SIGILL            |	coredump 	|
+ *	|  SIGTRAP           |	coredump 	|
+ *	|  SIGABRT/SIGIOT    |	coredump 	|
+ *	|  SIGBUS            |	coredump 	|
+ *	|  SIGFPE            |	coredump 	|
+ *	|  SIGKILL           |	terminate(+)	|
+ *	|  SIGUSR1           |	terminate	|
+ *	|  SIGSEGV           |	coredump 	|
+ *	|  SIGUSR2           |	terminate	|
+ *	|  SIGPIPE           |	terminate	|
+ *	|  SIGALRM           |	terminate	|
+ *	|  SIGTERM           |	terminate	|
+ *	|  SIGCHLD           |	ignore   	|
+ *	|  SIGCONT           |	ignore(*)	|
+ *	|  SIGSTOP           |	stop(*)(+)  	|
+ *	|  SIGTSTP           |	stop(*)  	|
+ *	|  SIGTTIN           |	stop(*)  	|
+ *	|  SIGTTOU           |	stop(*)  	|
+ *	|  SIGURG            |	ignore   	|
+ *	|  SIGXCPU           |	coredump 	|
+ *	|  SIGXFSZ           |	coredump 	|
+ *	|  SIGVTALRM         |	terminate	|
+ *	|  SIGPROF           |	terminate	|
+ *	|  SIGPOLL/SIGIO     |	terminate	|
+ *	|  SIGSYS/SIGUNUSED  |	coredump 	|
+ *	|  SIGSTKFLT         |	terminate	|
+ *	|  SIGWINCH          |	ignore   	|
+ *	|  SIGPWR            |	terminate	|
+ *	|  SIGRTMIN-SIGRTMAX |	terminate       |
+ *	+--------------------+------------------+
+ *	|  non-POSIX signal  |  default action  |
+ *	+--------------------+------------------+
+ *	|  SIGEMT            |  coredump	|
+ *	+--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)").  This happens regardless of blocking,
+ * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
+ */
+
+#ifdef SIGEMT
+#define SIGEMT_MASK	rt_sigmask(SIGEMT)
+#else
+#define SIGEMT_MASK	0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define rt_sigmask(sig)	(1ULL << ((sig)-1))
+#else
+#define rt_sigmask(sig)	sigmask(sig)
+#endif
+#define siginmask(sig, mask) (rt_sigmask(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+	rt_sigmask(SIGKILL)   |  rt_sigmask(SIGSTOP))
+
+#define SIG_KERNEL_STOP_MASK (\
+	rt_sigmask(SIGSTOP)   |  rt_sigmask(SIGTSTP)   | \
+	rt_sigmask(SIGTTIN)   |  rt_sigmask(SIGTTOU)   )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+        rt_sigmask(SIGQUIT)   |  rt_sigmask(SIGILL)    | \
+	rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGABRT)   | \
+        rt_sigmask(SIGFPE)    |  rt_sigmask(SIGSEGV)   | \
+	rt_sigmask(SIGBUS)    |  rt_sigmask(SIGSYS)    | \
+        rt_sigmask(SIGXCPU)   |  rt_sigmask(SIGXFSZ)   | \
+	SIGEMT_MASK				       )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+        rt_sigmask(SIGCONT)   |  rt_sigmask(SIGCHLD)   | \
+	rt_sigmask(SIGWINCH)  |  rt_sigmask(SIGURG)    )
+
+#define sig_kernel_only(sig) \
+	(((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+	(((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+	(((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+	(((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
+
+#define sig_needs_tasklist(sig)	((sig) == SIGCONT)
+
+#define sig_user_defined(t, signr) \
+	(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&	\
+	 ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
+
+#define sig_fatal(t, signr) \
+	(!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+	 (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 7ba23ec..3f70149 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -83,7 +83,6 @@
  *	These macros fold the SMP functionality into a single CPU system
  */
 #define raw_smp_processor_id()			0
-#define hard_smp_processor_id()			0
 static inline int up_smp_call_function(void)
 {
 	return 0;
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index f56d247..34d4b07 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
 
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 35fa4d5..4a7ae8a 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -396,4 +396,23 @@
 
 #define	RPC_MAX_ADDRBUFLEN	(63U)
 
+/*
+ * When we want to reduce the size of the reserved space in the response
+ * buffer, we need to take into account the size of any checksum data that
+ * may be at the end of the packet. This is difficult to determine exactly
+ * for all cases without actually generating the checksum, so we just use a
+ * static value.
+ */
+static inline void
+svc_reserve_auth(struct svc_rqst *rqstp, int space)
+{
+	int			added_space = 0;
+
+	switch(rqstp->rq_authop->flavour) {
+		case RPC_AUTH_GSS:
+			added_space = RPC_MAX_AUTH_SIZE;
+	}
+	return svc_reserve(rqstp, space + added_space);
+}
+
 #endif /* SUNRPC_SVC_H */
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 79096875..e21dd93 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -37,7 +37,8 @@
 
 	atomic_t    	    	sk_reserved;	/* space on outq that is reserved */
 
-	spinlock_t		sk_defer_lock;	/* protects sk_deferred */
+	spinlock_t		sk_lock;	/* protects sk_deferred and
+						 * sk_info_authunix */
 	struct list_head	sk_deferred;	/* deferred requests that need to
 						 * be revisted */
 	struct mutex		sk_mutex;	/* to serialize sending data */
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 9d2aa1a..9c7cb64 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -32,18 +32,51 @@
 static inline void pm_restore_console(void) {}
 #endif
 
+/**
+ * struct hibernation_ops - hibernation platform support
+ *
+ * The methods in this structure allow a platform to override the default
+ * mechanism of shutting down the machine during a hibernation transition.
+ *
+ * All three methods must be assigned.
+ *
+ * @prepare: prepare system for hibernation
+ * @enter: shut down system after state has been saved to disk
+ * @finish: finish/clean up after state has been reloaded
+ */
+struct hibernation_ops {
+	int (*prepare)(void);
+	int (*enter)(void);
+	void (*finish)(void);
+};
+
 #if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
 /* kernel/power/snapshot.c */
-extern void __init register_nosave_region(unsigned long, unsigned long);
+extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
+static inline void register_nosave_region(unsigned long b, unsigned long e)
+{
+	__register_nosave_region(b, e, 0);
+}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e)
+{
+	__register_nosave_region(b, e, 1);
+}
 extern int swsusp_page_is_forbidden(struct page *);
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
 extern unsigned long get_safe_page(gfp_t gfp_mask);
+
+extern void hibernation_set_ops(struct hibernation_ops *ops);
+extern int hibernate(void);
 #else
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
+
+static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
+static inline int hibernate(void) { return -ENOSYS; }
 #endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
 
 void save_processor_state(void);
diff --git a/include/linux/svga.h b/include/linux/svga.h
index e1cc552..13ad0b8 100644
--- a/include/linux/svga.h
+++ b/include/linux/svga.h
@@ -113,6 +113,8 @@
 void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit);
 void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor);
 int svga_get_tilemax(struct fb_info *info);
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+		   struct fb_var_screeninfo *var);
 
 int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node);
 int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 1912c6c..3139f44 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -576,6 +576,8 @@
 			       struct stat64 __user *statbuf, int flag);
 asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf,
 			       int bufsiz);
+asmlinkage long sys_utimensat(int dfd, char __user *filename,
+				struct timespec __user *utimes, int flags);
 asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename,
 				     struct compat_timeval __user *t);
 asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index 2a19698..6b3a318 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -63,6 +63,7 @@
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
+#define TIFM_CTRL_POWER_MASK      0x00000007
 
 #define TIFM_SOCK_STATE_OCCUPIED  0x00000008
 #define TIFM_SOCK_STATE_POWERED   0x00000080
diff --git a/include/linux/usb.h b/include/linux/usb.h
index cfbd2bb..94bd38a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -126,7 +126,7 @@
  * Each interface may have alternate settings.  The initial configuration
  * of a device sets altsetting 0, but the device driver can change
  * that setting using usb_set_interface().  Alternate settings are often
- * used to control the the use of periodic endpoints, such as by having
+ * used to control the use of periodic endpoints, such as by having
  * different endpoints use different amounts of reserved USB bandwidth.
  * All standards-conformant USB devices that use isochronous endpoints
  * will use them in non-default settings.
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index acb1f10..d9325cf 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -212,8 +212,6 @@
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
 void refresh_cpu_vm_stats(int);
-void refresh_vm_stats(void);
-
 #else /* CONFIG_SMP */
 
 /*
@@ -260,7 +258,6 @@
 #define mod_zone_page_state __mod_zone_page_state
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
-static inline void refresh_vm_stats(void) { }
 #endif
 
 #endif /* _LINUX_VMSTAT_H */
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index f16ba1e..d555f31 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -24,15 +24,13 @@
 struct work_struct {
 	atomic_long_t data;
 #define WORK_STRUCT_PENDING 0		/* T if work item pending execution */
-#define WORK_STRUCT_NOAUTOREL 1		/* F if work item automatically released on exec */
 #define WORK_STRUCT_FLAG_MASK (3UL)
 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
 	struct list_head entry;
 	work_func_t func;
 };
 
-#define WORK_DATA_INIT(autorelease) \
-	ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL)
+#define WORK_DATA_INIT()	ATOMIC_LONG_INIT(0)
 
 struct delayed_work {
 	struct work_struct work;
@@ -44,14 +42,8 @@
 };
 
 #define __WORK_INITIALIZER(n, f) {				\
-	.data = WORK_DATA_INIT(0),				\
-        .entry	= { &(n).entry, &(n).entry },			\
-	.func = (f),						\
-	}
-
-#define __WORK_INITIALIZER_NAR(n, f) {				\
-	.data = WORK_DATA_INIT(1),				\
-        .entry	= { &(n).entry, &(n).entry },			\
+	.data = WORK_DATA_INIT(),				\
+	.entry	= { &(n).entry, &(n).entry },			\
 	.func = (f),						\
 	}
 
@@ -60,23 +52,12 @@
 	.timer = TIMER_INITIALIZER(NULL, 0, 0),			\
 	}
 
-#define __DELAYED_WORK_INITIALIZER_NAR(n, f) {			\
-	.work = __WORK_INITIALIZER_NAR((n).work, (f)),		\
-	.timer = TIMER_INITIALIZER(NULL, 0, 0),			\
-	}
-
 #define DECLARE_WORK(n, f)					\
 	struct work_struct n = __WORK_INITIALIZER(n, f)
 
-#define DECLARE_WORK_NAR(n, f)					\
-	struct work_struct n = __WORK_INITIALIZER_NAR(n, f)
-
 #define DECLARE_DELAYED_WORK(n, f)				\
 	struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
 
-#define DECLARE_DELAYED_WORK_NAR(n, f)			\
-	struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f)
-
 /*
  * initialize a work item's function pointer
  */
@@ -95,16 +76,9 @@
  * assignment of the work data initializer allows the compiler
  * to generate better code.
  */
-#define INIT_WORK(_work, _func)					\
-	do {							\
-		(_work)->data = (atomic_long_t) WORK_DATA_INIT(0);	\
-		INIT_LIST_HEAD(&(_work)->entry);		\
-		PREPARE_WORK((_work), (_func));			\
-	} while (0)
-
-#define INIT_WORK_NAR(_work, _func)					\
+#define INIT_WORK(_work, _func)						\
 	do {								\
-		(_work)->data = (atomic_long_t) WORK_DATA_INIT(1);	\
+		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
 		INIT_LIST_HEAD(&(_work)->entry);			\
 		PREPARE_WORK((_work), (_func));				\
 	} while (0)
@@ -115,12 +89,6 @@
 		init_timer(&(_work)->timer);			\
 	} while (0)
 
-#define INIT_DELAYED_WORK_NAR(_work, _func)			\
-	do {							\
-		INIT_WORK_NAR(&(_work)->work, (_func));		\
-		init_timer(&(_work)->timer);			\
-	} while (0)
-
 #define INIT_DELAYED_WORK_DEFERRABLE(_work, _func)			\
 	do {							\
 		INIT_WORK(&(_work)->work, (_func));		\
@@ -143,24 +111,10 @@
 	work_pending(&(w)->work)
 
 /**
- * work_release - Release a work item under execution
- * @work: The work item to release
- *
- * This is used to release a work item that has been initialised with automatic
- * release mode disabled (WORK_STRUCT_NOAUTOREL is set).  This gives the work
- * function the opportunity to grab auxiliary data from the container of the
- * work_struct before clearing the pending bit as the work_struct may be
- * subject to deallocation the moment the pending bit is cleared.
- *
- * In such a case, this should be called in the work function after it has
- * fetched any data it may require from the containter of the work_struct.
- * After this function has been called, the work_struct may be scheduled for
- * further execution or it may be deallocated unless other precautions are
- * taken.
- *
- * This should also be used to release a delayed work item.
+ * work_clear_pending - for internal use only, mark a work item as not pending
+ * @work: The work item in question
  */
-#define work_release(work) \
+#define work_clear_pending(work) \
 	clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
 
 
@@ -174,27 +128,28 @@
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
 extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
-extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay));
+extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq,
+			struct delayed_work *work, unsigned long delay));
 extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
-	struct delayed_work *work, unsigned long delay);
+			struct delayed_work *work, unsigned long delay);
+
 extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq));
+extern void flush_scheduled_work(void);
 
 extern int FASTCALL(schedule_work(struct work_struct *work));
-extern int FASTCALL(run_scheduled_work(struct work_struct *work));
-extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay));
-
-extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay);
+extern int FASTCALL(schedule_delayed_work(struct delayed_work *work,
+					unsigned long delay));
+extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
+					unsigned long delay);
 extern int schedule_on_each_cpu(work_func_t func);
-extern void flush_scheduled_work(void);
 extern int current_is_keventd(void);
 extern int keventd_up(void);
 
 extern void init_workqueues(void);
-void cancel_rearming_delayed_work(struct delayed_work *work);
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *,
-				       struct delayed_work *);
 int execute_in_process_context(work_func_t fn, struct execute_work *);
 
+extern void cancel_work_sync(struct work_struct *work);
+
 /*
  * Kill off a pending schedule_delayed_work().  Note that the work callback
  * function may still be running on return from cancel_delayed_work(), unless
@@ -207,8 +162,18 @@
 
 	ret = del_timer(&work->timer);
 	if (ret)
-		work_release(&work->work);
+		work_clear_pending(&work->work);
 	return ret;
 }
 
+extern void cancel_rearming_delayed_work(struct delayed_work *work);
+
+/* Obsolete. use cancel_rearming_delayed_work() */
+static inline
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+					struct delayed_work *work)
+{
+	cancel_rearming_delayed_work(work);
+}
+
 #endif
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d56b292..bbd85cd 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1291,6 +1291,8 @@
 extern const struct ieee80211_channel *ieee80211_get_channel(struct
 							     ieee80211_device
 							     *ieee, u8 channel);
+extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
+				      u8 channel);
 
 /* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
diff --git a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h
index 7a209f6..0df5749 100644
--- a/include/net/irda/af_irda.h
+++ b/include/net/irda/af_irda.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 89fe534..36bee44 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h
index 2007c5a..fcc8964 100644
--- a/include/net/irda/iriap.h
+++ b/include/net/irda/iriap.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/iriap_event.h b/include/net/irda/iriap_event.h
index 4ca3d20..89747f0 100644
--- a/include/net/irda/iriap_event.h
+++ b/include/net/irda/iriap_event.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irias_object.h b/include/net/irda/irias_object.h
index c41196b..83f7808 100644
--- a/include/net/irda/irias_object.h
+++ b/include/net/irda/irias_object.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/irlan_client.h b/include/net/irda/irlan_client.h
index 736dabe..fa8455e 100644
--- a/include/net/irda/irlan_client.h
+++ b/include/net/irda/irlan_client.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 9592c37..73cacb3 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlan_eth.h b/include/net/irda/irlan_eth.h
index 9a9b361..0062347 100644
--- a/include/net/irda/irlan_eth.h
+++ b/include/net/irda/irlan_eth.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/irlan_event.h b/include/net/irda/irlan_event.h
index b9baac9..6d9539f 100644
--- a/include/net/irda/irlan_event.h
+++ b/include/net/irda/irlan_event.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlan_filter.h b/include/net/irda/irlan_filter.h
index 1720539..a5a2539 100644
--- a/include/net/irda/irlan_filter.h
+++ b/include/net/irda/irlan_filter.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/irlan_provider.h b/include/net/irda/irlan_provider.h
index ca51d5b..92f3b0e 100644
--- a/include/net/irda/irlan_provider.h
+++ b/include/net/irda/irlan_provider.h
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index e77eb88..f0248fb 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index e212b9b..3ffc1d0 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h
index 03c6f81..e03ae4a 100644
--- a/include/net/irda/irlmp_event.h
+++ b/include/net/irda/irlmp_event.h
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irlmp_frame.h b/include/net/irda/irlmp_frame.h
index c463f8b..1906eb7 100644
--- a/include/net/irda/irlmp_frame.h
+++ b/include/net/irda/irlmp_frame.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/irmod.h b/include/net/irda/irmod.h
index 72b446c..86f0dbb 100644
--- a/include/net/irda/irmod.h
+++ b/include/net/irda/irmod.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charg.
  *     
diff --git a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h
index 335b0ac..37f512b 100644
--- a/include/net/irda/irqueue.h
+++ b/include/net/irda/irqueue.h
@@ -21,7 +21,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h
index a899e58..cf80c1a 100644
--- a/include/net/irda/irttp.h
+++ b/include/net/irda/irttp.h
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/parameters.h b/include/net/irda/parameters.h
index 3a605d3..c0d9388 100644
--- a/include/net/irda/parameters.h
+++ b/include/net/irda/parameters.h
@@ -26,7 +26,7 @@
  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  *     MA 02111-1307 USA
  *
- *     Michel Dänzer <daenzer@debian.org>, 10/2001
+ *     Michel Dänzer <daenzer@debian.org>, 10/2001
  *     - simplify irda_pv_t to avoid endianness issues
  *     
  ********************************************************************/
diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h
index cb61568..cb2615c 100644
--- a/include/net/irda/timer.h
+++ b/include/net/irda/timer.h
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/net/irda/wrapper.h b/include/net/irda/wrapper.h
index 98768b3..2942ad6 100644
--- a/include/net/irda/wrapper.h
+++ b/include/net/irda/wrapper.h
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ad0182e..2e6bdc4 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -314,8 +314,7 @@
 	struct list_head  task_queue;
 	int               task_queue_size;
 
-	struct semaphore  queue_thread_sema;
-	int               queue_thread_kill;
+	struct task_struct *queue_thread;
 };
 
 struct sas_ha_event {
diff --git a/init/Kconfig b/init/Kconfig
index d0edf42..e63a017 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -143,9 +143,7 @@
 	  queues every message has a priority which decides about succession
 	  of receiving it by a process. If you want to compile and run
 	  programs written e.g. for Solaris with use of its POSIX message
-	  queues (functions mq_*) say Y here. To use this feature you will
-	  also need mqueue library, available from
-	  <http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
+	  queues (functions mq_*) say Y here.
 
 	  POSIX message queues are visible as a filesystem called 'mqueue'
 	  and can be mounted somewhere if you want to do filesystem
@@ -308,7 +306,7 @@
 	  releases.
 
 	  If enabled, this option will also move any device structures
-	  that belong to a class, back into the /sys/class heirachy, in
+	  that belong to a class, back into the /sys/class hierarchy, in
 	  order to support older versions of udev.
 
 	  If you are using a distro that was released in 2006 or later,
@@ -504,6 +502,15 @@
 	  on EMBEDDED systems.  /proc/vmstat will only show page counts
 	  if VM event counters are disabled.
 
+config SLUB_DEBUG
+	default y
+	bool "Enable SLUB debugging support" if EMBEDDED
+	help
+	  SLUB has extensive debug support features. Disabling these can
+	  result in significant savings in code size. This also disables
+	  SLUB sysfs support. /sys/slab will not exist and there will be
+	  no support for cache validation etc.
+
 choice
 	prompt "Choose SLAB allocator"
 	default SLAB
@@ -514,9 +521,9 @@
 	bool "SLAB"
 	help
 	  The regular slab allocator that is established and known to work
-	  well in all environments. It organizes chache hot objects in
+	  well in all environments. It organizes cache hot objects in
 	  per cpu and per node queues. SLAB is the default choice for
-	  slab allocator.
+	  a slab allocator.
 
 config SLUB
 	depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
@@ -526,21 +533,20 @@
 	   instead of managing queues of cached objects (SLAB approach).
 	   Per cpu caching is realized using slabs of objects instead
 	   of queues of objects. SLUB can use memory efficiently
-	   way and has enhanced diagnostics.
+	   and has enhanced diagnostics.
 
 config SLOB
 #
-#	SLOB cannot support SMP because SLAB_DESTROY_BY_RCU does not work
-#	properly.
+#	SLOB does not support SMP because SLAB_DESTROY_BY_RCU is unsupported
 #
 	depends on EMBEDDED && !SMP && !SPARSEMEM
 	bool "SLOB (Simple Allocator)"
 	help
 	   SLOB replaces the SLAB allocator with a drastically simpler
 	   allocator.  SLOB is more space efficient that SLAB but does not
-	   scale well (single lock for all operations) and is more susceptible
-	   to fragmentation. SLOB it is a great choice to reduce
-	   memory usage and code size for embedded systems.
+	   scale well (single lock for all operations) and is also highly
+	   susceptible to fragmentation. SLUB can accomplish a higher object
+	   density. It is usually better to use SLUB instead of SLOB.
 
 endchoice
 
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 3f57ed4..46fe407 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -7,6 +7,7 @@
 #include <linux/root_dev.h>
 #include <linux/security.h>
 #include <linux/delay.h>
+#include <linux/genhd.h>
 #include <linux/mount.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -308,17 +309,21 @@
 	        /*
 		 * Allow the user to distinguish between failed sys_open
 		 * and bad superblock on root device.
+		 * and give them a list of the available devices
 		 */
 #ifdef CONFIG_BLOCK
 		__bdevname(ROOT_DEV, b);
 #endif
 		printk("VFS: Cannot open root device \"%s\" or %s\n",
 				root_device_name, b);
-		printk("Please append a correct \"root=\" boot option\n");
+		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
+		printk_all_partitions();
 		panic("VFS: Unable to mount root fs on %s", b);
 	}
 
+	printk("List of all partitions:\n");
+	printk_all_partitions();
 	printk("No filesystem could mount root, tried: ");
 	for (p = fs_names; *p; p += strlen(p)+1)
 		printk(" %s", p);
diff --git a/init/main.c b/init/main.c
index c1537e0..e8d080c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -54,6 +54,7 @@
 #include <linux/lockdep.h>
 #include <linux/pid_namespace.h>
 #include <linux/device.h>
+#include <linux/kthread.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -425,8 +426,12 @@
 static void noinline rest_init(void)
 	__releases(kernel_lock)
 {
+	int pid;
+
 	kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
 	numa_default_policy();
+	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
+	kthreadd_task = find_task_by_pid(pid);
 	unlock_kernel();
 
 	/*
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
index 0b46a5d..c64ce9c 100644
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -23,7 +23,7 @@
 	  "explicit preemption points" to the kernel code. These new
 	  preemption points have been selected to reduce the maximum
 	  latency of rescheduling, providing faster application reactions,
-	  at the cost of slighly lower throughput.
+	  at the cost of slightly lower throughput.
 
 	  This allows reaction to interactive events by allowing a
 	  low priority process to voluntarily preempt itself even if it
@@ -43,7 +43,7 @@
 	  even if it is in kernel mode executing a system call and would
 	  otherwise not be about to reach a natural preemption point.
 	  This allows applications to run more 'smoothly' even when the
-	  system is under load, at the cost of slighly lower throughput
+	  system is under load, at the cost of slightly lower throughput
 	  and a slight runtime overhead to kernel code.
 
 	  Select this if you are building a kernel for a desktop or
diff --git a/kernel/configs.c b/kernel/configs.c
index 8fa1fb2..e84d3f9 100644
--- a/kernel/configs.c
+++ b/kernel/configs.c
@@ -61,18 +61,9 @@
 ikconfig_read_current(struct file *file, char __user *buf,
 		      size_t len, loff_t * offset)
 {
-	loff_t pos = *offset;
-	ssize_t count;
-
-	if (pos >= kernel_config_data_size)
-		return 0;
-
-	count = min(len, (size_t)(kernel_config_data_size - pos));
-	if (copy_to_user(buf, kernel_config_data + MAGIC_SIZE + pos, count))
-		return -EFAULT;
-
-	*offset += count;
-	return count;
+	return simple_read_from_buffer(buf, len, offset,
+				       kernel_config_data + MAGIC_SIZE,
+				       kernel_config_data_size);
 }
 
 static const struct file_operations ikconfig_file_ops = {
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 36e7084..208cf34 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -97,7 +97,7 @@
 		    (!cputime_eq(p->utime, cputime_zero) ||
 		     !cputime_eq(p->stime, cputime_zero)))
 			printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
-				(state = %ld, flags = %lx) \n",
+				(state = %ld, flags = %x) \n",
 				 p->comm, p->pid, cpu, p->state, p->flags);
 	}
 	write_unlock_irq(&tasklist_lock);
@@ -120,11 +120,13 @@
 }
 
 /* Requires cpu_add_remove_lock to be held */
-static int _cpu_down(unsigned int cpu)
+static int _cpu_down(unsigned int cpu, int tasks_frozen)
 {
-	int err;
+	int err, nr_calls = 0;
 	struct task_struct *p;
 	cpumask_t old_allowed, tmp;
+	void *hcpu = (void *)(long)cpu;
+	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 
 	if (num_online_cpus() == 1)
 		return -EBUSY;
@@ -132,12 +134,16 @@
 	if (!cpu_online(cpu))
 		return -EINVAL;
 
-	err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
-						(void *)(long)cpu);
+	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+	err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
+					hcpu, -1, &nr_calls);
 	if (err == NOTIFY_BAD) {
+		__raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+					  hcpu, nr_calls, NULL);
 		printk("%s: attempt to take down CPU %u failed\n",
 				__FUNCTION__, cpu);
-		return -EINVAL;
+		err = -EINVAL;
+		goto out_release;
 	}
 
 	/* Ensure that we are not runnable on dying cpu */
@@ -152,8 +158,8 @@
 
 	if (IS_ERR(p) || cpu_online(cpu)) {
 		/* CPU didn't die: tell everyone.  Can't complain. */
-		if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
-				(void *)(long)cpu) == NOTIFY_BAD)
+		if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+					    hcpu) == NOTIFY_BAD)
 			BUG();
 
 		if (IS_ERR(p)) {
@@ -170,13 +176,9 @@
 	/* This actually kills the CPU. */
 	__cpu_die(cpu);
 
-	/* Move it here so it can run. */
-	kthread_bind(p, get_cpu());
-	put_cpu();
-
 	/* CPU is completely dead: tell everyone.  Too late to complain. */
-	if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD,
-			(void *)(long)cpu) == NOTIFY_BAD)
+	if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
+				    hcpu) == NOTIFY_BAD)
 		BUG();
 
 	check_for_tasks(cpu);
@@ -185,6 +187,8 @@
 	err = kthread_stop(p);
 out_allowed:
 	set_cpus_allowed(current, old_allowed);
+out_release:
+	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
 	return err;
 }
 
@@ -196,7 +200,7 @@
 	if (cpu_hotplug_disabled)
 		err = -EBUSY;
 	else
-		err = _cpu_down(cpu);
+		err = _cpu_down(cpu, 0);
 
 	mutex_unlock(&cpu_add_remove_lock);
 	return err;
@@ -204,15 +208,18 @@
 #endif /*CONFIG_HOTPLUG_CPU*/
 
 /* Requires cpu_add_remove_lock to be held */
-static int __cpuinit _cpu_up(unsigned int cpu)
+static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
 {
-	int ret;
+	int ret, nr_calls = 0;
 	void *hcpu = (void *)(long)cpu;
+	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 
 	if (cpu_online(cpu) || !cpu_present(cpu))
 		return -EINVAL;
 
-	ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+	ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
+							-1, &nr_calls);
 	if (ret == NOTIFY_BAD) {
 		printk("%s: attempt to bring up CPU %u failed\n",
 				__FUNCTION__, cpu);
@@ -229,12 +236,13 @@
 	BUG_ON(!cpu_online(cpu));
 
 	/* Now call notifier in preparation. */
-	raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+	raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
 
 out_notify:
 	if (ret != 0)
-		raw_notifier_call_chain(&cpu_chain,
-				CPU_UP_CANCELED, hcpu);
+		__raw_notifier_call_chain(&cpu_chain,
+				CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
+	raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
 
 	return ret;
 }
@@ -247,19 +255,13 @@
 	if (cpu_hotplug_disabled)
 		err = -EBUSY;
 	else
-		err = _cpu_up(cpu);
+		err = _cpu_up(cpu, 0);
 
 	mutex_unlock(&cpu_add_remove_lock);
 	return err;
 }
 
 #ifdef CONFIG_SUSPEND_SMP
-/* Needed to prevent the microcode driver from requesting firmware in its CPU
- * hotplug notifier during the suspend/resume.
- */
-int suspend_cpu_hotplug;
-EXPORT_SYMBOL(suspend_cpu_hotplug);
-
 static cpumask_t frozen_cpus;
 
 int disable_nonboot_cpus(void)
@@ -267,7 +269,6 @@
 	int cpu, first_cpu, error = 0;
 
 	mutex_lock(&cpu_add_remove_lock);
-	suspend_cpu_hotplug = 1;
 	first_cpu = first_cpu(cpu_online_map);
 	/* We take down all of the non-boot CPUs in one shot to avoid races
 	 * with the userspace trying to use the CPU hotplug at the same time
@@ -277,7 +278,7 @@
 	for_each_online_cpu(cpu) {
 		if (cpu == first_cpu)
 			continue;
-		error = _cpu_down(cpu);
+		error = _cpu_down(cpu, 1);
 		if (!error) {
 			cpu_set(cpu, frozen_cpus);
 			printk("CPU%d is down\n", cpu);
@@ -294,7 +295,6 @@
 	} else {
 		printk(KERN_ERR "Non-boot CPUs are not disabled\n");
 	}
-	suspend_cpu_hotplug = 0;
 	mutex_unlock(&cpu_add_remove_lock);
 	return error;
 }
@@ -309,10 +309,9 @@
 	if (cpus_empty(frozen_cpus))
 		goto out;
 
-	suspend_cpu_hotplug = 1;
 	printk("Enabling non-boot CPUs ...\n");
 	for_each_cpu_mask(cpu, frozen_cpus) {
-		error = _cpu_up(cpu);
+		error = _cpu_up(cpu, 1);
 		if (!error) {
 			printk("CPU%d is up\n", cpu);
 			continue;
@@ -320,7 +319,6 @@
 		printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
 	}
 	cpus_clear(frozen_cpus);
-	suspend_cpu_hotplug = 0;
 out:
 	mutex_unlock(&cpu_add_remove_lock);
 }
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 88b416d..f57854b 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1772,12 +1772,7 @@
 {
 	struct ctr_struct *ctr = file->private_data;
 
-	if (*ppos + nbytes > ctr->bufsz)
-		nbytes = ctr->bufsz - *ppos;
-	if (copy_to_user(buf, ctr->buf + *ppos, nbytes))
-		return -EFAULT;
-	*ppos += nbytes;
-	return nbytes;
+	return simple_read_from_buffer(buf, nbytes, ppos, ctr->buf, ctr->bufsz);
 }
 
 static int cpuset_tasks_release(struct inode *unused_inode, struct file *file)
diff --git a/kernel/exit.c b/kernel/exit.c
index f5a7abb..b0c6f0c 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -26,6 +26,7 @@
 #include <linux/profile.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/kthread.h>
 #include <linux/mempolicy.h>
 #include <linux/taskstats_kern.h>
 #include <linux/delayacct.h>
@@ -254,26 +255,25 @@
 }
 
 /**
- * reparent_to_init - Reparent the calling kernel thread to the init task of the pid space that the thread belongs to.
+ * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd
  *
  * If a kernel thread is launched as a result of a system call, or if
- * it ever exits, it should generally reparent itself to init so that
- * it is correctly cleaned up on exit.
+ * it ever exits, it should generally reparent itself to kthreadd so it
+ * isn't in the way of other processes and is correctly cleaned up on exit.
  *
  * The various task state such as scheduling policy and priority may have
  * been inherited from a user process, so we reset them to sane values here.
  *
- * NOTE that reparent_to_init() gives the caller full capabilities.
+ * NOTE that reparent_to_kthreadd() gives the caller full capabilities.
  */
-static void reparent_to_init(void)
+static void reparent_to_kthreadd(void)
 {
 	write_lock_irq(&tasklist_lock);
 
 	ptrace_unlink(current);
 	/* Reparent to init */
 	remove_parent(current);
-	current->parent = child_reaper(current);
-	current->real_parent = child_reaper(current);
+	current->real_parent = current->parent = kthreadd_task;
 	add_parent(current);
 
 	/* Set the exit signal to SIGCHLD so we signal init on exit */
@@ -347,7 +347,7 @@
 		return -EINVAL;
 
 	spin_lock_irq(&current->sighand->siglock);
-	sigaddset(&current->blocked, sig);
+	current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 	return 0;
@@ -400,7 +400,7 @@
 	current->files = init_task.files;
 	atomic_inc(&current->files->count);
 
-	reparent_to_init();
+	reparent_to_kthreadd();
 }
 
 EXPORT_SYMBOL(daemonize);
diff --git a/kernel/fork.c b/kernel/fork.c
index a8dd75d..5dd3979 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -105,7 +105,7 @@
 
 void free_task(struct task_struct *tsk)
 {
-	free_thread_info(tsk->thread_info);
+	free_thread_info(tsk->stack);
 	rt_mutex_debug_task_free(tsk);
 	free_task_struct(tsk);
 }
@@ -175,7 +175,7 @@
 	}
 
 	*tsk = *orig;
-	tsk->thread_info = ti;
+	tsk->stack = ti;
 	setup_thread_stack(tsk, orig);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
diff --git a/kernel/futex.c b/kernel/futex.c
index 600bc9d..b7ce15c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -16,6 +16,9 @@
  *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
  *
+ *  PRIVATE futexes by Eric Dumazet
+ *  Copyright (C) 2007 Eric Dumazet <dada1@cosmosbay.com>
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
@@ -53,6 +56,12 @@
 
 #include "rtmutex_common.h"
 
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
@@ -81,12 +90,12 @@
  * we can wake only the relevant ones (hashed queues may be shared).
  *
  * A futex_q has a woken state, just like tasks have TASK_RUNNING.
- * It is considered woken when list_empty(&q->list) || q->lock_ptr == 0.
+ * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
  * The order of wakup is always to make the first condition true, then
  * wake up q->waiters, then make the second condition true.
  */
 struct futex_q {
-	struct list_head list;
+	struct plist_node list;
 	wait_queue_head_t waiters;
 
 	/* Which hash list lock to use: */
@@ -102,14 +111,20 @@
 	/* Optional priority inheritance state: */
 	struct futex_pi_state *pi_state;
 	struct task_struct *task;
+
+	/*
+	 * This waiter is used in case of requeue from a
+	 * normal futex to a PI-futex
+	 */
+	struct rt_mutex_waiter waiter;
 };
 
 /*
  * Split the global futex_lock into every hash list lock.
  */
 struct futex_hash_bucket {
-       spinlock_t              lock;
-       struct list_head       chain;
+	spinlock_t lock;
+	struct plist_head chain;
 };
 
 static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
@@ -138,19 +153,26 @@
 		&& key1->both.offset == key2->both.offset);
 }
 
-/*
- * Get parameters which are the keys for a futex.
+/**
+ * get_futex_key - Get parameters which are the keys for a futex.
+ * @uaddr: virtual address of the futex
+ * @shared: NULL for a PROCESS_PRIVATE futex,
+ *	&current->mm->mmap_sem for a PROCESS_SHARED futex
+ * @key: address where result is stored.
+ *
+ * Returns a negative error code or 0
+ * The key words are stored in *key on success.
  *
  * For shared mappings, it's (page->index, vma->vm_file->f_path.dentry->d_inode,
  * offset_within_page).  For private mappings, it's (uaddr, current->mm).
  * We can usually work out the index without swapping in the page.
  *
- * Returns: 0, or negative error code.
- * The key words are stored in *key on success.
- *
- * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
+ * fshared is NULL for PROCESS_PRIVATE futexes
+ * For other futexes, it points to &current->mm->mmap_sem and
+ * caller must have taken the reader lock. but NOT any spinlocks.
  */
-int get_futex_key(u32 __user *uaddr, union futex_key *key)
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *fshared,
+		  union futex_key *key)
 {
 	unsigned long address = (unsigned long)uaddr;
 	struct mm_struct *mm = current->mm;
@@ -162,11 +184,25 @@
 	 * The futex address must be "naturally" aligned.
 	 */
 	key->both.offset = address % PAGE_SIZE;
-	if (unlikely((key->both.offset % sizeof(u32)) != 0))
+	if (unlikely((address % sizeof(u32)) != 0))
 		return -EINVAL;
 	address -= key->both.offset;
 
 	/*
+	 * PROCESS_PRIVATE futexes are fast.
+	 * As the mm cannot disappear under us and the 'key' only needs
+	 * virtual address, we dont even have to find the underlying vma.
+	 * Note : We do have to check 'uaddr' is a valid user address,
+	 *        but access_ok() should be faster than find_vma()
+	 */
+	if (!fshared) {
+		if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
+			return -EFAULT;
+		key->private.mm = mm;
+		key->private.address = address;
+		return 0;
+	}
+	/*
 	 * The futex is hashed differently depending on whether
 	 * it's in a shared or private mapping.  So check vma first.
 	 */
@@ -180,6 +216,9 @@
 	if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
 		return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
 
+	/* Save the user address in the ley */
+	key->uaddr = uaddr;
+
 	/*
 	 * Private mappings are handled in a simple way.
 	 *
@@ -190,6 +229,7 @@
 	 * mappings of _writable_ handles.
 	 */
 	if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
+		key->both.offset |= FUT_OFF_MMSHARED; /* reference taken on mm */
 		key->private.mm = mm;
 		key->private.address = address;
 		return 0;
@@ -199,7 +239,7 @@
 	 * Linear file mappings are also simple.
 	 */
 	key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
-	key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
+	key->both.offset |= FUT_OFF_INODE; /* inode-based key. */
 	if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
 		key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
 				     + vma->vm_pgoff);
@@ -227,16 +267,18 @@
  * Take a reference to the resource addressed by a key.
  * Can be called while holding spinlocks.
  *
- * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
- * function, if it is called at all.  mmap_sem keeps key->shared.inode valid.
  */
 inline void get_futex_key_refs(union futex_key *key)
 {
-	if (key->both.ptr != 0) {
-		if (key->both.offset & 1)
+	if (key->both.ptr == 0)
+		return;
+	switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+		case FUT_OFF_INODE:
 			atomic_inc(&key->shared.inode->i_count);
-		else
+			break;
+		case FUT_OFF_MMSHARED:
 			atomic_inc(&key->private.mm->mm_count);
+			break;
 	}
 }
 EXPORT_SYMBOL_GPL(get_futex_key_refs);
@@ -247,11 +289,15 @@
  */
 void drop_futex_key_refs(union futex_key *key)
 {
-	if (key->both.ptr != 0) {
-		if (key->both.offset & 1)
+	if (key->both.ptr == 0)
+		return;
+	switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+		case FUT_OFF_INODE:
 			iput(key->shared.inode);
-		else
+			break;
+		case FUT_OFF_MMSHARED:
 			mmdrop(key->private.mm);
+			break;
 	}
 }
 EXPORT_SYMBOL_GPL(drop_futex_key_refs);
@@ -268,28 +314,38 @@
 }
 
 /*
- * Fault handling. Called with current->mm->mmap_sem held.
+ * Fault handling.
+ * if fshared is non NULL, current->mm->mmap_sem is already held
  */
-static int futex_handle_fault(unsigned long address, int attempt)
+static int futex_handle_fault(unsigned long address,
+			      struct rw_semaphore *fshared, int attempt)
 {
 	struct vm_area_struct * vma;
 	struct mm_struct *mm = current->mm;
+	int ret = -EFAULT;
 
-	if (attempt > 2 || !(vma = find_vma(mm, address)) ||
-	    vma->vm_start > address || !(vma->vm_flags & VM_WRITE))
-		return -EFAULT;
+	if (attempt > 2)
+		return ret;
 
-	switch (handle_mm_fault(mm, vma, address, 1)) {
-	case VM_FAULT_MINOR:
-		current->min_flt++;
-		break;
-	case VM_FAULT_MAJOR:
-		current->maj_flt++;
-		break;
-	default:
-		return -EFAULT;
+	if (!fshared)
+		down_read(&mm->mmap_sem);
+	vma = find_vma(mm, address);
+	if (vma && address >= vma->vm_start &&
+	    (vma->vm_flags & VM_WRITE)) {
+		switch (handle_mm_fault(mm, vma, address, 1)) {
+		case VM_FAULT_MINOR:
+			ret = 0;
+			current->min_flt++;
+			break;
+		case VM_FAULT_MAJOR:
+			ret = 0;
+			current->maj_flt++;
+			break;
+		}
 	}
-	return 0;
+	if (!fshared)
+		up_read(&mm->mmap_sem);
+	return ret;
 }
 
 /*
@@ -439,18 +495,19 @@
 }
 
 static int
-lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
+		union futex_key *key, struct futex_pi_state **ps)
 {
 	struct futex_pi_state *pi_state = NULL;
 	struct futex_q *this, *next;
-	struct list_head *head;
+	struct plist_head *head;
 	struct task_struct *p;
 	pid_t pid;
 
 	head = &hb->chain;
 
-	list_for_each_entry_safe(this, next, head, list) {
-		if (match_futex(&this->key, &me->key)) {
+	plist_for_each_entry_safe(this, next, head, list) {
+		if (match_futex(&this->key, key)) {
 			/*
 			 * Another waiter already exists - bump up
 			 * the refcount and return its pi_state:
@@ -465,7 +522,7 @@
 			WARN_ON(!atomic_read(&pi_state->refcount));
 
 			atomic_inc(&pi_state->refcount);
-			me->pi_state = pi_state;
+			*ps = pi_state;
 
 			return 0;
 		}
@@ -492,7 +549,7 @@
 	rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
 
 	/* Store the key for possible exit cleanups: */
-	pi_state->key = me->key;
+	pi_state->key = *key;
 
 	spin_lock_irq(&p->pi_lock);
 	WARN_ON(!list_empty(&pi_state->list));
@@ -502,7 +559,7 @@
 
 	put_task_struct(p);
 
-	me->pi_state = pi_state;
+	*ps = pi_state;
 
 	return 0;
 }
@@ -513,12 +570,12 @@
  */
 static void wake_futex(struct futex_q *q)
 {
-	list_del_init(&q->list);
+	plist_del(&q->list, &q->list.plist);
 	if (q->filp)
 		send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
 	/*
 	 * The lock in wake_up_all() is a crucial memory barrier after the
-	 * list_del_init() and also before assigning to q->lock_ptr.
+	 * plist_del() and also before assigning to q->lock_ptr.
 	 */
 	wake_up_all(&q->waiters);
 	/*
@@ -562,6 +619,8 @@
 	 */
 	if (!(uval & FUTEX_OWNER_DIED)) {
 		newval = FUTEX_WAITERS | new_owner->pid;
+		/* Keep the FUTEX_WAITER_REQUEUED flag if it was set */
+		newval |= (uval & FUTEX_WAITER_REQUEUED);
 
 		pagefault_disable();
 		curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -629,17 +688,19 @@
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(u32 __user *uaddr, int nr_wake)
+static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+		      int nr_wake)
 {
 	struct futex_hash_bucket *hb;
 	struct futex_q *this, *next;
-	struct list_head *head;
+	struct plist_head *head;
 	union futex_key key;
 	int ret;
 
-	down_read(&current->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr, &key);
+	ret = get_futex_key(uaddr, fshared, &key);
 	if (unlikely(ret != 0))
 		goto out;
 
@@ -647,7 +708,7 @@
 	spin_lock(&hb->lock);
 	head = &hb->chain;
 
-	list_for_each_entry_safe(this, next, head, list) {
+	plist_for_each_entry_safe(this, next, head, list) {
 		if (match_futex (&this->key, &key)) {
 			if (this->pi_state) {
 				ret = -EINVAL;
@@ -661,7 +722,261 @@
 
 	spin_unlock(&hb->lock);
 out:
-	up_read(&current->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
+	return ret;
+}
+
+/*
+ * Called from futex_requeue_pi.
+ * Set FUTEX_WAITERS and FUTEX_WAITER_REQUEUED flags on the
+ * PI-futex value; search its associated pi_state if an owner exist
+ * or create a new one without owner.
+ */
+static inline int
+lookup_pi_state_for_requeue(u32 __user *uaddr, struct futex_hash_bucket *hb,
+			    union futex_key *key,
+			    struct futex_pi_state **pi_state)
+{
+	u32 curval, uval, newval;
+
+retry:
+	/*
+	 * We can't handle a fault cleanly because we can't
+	 * release the locks here. Simply return the fault.
+	 */
+	if (get_futex_value_locked(&curval, uaddr))
+		return -EFAULT;
+
+	/* set the flags FUTEX_WAITERS and FUTEX_WAITER_REQUEUED */
+	if ((curval & (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED))
+	    != (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED)) {
+		/*
+		 * No waiters yet, we prepare the futex to have some waiters.
+		 */
+
+		uval = curval;
+		newval = uval | FUTEX_WAITERS | FUTEX_WAITER_REQUEUED;
+
+		pagefault_disable();
+		curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+		pagefault_enable();
+
+		if (unlikely(curval == -EFAULT))
+			return -EFAULT;
+		if (unlikely(curval != uval))
+			goto retry;
+	}
+
+	if (!(curval & FUTEX_TID_MASK)
+	    || lookup_pi_state(curval, hb, key, pi_state)) {
+		/* the futex has no owner (yet) or the lookup failed:
+		   allocate one pi_state without owner */
+
+		*pi_state = alloc_pi_state();
+
+		/* Already stores the key: */
+		(*pi_state)->key = *key;
+
+		/* init the mutex without owner */
+		__rt_mutex_init(&(*pi_state)->pi_mutex, NULL);
+	}
+
+	return 0;
+}
+
+/*
+ * Keep the first nr_wake waiter from futex1, wake up one,
+ * and requeue the next nr_requeue waiters following hashed on
+ * one physical page to another physical page (PI-futex uaddr2)
+ */
+static int futex_requeue_pi(u32 __user *uaddr1,
+			    struct rw_semaphore *fshared,
+			    u32 __user *uaddr2,
+			    int nr_wake, int nr_requeue, u32 *cmpval)
+{
+	union futex_key key1, key2;
+	struct futex_hash_bucket *hb1, *hb2;
+	struct plist_head *head1;
+	struct futex_q *this, *next;
+	struct futex_pi_state *pi_state2 = NULL;
+	struct rt_mutex_waiter *waiter, *top_waiter = NULL;
+	struct rt_mutex *lock2 = NULL;
+	int ret, drop_count = 0;
+
+	if (refill_pi_state_cache())
+		return -ENOMEM;
+
+retry:
+	/*
+	 * First take all the futex related locks:
+	 */
+	if (fshared)
+		down_read(fshared);
+
+	ret = get_futex_key(uaddr1, fshared, &key1);
+	if (unlikely(ret != 0))
+		goto out;
+	ret = get_futex_key(uaddr2, fshared, &key2);
+	if (unlikely(ret != 0))
+		goto out;
+
+	hb1 = hash_futex(&key1);
+	hb2 = hash_futex(&key2);
+
+	double_lock_hb(hb1, hb2);
+
+	if (likely(cmpval != NULL)) {
+		u32 curval;
+
+		ret = get_futex_value_locked(&curval, uaddr1);
+
+		if (unlikely(ret)) {
+			spin_unlock(&hb1->lock);
+			if (hb1 != hb2)
+				spin_unlock(&hb2->lock);
+
+			/*
+			 * If we would have faulted, release mmap_sem, fault
+			 * it in and start all over again.
+			 */
+			if (fshared)
+				up_read(fshared);
+
+			ret = get_user(curval, uaddr1);
+
+			if (!ret)
+				goto retry;
+
+			return ret;
+		}
+		if (curval != *cmpval) {
+			ret = -EAGAIN;
+			goto out_unlock;
+		}
+	}
+
+	head1 = &hb1->chain;
+	plist_for_each_entry_safe(this, next, head1, list) {
+		if (!match_futex (&this->key, &key1))
+			continue;
+		if (++ret <= nr_wake) {
+			wake_futex(this);
+		} else {
+			/*
+			 * FIRST: get and set the pi_state
+			 */
+			if (!pi_state2) {
+				int s;
+				/* do this only the first time we requeue someone */
+				s = lookup_pi_state_for_requeue(uaddr2, hb2,
+								&key2, &pi_state2);
+				if (s) {
+					ret = s;
+					goto out_unlock;
+				}
+
+				lock2 = &pi_state2->pi_mutex;
+				spin_lock(&lock2->wait_lock);
+
+				/* Save the top waiter of the wait_list */
+				if (rt_mutex_has_waiters(lock2))
+					top_waiter = rt_mutex_top_waiter(lock2);
+			} else
+				atomic_inc(&pi_state2->refcount);
+
+
+			this->pi_state = pi_state2;
+
+			/*
+			 * SECOND: requeue futex_q to the correct hashbucket
+			 */
+
+			/*
+			 * If key1 and key2 hash to the same bucket, no need to
+			 * requeue.
+			 */
+			if (likely(head1 != &hb2->chain)) {
+				plist_del(&this->list, &hb1->chain);
+				plist_add(&this->list, &hb2->chain);
+				this->lock_ptr = &hb2->lock;
+#ifdef CONFIG_DEBUG_PI_LIST
+				this->list.plist.lock = &hb2->lock;
+#endif
+			}
+			this->key = key2;
+			get_futex_key_refs(&key2);
+			drop_count++;
+
+
+			/*
+			 * THIRD: queue it to lock2
+			 */
+			spin_lock_irq(&this->task->pi_lock);
+			waiter = &this->waiter;
+			waiter->task = this->task;
+			waiter->lock = lock2;
+			plist_node_init(&waiter->list_entry, this->task->prio);
+			plist_node_init(&waiter->pi_list_entry, this->task->prio);
+			plist_add(&waiter->list_entry, &lock2->wait_list);
+			this->task->pi_blocked_on = waiter;
+			spin_unlock_irq(&this->task->pi_lock);
+
+			if (ret - nr_wake >= nr_requeue)
+				break;
+		}
+	}
+
+	/* If we've requeued some tasks and the top_waiter of the rt_mutex
+	   has changed, we must adjust the priority of the owner, if any */
+	if (drop_count) {
+		struct task_struct *owner = rt_mutex_owner(lock2);
+		if (owner &&
+		    (top_waiter != (waiter = rt_mutex_top_waiter(lock2)))) {
+			int chain_walk = 0;
+
+			spin_lock_irq(&owner->pi_lock);
+			if (top_waiter)
+				plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
+			else
+				/*
+				 * There was no waiters before the requeue,
+				 * the flag must be updated
+				 */
+				mark_rt_mutex_waiters(lock2);
+
+			plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+			__rt_mutex_adjust_prio(owner);
+			if (owner->pi_blocked_on) {
+				chain_walk = 1;
+				get_task_struct(owner);
+			}
+
+			spin_unlock_irq(&owner->pi_lock);
+			spin_unlock(&lock2->wait_lock);
+
+			if (chain_walk)
+				rt_mutex_adjust_prio_chain(owner, 0, lock2, NULL,
+							   current);
+		} else {
+			/* No owner or the top_waiter does not change */
+			mark_rt_mutex_waiters(lock2);
+			spin_unlock(&lock2->wait_lock);
+		}
+	}
+
+out_unlock:
+	spin_unlock(&hb1->lock);
+	if (hb1 != hb2)
+		spin_unlock(&hb2->lock);
+
+	/* drop_futex_key_refs() must be called outside the spinlocks. */
+	while (--drop_count >= 0)
+		drop_futex_key_refs(&key1);
+
+out:
+	if (fshared)
+		up_read(fshared);
 	return ret;
 }
 
@@ -670,22 +985,24 @@
  * to this virtual address:
  */
 static int
-futex_wake_op(u32 __user *uaddr1, u32 __user *uaddr2,
+futex_wake_op(u32 __user *uaddr1, struct rw_semaphore *fshared,
+	      u32 __user *uaddr2,
 	      int nr_wake, int nr_wake2, int op)
 {
 	union futex_key key1, key2;
 	struct futex_hash_bucket *hb1, *hb2;
-	struct list_head *head;
+	struct plist_head *head;
 	struct futex_q *this, *next;
 	int ret, op_ret, attempt = 0;
 
 retryfull:
-	down_read(&current->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr1, &key1);
+	ret = get_futex_key(uaddr1, fshared, &key1);
 	if (unlikely(ret != 0))
 		goto out;
-	ret = get_futex_key(uaddr2, &key2);
+	ret = get_futex_key(uaddr2, fshared, &key2);
 	if (unlikely(ret != 0))
 		goto out;
 
@@ -725,11 +1042,10 @@
 		 * still holding the mmap_sem.
 		 */
 		if (attempt++) {
-			if (futex_handle_fault((unsigned long)uaddr2,
-						attempt)) {
-				ret = -EFAULT;
+			ret = futex_handle_fault((unsigned long)uaddr2,
+						fshared, attempt);
+			if (ret)
 				goto out;
-			}
 			goto retry;
 		}
 
@@ -737,7 +1053,8 @@
 		 * If we would have faulted, release mmap_sem,
 		 * fault it in and start all over again.
 		 */
-		up_read(&current->mm->mmap_sem);
+		if (fshared)
+			up_read(fshared);
 
 		ret = get_user(dummy, uaddr2);
 		if (ret)
@@ -748,7 +1065,7 @@
 
 	head = &hb1->chain;
 
-	list_for_each_entry_safe(this, next, head, list) {
+	plist_for_each_entry_safe(this, next, head, list) {
 		if (match_futex (&this->key, &key1)) {
 			wake_futex(this);
 			if (++ret >= nr_wake)
@@ -760,7 +1077,7 @@
 		head = &hb2->chain;
 
 		op_ret = 0;
-		list_for_each_entry_safe(this, next, head, list) {
+		plist_for_each_entry_safe(this, next, head, list) {
 			if (match_futex (&this->key, &key2)) {
 				wake_futex(this);
 				if (++op_ret >= nr_wake2)
@@ -774,7 +1091,8 @@
 	if (hb1 != hb2)
 		spin_unlock(&hb2->lock);
 out:
-	up_read(&current->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 	return ret;
 }
 
@@ -782,22 +1100,24 @@
  * Requeue all waiters hashed on one physical page to another
  * physical page.
  */
-static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
+static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
+			 u32 __user *uaddr2,
 			 int nr_wake, int nr_requeue, u32 *cmpval)
 {
 	union futex_key key1, key2;
 	struct futex_hash_bucket *hb1, *hb2;
-	struct list_head *head1;
+	struct plist_head *head1;
 	struct futex_q *this, *next;
 	int ret, drop_count = 0;
 
  retry:
-	down_read(&current->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr1, &key1);
+	ret = get_futex_key(uaddr1, fshared, &key1);
 	if (unlikely(ret != 0))
 		goto out;
-	ret = get_futex_key(uaddr2, &key2);
+	ret = get_futex_key(uaddr2, fshared, &key2);
 	if (unlikely(ret != 0))
 		goto out;
 
@@ -820,7 +1140,8 @@
 			 * If we would have faulted, release mmap_sem, fault
 			 * it in and start all over again.
 			 */
-			up_read(&current->mm->mmap_sem);
+			if (fshared)
+				up_read(fshared);
 
 			ret = get_user(curval, uaddr1);
 
@@ -836,7 +1157,7 @@
 	}
 
 	head1 = &hb1->chain;
-	list_for_each_entry_safe(this, next, head1, list) {
+	plist_for_each_entry_safe(this, next, head1, list) {
 		if (!match_futex (&this->key, &key1))
 			continue;
 		if (++ret <= nr_wake) {
@@ -847,9 +1168,13 @@
 			 * requeue.
 			 */
 			if (likely(head1 != &hb2->chain)) {
-				list_move_tail(&this->list, &hb2->chain);
+				plist_del(&this->list, &hb1->chain);
+				plist_add(&this->list, &hb2->chain);
 				this->lock_ptr = &hb2->lock;
-			}
+#ifdef CONFIG_DEBUG_PI_LIST
+				this->list.plist.lock = &hb2->lock;
+#endif
+ 			}
 			this->key = key2;
 			get_futex_key_refs(&key2);
 			drop_count++;
@@ -869,7 +1194,8 @@
 		drop_futex_key_refs(&key1);
 
 out:
-	up_read(&current->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 	return ret;
 }
 
@@ -894,7 +1220,23 @@
 
 static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-	list_add_tail(&q->list, &hb->chain);
+	int prio;
+
+	/*
+	 * The priority used to register this element is
+	 * - either the real thread-priority for the real-time threads
+	 * (i.e. threads with a priority lower than MAX_RT_PRIO)
+	 * - or MAX_RT_PRIO for non-RT threads.
+	 * Thus, all RT-threads are woken first in priority order, and
+	 * the others are woken last, in FIFO order.
+	 */
+	prio = min(current->normal_prio, MAX_RT_PRIO);
+
+	plist_node_init(&q->list, prio);
+#ifdef CONFIG_DEBUG_PI_LIST
+	q->list.plist.lock = &hb->lock;
+#endif
+	plist_add(&q->list, &hb->chain);
 	q->task = current;
 	spin_unlock(&hb->lock);
 }
@@ -949,8 +1291,8 @@
 			spin_unlock(lock_ptr);
 			goto retry;
 		}
-		WARN_ON(list_empty(&q->list));
-		list_del(&q->list);
+		WARN_ON(plist_node_empty(&q->list));
+		plist_del(&q->list, &q->list.plist);
 
 		BUG_ON(q->pi_state);
 
@@ -964,39 +1306,104 @@
 
 /*
  * PI futexes can not be requeued and must remove themself from the
- * hash bucket. The hash bucket lock is held on entry and dropped here.
+ * hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
+ * and dropped here.
  */
-static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
+static void unqueue_me_pi(struct futex_q *q)
 {
-	WARN_ON(list_empty(&q->list));
-	list_del(&q->list);
+	WARN_ON(plist_node_empty(&q->list));
+	plist_del(&q->list, &q->list.plist);
 
 	BUG_ON(!q->pi_state);
 	free_pi_state(q->pi_state);
 	q->pi_state = NULL;
 
-	spin_unlock(&hb->lock);
+	spin_unlock(q->lock_ptr);
 
 	drop_futex_key_refs(&q->key);
 }
 
+/*
+ * Fixup the pi_state owner with current.
+ *
+ * The cur->mm semaphore must be  held, it is released at return of this
+ * function.
+ */
+static int fixup_pi_state_owner(u32 __user *uaddr, struct rw_semaphore *fshared,
+				struct futex_q *q,
+				struct futex_hash_bucket *hb,
+				struct task_struct *curr)
+{
+	u32 newtid = curr->pid | FUTEX_WAITERS;
+	struct futex_pi_state *pi_state = q->pi_state;
+	u32 uval, curval, newval;
+	int ret;
+
+	/* Owner died? */
+	if (pi_state->owner != NULL) {
+		spin_lock_irq(&pi_state->owner->pi_lock);
+		WARN_ON(list_empty(&pi_state->list));
+		list_del_init(&pi_state->list);
+		spin_unlock_irq(&pi_state->owner->pi_lock);
+	} else
+		newtid |= FUTEX_OWNER_DIED;
+
+	pi_state->owner = curr;
+
+	spin_lock_irq(&curr->pi_lock);
+	WARN_ON(!list_empty(&pi_state->list));
+	list_add(&pi_state->list, &curr->pi_state_list);
+	spin_unlock_irq(&curr->pi_lock);
+
+	/* Unqueue and drop the lock */
+	unqueue_me_pi(q);
+	if (fshared)
+		up_read(fshared);
+	/*
+	 * We own it, so we have to replace the pending owner
+	 * TID. This must be atomic as we have preserve the
+	 * owner died bit here.
+	 */
+	ret = get_user(uval, uaddr);
+	while (!ret) {
+		newval = (uval & FUTEX_OWNER_DIED) | newtid;
+		newval |= (uval & FUTEX_WAITER_REQUEUED);
+		curval = futex_atomic_cmpxchg_inatomic(uaddr,
+						       uval, newval);
+		if (curval == -EFAULT)
+ 			ret = -EFAULT;
+		if (curval == uval)
+			break;
+		uval = curval;
+	}
+	return ret;
+}
+
+/*
+ * In case we must use restart_block to restart a futex_wait,
+ * we encode in the 'arg3' shared capability
+ */
+#define ARG3_SHARED  1
+
 static long futex_wait_restart(struct restart_block *restart);
-static int futex_wait_abstime(u32 __user *uaddr, u32 val,
-			int timed, unsigned long abs_time)
+static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+		      u32 val, ktime_t *abs_time)
 {
 	struct task_struct *curr = current;
 	DECLARE_WAITQUEUE(wait, curr);
 	struct futex_hash_bucket *hb;
 	struct futex_q q;
-	unsigned long time_left = 0;
 	u32 uval;
 	int ret;
+	struct hrtimer_sleeper t, *to = NULL;
+	int rem = 0;
 
 	q.pi_state = NULL;
  retry:
-	down_read(&curr->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr, &q.key);
+	ret = get_futex_key(uaddr, fshared, &q.key);
 	if (unlikely(ret != 0))
 		goto out_release_sem;
 
@@ -1019,8 +1426,8 @@
 	 * a wakeup when *uaddr != val on entry to the syscall.  This is
 	 * rare, but normal.
 	 *
-	 * We hold the mmap semaphore, so the mapping cannot have changed
-	 * since we looked it up in get_futex_key.
+	 * for shared futexes, we hold the mmap semaphore, so the mapping
+	 * cannot have changed since we looked it up in get_futex_key.
 	 */
 	ret = get_futex_value_locked(&uval, uaddr);
 
@@ -1031,7 +1438,8 @@
 		 * If we would have faulted, release mmap_sem, fault it in and
 		 * start all over again.
 		 */
-		up_read(&curr->mm->mmap_sem);
+		if (fshared)
+			up_read(fshared);
 
 		ret = get_user(uval, uaddr);
 
@@ -1043,6 +1451,14 @@
 	if (uval != val)
 		goto out_unlock_release_sem;
 
+	/*
+	 * This rt_mutex_waiter structure is prepared here and will
+	 * be used only if this task is requeued from a normal futex to
+	 * a PI-futex with futex_requeue_pi.
+	 */
+	debug_rt_mutex_init_waiter(&q.waiter);
+	q.waiter.task = NULL;
+
 	/* Only actually queue if *uaddr contained val.  */
 	__queue_me(&q, hb);
 
@@ -1050,7 +1466,8 @@
 	 * Now the futex is queued and we have checked the data, we
 	 * don't want to hold mmap_sem while we sleep.
 	 */
-	up_read(&curr->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 
 	/*
 	 * There might have been scheduling since the queue_me(), as we
@@ -1065,23 +1482,33 @@
 	__set_current_state(TASK_INTERRUPTIBLE);
 	add_wait_queue(&q.waiters, &wait);
 	/*
-	 * !list_empty() is safe here without any lock.
+	 * !plist_node_empty() is safe here without any lock.
 	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
 	 */
-	time_left = 0;
-	if (likely(!list_empty(&q.list))) {
-		unsigned long rel_time;
+	if (likely(!plist_node_empty(&q.list))) {
+		if (!abs_time)
+			schedule();
+		else {
+			to = &t;
+			hrtimer_init(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+			hrtimer_init_sleeper(&t, current);
+			t.timer.expires = *abs_time;
 
-		if (timed) {
-			unsigned long now = jiffies;
-			if (time_after(now, abs_time))
-				rel_time = 0;
-			else
-				rel_time = abs_time - now;
-		} else
-			rel_time = MAX_SCHEDULE_TIMEOUT;
+			hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
 
-		time_left = schedule_timeout(rel_time);
+			/*
+			 * the timer could have already expired, in which
+			 * case current would be flagged for rescheduling.
+			 * Don't bother calling schedule.
+			 */
+			if (likely(t.task))
+				schedule();
+
+			hrtimer_cancel(&t.timer);
+
+			/* Flag if a timeout occured */
+			rem = (t.task == NULL);
+		}
 	}
 	__set_current_state(TASK_RUNNING);
 
@@ -1090,17 +1517,80 @@
 	 * we are the only user of it.
 	 */
 
+	if (q.pi_state) {
+		/*
+		 * We were woken but have been requeued on a PI-futex.
+		 * We have to complete the lock acquisition by taking
+		 * the rtmutex.
+		 */
+
+		struct rt_mutex *lock = &q.pi_state->pi_mutex;
+
+		spin_lock(&lock->wait_lock);
+		if (unlikely(q.waiter.task)) {
+			remove_waiter(lock, &q.waiter);
+		}
+		spin_unlock(&lock->wait_lock);
+
+		if (rem)
+			ret = -ETIMEDOUT;
+		else
+			ret = rt_mutex_timed_lock(lock, to, 1);
+
+		if (fshared)
+			down_read(fshared);
+		spin_lock(q.lock_ptr);
+
+		/*
+		 * Got the lock. We might not be the anticipated owner if we
+		 * did a lock-steal - fix up the PI-state in that case.
+		 */
+		if (!ret && q.pi_state->owner != curr) {
+			/*
+			 * We MUST play with the futex we were requeued on,
+			 * NOT the current futex.
+			 * We can retrieve it from the key of the pi_state
+			 */
+			uaddr = q.pi_state->key.uaddr;
+
+			/* mmap_sem and hash_bucket lock are unlocked at
+			   return of this function */
+			ret = fixup_pi_state_owner(uaddr, fshared,
+						   &q, hb, curr);
+		} else {
+			/*
+			 * Catch the rare case, where the lock was released
+			 * when we were on the way back before we locked
+			 * the hash bucket.
+			 */
+			if (ret && q.pi_state->owner == curr) {
+				if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+					ret = 0;
+			}
+			/* Unqueue and drop the lock */
+			unqueue_me_pi(&q);
+			if (fshared)
+				up_read(fshared);
+		}
+
+		debug_rt_mutex_free_waiter(&q.waiter);
+
+		return ret;
+	}
+
+	debug_rt_mutex_free_waiter(&q.waiter);
+
 	/* If we were woken (and unqueued), we succeeded, whatever. */
 	if (!unqueue_me(&q))
 		return 0;
-	if (time_left == 0)
+	if (rem)
 		return -ETIMEDOUT;
 
 	/*
 	 * We expect signal_pending(current), but another thread may
 	 * have handled it for us already.
 	 */
-	if (time_left == MAX_SCHEDULE_TIMEOUT)
+	if (!abs_time)
 		return -ERESTARTSYS;
 	else {
 		struct restart_block *restart;
@@ -1108,8 +1598,10 @@
 		restart->fn = futex_wait_restart;
 		restart->arg0 = (unsigned long)uaddr;
 		restart->arg1 = (unsigned long)val;
-		restart->arg2 = (unsigned long)timed;
-		restart->arg3 = abs_time;
+		restart->arg2 = (unsigned long)abs_time;
+		restart->arg3 = 0;
+		if (fshared)
+			restart->arg3 |= ARG3_SHARED;
 		return -ERESTART_RESTARTBLOCK;
 	}
 
@@ -1117,65 +1609,111 @@
 	queue_unlock(&q, hb);
 
  out_release_sem:
-	up_read(&curr->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 	return ret;
 }
 
-static int futex_wait(u32 __user *uaddr, u32 val, unsigned long rel_time)
-{
-	int timed = (rel_time != MAX_SCHEDULE_TIMEOUT);
-	return futex_wait_abstime(uaddr, val, timed, jiffies+rel_time);
-}
 
 static long futex_wait_restart(struct restart_block *restart)
 {
 	u32 __user *uaddr = (u32 __user *)restart->arg0;
 	u32 val = (u32)restart->arg1;
-	int timed = (int)restart->arg2;
-	unsigned long abs_time = restart->arg3;
+	ktime_t *abs_time = (ktime_t *)restart->arg2;
+	struct rw_semaphore *fshared = NULL;
 
 	restart->fn = do_no_restart_syscall;
-	return (long)futex_wait_abstime(uaddr, val, timed, abs_time);
+	if (restart->arg3 & ARG3_SHARED)
+		fshared = &current->mm->mmap_sem;
+	return (long)futex_wait(uaddr, fshared, val, abs_time);
 }
 
 
+static void set_pi_futex_owner(struct futex_hash_bucket *hb,
+			       union futex_key *key, struct task_struct *p)
+{
+	struct plist_head *head;
+	struct futex_q *this, *next;
+	struct futex_pi_state *pi_state = NULL;
+	struct rt_mutex *lock;
+
+	/* Search a waiter that should already exists */
+
+	head = &hb->chain;
+
+	plist_for_each_entry_safe(this, next, head, list) {
+		if (match_futex (&this->key, key)) {
+			pi_state = this->pi_state;
+			break;
+		}
+	}
+
+	BUG_ON(!pi_state);
+
+	/* set p as pi_state's owner */
+	lock = &pi_state->pi_mutex;
+
+	spin_lock(&lock->wait_lock);
+	spin_lock_irq(&p->pi_lock);
+
+	list_add(&pi_state->list, &p->pi_state_list);
+	pi_state->owner = p;
+
+
+	/* set p as pi_mutex's owner */
+	debug_rt_mutex_proxy_lock(lock, p);
+	WARN_ON(rt_mutex_owner(lock));
+	rt_mutex_set_owner(lock, p, 0);
+	rt_mutex_deadlock_account_lock(lock, p);
+
+	plist_add(&rt_mutex_top_waiter(lock)->pi_list_entry,
+		  &p->pi_waiters);
+	__rt_mutex_adjust_prio(p);
+
+	spin_unlock_irq(&p->pi_lock);
+	spin_unlock(&lock->wait_lock);
+}
+
 /*
  * Userspace tried a 0 -> TID atomic transition of the futex value
  * and failed. The kernel side here does the whole locking operation:
  * if there are waiters then it will block, it does PI, etc. (Due to
  * races the kernel might see a 0 value of the futex too.)
  */
-static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
-			 long nsec, int trylock)
+static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
+			 int detect, ktime_t *time, int trylock)
 {
 	struct hrtimer_sleeper timeout, *to = NULL;
 	struct task_struct *curr = current;
 	struct futex_hash_bucket *hb;
 	u32 uval, newval, curval;
 	struct futex_q q;
-	int ret, attempt = 0;
+	int ret, lock_held, attempt = 0;
 
 	if (refill_pi_state_cache())
 		return -ENOMEM;
 
-	if (sec != MAX_SCHEDULE_TIMEOUT) {
+	if (time) {
 		to = &timeout;
 		hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 		hrtimer_init_sleeper(to, current);
-		to->timer.expires = ktime_set(sec, nsec);
+		to->timer.expires = *time;
 	}
 
 	q.pi_state = NULL;
  retry:
-	down_read(&curr->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr, &q.key);
+	ret = get_futex_key(uaddr, fshared, &q.key);
 	if (unlikely(ret != 0))
 		goto out_release_sem;
 
 	hb = queue_lock(&q, -1, NULL);
 
  retry_locked:
+	lock_held = 0;
+
 	/*
 	 * To avoid races, we attempt to take the lock here again
 	 * (by doing a 0 -> TID atomic cmpxchg), while holding all
@@ -1194,7 +1732,16 @@
 	if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
 		if (!detect && 0)
 			force_sig(SIGKILL, current);
-		ret = -EDEADLK;
+		/*
+		 * Normally, this check is done in user space.
+		 * In case of requeue, the owner may attempt to lock this futex,
+		 * even if the ownership has already been given by the previous
+		 * waker.
+		 * In the usual case, this is a case of deadlock, but not in case
+		 * of REQUEUE_PI.
+		 */
+		if (!(curval & FUTEX_WAITER_REQUEUED))
+			ret = -EDEADLK;
 		goto out_unlock_release_sem;
 	}
 
@@ -1206,7 +1753,18 @@
 		goto out_unlock_release_sem;
 
 	uval = curval;
-	newval = uval | FUTEX_WAITERS;
+	/*
+	 * In case of a requeue, check if there already is an owner
+	 * If not, just take the futex.
+	 */
+	if ((curval & FUTEX_WAITER_REQUEUED) && !(curval & FUTEX_TID_MASK)) {
+		/* set current as futex owner */
+		newval = curval | current->pid;
+		lock_held = 1;
+	} else
+		/* Set the WAITERS flag, so the owner will know it has someone
+		   to wake at next unlock */
+		newval = curval | FUTEX_WAITERS;
 
 	pagefault_disable();
 	curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -1217,11 +1775,16 @@
 	if (unlikely(curval != uval))
 		goto retry_locked;
 
+	if (lock_held) {
+		set_pi_futex_owner(hb, &q.key, curr);
+		goto out_unlock_release_sem;
+	}
+
 	/*
 	 * We dont have the lock. Look up the PI state (or create it if
 	 * we are the first waiter):
 	 */
-	ret = lookup_pi_state(uval, hb, &q);
+	ret = lookup_pi_state(uval, hb, &q.key, &q.pi_state);
 
 	if (unlikely(ret)) {
 		/*
@@ -1263,7 +1826,8 @@
 	 * Now the futex is queued and we have checked the data, we
 	 * don't want to hold mmap_sem while we sleep.
 	 */
-	up_read(&curr->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 
 	WARN_ON(!q.pi_state);
 	/*
@@ -1277,52 +1841,18 @@
 		ret = ret ? 0 : -EWOULDBLOCK;
 	}
 
-	down_read(&curr->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 	spin_lock(q.lock_ptr);
 
 	/*
 	 * Got the lock. We might not be the anticipated owner if we
 	 * did a lock-steal - fix up the PI-state in that case.
 	 */
-	if (!ret && q.pi_state->owner != curr) {
-		u32 newtid = current->pid | FUTEX_WAITERS;
-
-		/* Owner died? */
-		if (q.pi_state->owner != NULL) {
-			spin_lock_irq(&q.pi_state->owner->pi_lock);
-			WARN_ON(list_empty(&q.pi_state->list));
-			list_del_init(&q.pi_state->list);
-			spin_unlock_irq(&q.pi_state->owner->pi_lock);
-		} else
-			newtid |= FUTEX_OWNER_DIED;
-
-		q.pi_state->owner = current;
-
-		spin_lock_irq(&current->pi_lock);
-		WARN_ON(!list_empty(&q.pi_state->list));
-		list_add(&q.pi_state->list, &current->pi_state_list);
-		spin_unlock_irq(&current->pi_lock);
-
-		/* Unqueue and drop the lock */
-		unqueue_me_pi(&q, hb);
-		up_read(&curr->mm->mmap_sem);
-		/*
-		 * We own it, so we have to replace the pending owner
-		 * TID. This must be atomic as we have preserve the
-		 * owner died bit here.
-		 */
-		ret = get_user(uval, uaddr);
-		while (!ret) {
-			newval = (uval & FUTEX_OWNER_DIED) | newtid;
-			curval = futex_atomic_cmpxchg_inatomic(uaddr,
-							       uval, newval);
-			if (curval == -EFAULT)
-				ret = -EFAULT;
-			if (curval == uval)
-				break;
-			uval = curval;
-		}
-	} else {
+	if (!ret && q.pi_state->owner != curr)
+		/* mmap_sem is unlocked at return of this function */
+		ret = fixup_pi_state_owner(uaddr, fshared, &q, hb, curr);
+	else {
 		/*
 		 * Catch the rare case, where the lock was released
 		 * when we were on the way back before we locked
@@ -1333,8 +1863,9 @@
 				ret = 0;
 		}
 		/* Unqueue and drop the lock */
-		unqueue_me_pi(&q, hb);
-		up_read(&curr->mm->mmap_sem);
+		unqueue_me_pi(&q);
+		if (fshared)
+			up_read(fshared);
 	}
 
 	if (!detect && ret == -EDEADLK && 0)
@@ -1346,7 +1877,8 @@
 	queue_unlock(&q, hb);
 
  out_release_sem:
-	up_read(&curr->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 	return ret;
 
  uaddr_faulted:
@@ -1357,15 +1889,16 @@
 	 * still holding the mmap_sem.
 	 */
 	if (attempt++) {
-		if (futex_handle_fault((unsigned long)uaddr, attempt)) {
-			ret = -EFAULT;
+		ret = futex_handle_fault((unsigned long)uaddr, fshared,
+					 attempt);
+		if (ret)
 			goto out_unlock_release_sem;
-		}
 		goto retry_locked;
 	}
 
 	queue_unlock(&q, hb);
-	up_read(&curr->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 
 	ret = get_user(uval, uaddr);
 	if (!ret && (uval != -EFAULT))
@@ -1379,12 +1912,12 @@
  * This is the in-kernel slowpath: we look up the PI state (if any),
  * and do the rt-mutex unlock.
  */
-static int futex_unlock_pi(u32 __user *uaddr)
+static int futex_unlock_pi(u32 __user *uaddr, struct rw_semaphore *fshared)
 {
 	struct futex_hash_bucket *hb;
 	struct futex_q *this, *next;
 	u32 uval;
-	struct list_head *head;
+	struct plist_head *head;
 	union futex_key key;
 	int ret, attempt = 0;
 
@@ -1399,9 +1932,10 @@
 	/*
 	 * First take all the futex related locks:
 	 */
-	down_read(&current->mm->mmap_sem);
+	if (fshared)
+		down_read(fshared);
 
-	ret = get_futex_key(uaddr, &key);
+	ret = get_futex_key(uaddr, fshared, &key);
 	if (unlikely(ret != 0))
 		goto out;
 
@@ -1435,7 +1969,7 @@
 	 */
 	head = &hb->chain;
 
-	list_for_each_entry_safe(this, next, head, list) {
+	plist_for_each_entry_safe(this, next, head, list) {
 		if (!match_futex (&this->key, &key))
 			continue;
 		ret = wake_futex_pi(uaddr, uval, this);
@@ -1460,7 +1994,8 @@
 out_unlock:
 	spin_unlock(&hb->lock);
 out:
-	up_read(&current->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 
 	return ret;
 
@@ -1472,15 +2007,16 @@
 	 * still holding the mmap_sem.
 	 */
 	if (attempt++) {
-		if (futex_handle_fault((unsigned long)uaddr, attempt)) {
-			ret = -EFAULT;
+		ret = futex_handle_fault((unsigned long)uaddr, fshared,
+					 attempt);
+		if (ret)
 			goto out_unlock;
-		}
 		goto retry_locked;
 	}
 
 	spin_unlock(&hb->lock);
-	up_read(&current->mm->mmap_sem);
+	if (fshared)
+		up_read(fshared);
 
 	ret = get_user(uval, uaddr);
 	if (!ret && (uval != -EFAULT))
@@ -1509,10 +2045,10 @@
 	poll_wait(filp, &q->waiters, wait);
 
 	/*
-	 * list_empty() is safe here without any lock.
+	 * plist_node_empty() is safe here without any lock.
 	 * q->lock_ptr != 0 is not safe, because of ordering against wakeup.
 	 */
-	if (list_empty(&q->list))
+	if (plist_node_empty(&q->list))
 		ret = POLLIN | POLLRDNORM;
 
 	return ret;
@@ -1532,6 +2068,7 @@
 	struct futex_q *q;
 	struct file *filp;
 	int ret, err;
+	struct rw_semaphore *fshared;
 	static unsigned long printk_interval;
 
 	if (printk_timed_ratelimit(&printk_interval, 60 * 60 * 1000)) {
@@ -1573,11 +2110,12 @@
 	}
 	q->pi_state = NULL;
 
-	down_read(&current->mm->mmap_sem);
-	err = get_futex_key(uaddr, &q->key);
+	fshared = &current->mm->mmap_sem;
+	down_read(fshared);
+	err = get_futex_key(uaddr, fshared, &q->key);
 
 	if (unlikely(err != 0)) {
-		up_read(&current->mm->mmap_sem);
+		up_read(fshared);
 		kfree(q);
 		goto error;
 	}
@@ -1589,7 +2127,7 @@
 	filp->private_data = q;
 
 	queue_me(q, ret, filp);
-	up_read(&current->mm->mmap_sem);
+	up_read(fshared);
 
 	/* Now we map fd to filp, so userspace can access it */
 	fd_install(ret, filp);
@@ -1702,6 +2240,8 @@
 		 * userspace.
 		 */
 		mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
+		/* Also keep the FUTEX_WAITER_REQUEUED flag if set */
+		mval |= (uval & FUTEX_WAITER_REQUEUED);
 		nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
 
 		if (nval == -EFAULT)
@@ -1716,7 +2256,7 @@
 		 */
 		if (!pi) {
 			if (uval & FUTEX_WAITERS)
-				futex_wake(uaddr, 1);
+				futex_wake(uaddr, &curr->mm->mmap_sem, 1);
 		}
 	}
 	return 0;
@@ -1772,7 +2312,8 @@
 		return;
 
 	if (pending)
-		handle_futex_death((void __user *)pending + futex_offset, curr, pip);
+		handle_futex_death((void __user *)pending + futex_offset,
+				   curr, pip);
 
 	while (entry != &head->list) {
 		/*
@@ -1798,39 +2339,47 @@
 	}
 }
 
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 		u32 __user *uaddr2, u32 val2, u32 val3)
 {
 	int ret;
+	int cmd = op & FUTEX_CMD_MASK;
+	struct rw_semaphore *fshared = NULL;
 
-	switch (op) {
+	if (!(op & FUTEX_PRIVATE_FLAG))
+		fshared = &current->mm->mmap_sem;
+
+	switch (cmd) {
 	case FUTEX_WAIT:
-		ret = futex_wait(uaddr, val, timeout);
+		ret = futex_wait(uaddr, fshared, val, timeout);
 		break;
 	case FUTEX_WAKE:
-		ret = futex_wake(uaddr, val);
+		ret = futex_wake(uaddr, fshared, val);
 		break;
 	case FUTEX_FD:
 		/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
 		ret = futex_fd(uaddr, val);
 		break;
 	case FUTEX_REQUEUE:
-		ret = futex_requeue(uaddr, uaddr2, val, val2, NULL);
+		ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL);
 		break;
 	case FUTEX_CMP_REQUEUE:
-		ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
+		ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3);
 		break;
 	case FUTEX_WAKE_OP:
-		ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
+		ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3);
 		break;
 	case FUTEX_LOCK_PI:
-		ret = futex_lock_pi(uaddr, val, timeout, val2, 0);
+		ret = futex_lock_pi(uaddr, fshared, val, timeout, 0);
 		break;
 	case FUTEX_UNLOCK_PI:
-		ret = futex_unlock_pi(uaddr);
+		ret = futex_unlock_pi(uaddr, fshared);
 		break;
 	case FUTEX_TRYLOCK_PI:
-		ret = futex_lock_pi(uaddr, 0, timeout, val2, 1);
+		ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
+		break;
+	case FUTEX_CMP_REQUEUE_PI:
+		ret = futex_requeue_pi(uaddr, fshared, uaddr2, val, val2, &val3);
 		break;
 	default:
 		ret = -ENOSYS;
@@ -1843,29 +2392,30 @@
 			  struct timespec __user *utime, u32 __user *uaddr2,
 			  u32 val3)
 {
-	struct timespec t;
-	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+	struct timespec ts;
+	ktime_t t, *tp = NULL;
 	u32 val2 = 0;
+	int cmd = op & FUTEX_CMD_MASK;
 
-	if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
-		if (copy_from_user(&t, utime, sizeof(t)) != 0)
+	if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+		if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
 			return -EFAULT;
-		if (!timespec_valid(&t))
+		if (!timespec_valid(&ts))
 			return -EINVAL;
-		if (op == FUTEX_WAIT)
-			timeout = timespec_to_jiffies(&t) + 1;
-		else {
-			timeout = t.tv_sec;
-			val2 = t.tv_nsec;
-		}
+
+		t = timespec_to_ktime(ts);
+		if (cmd == FUTEX_WAIT)
+			t = ktime_add(ktime_get(), t);
+		tp = &t;
 	}
 	/*
-	 * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
+	 * requeue parameter in 'utime' if cmd == FUTEX_REQUEUE.
 	 */
-	if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+	if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE
+	    || cmd == FUTEX_CMP_REQUEUE_PI)
 		val2 = (u32) (unsigned long) utime;
 
-	return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+	return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
 
 static int futexfs_get_sb(struct file_system_type *fs_type,
@@ -1895,7 +2445,7 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
-		INIT_LIST_HEAD(&futex_queues[i].chain);
+		plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock);
 		spin_lock_init(&futex_queues[i].lock);
 	}
 	return 0;
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 50f24ee..338a9b4 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -141,24 +141,24 @@
 		struct compat_timespec __user *utime, u32 __user *uaddr2,
 		u32 val3)
 {
-	struct timespec t;
-	unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+	struct timespec ts;
+	ktime_t t, *tp = NULL;
 	int val2 = 0;
 
 	if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
-		if (get_compat_timespec(&t, utime))
+		if (get_compat_timespec(&ts, utime))
 			return -EFAULT;
-		if (!timespec_valid(&t))
+		if (!timespec_valid(&ts))
 			return -EINVAL;
+
+		t = timespec_to_ktime(ts);
 		if (op == FUTEX_WAIT)
-			timeout = timespec_to_jiffies(&t) + 1;
-		else {
-			timeout = t.tv_sec;
-			val2 = t.tv_nsec;
-		}
+			t = ktime_add(ktime_get(), t);
+		tp = &t;
 	}
-	if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+	if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE
+	    || op == FUTEX_CMP_REQUEUE_PI)
 		val2 = (int) (unsigned long) utime;
 
-	return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+	return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index c9f4f04..23c03f4 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1411,11 +1411,13 @@
 	switch (action) {
 
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		init_hrtimers_cpu(cpu);
 		break;
 
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu);
 		migrate_hrtimers(cpu);
 		break;
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 32e1ab1..e391cbb 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -22,7 +22,6 @@
  * handle_bad_irq - handle spurious and unhandled irqs
  * @irq:       the interrupt number
  * @desc:      description of the interrupt
- * @regs:      pointer to a register structure
  *
  * Handles spurious and unhandled IRQ's. It also prints a debugmessage.
  */
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 49cc4b9..4d32eb0 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -135,7 +135,6 @@
 
 	/* Unblock all signals and set the session keyring. */
 	new_session = key_get(sub_info->ring);
-	flush_signals(current);
 	spin_lock_irq(&current->sighand->siglock);
 	old_session = __install_session_keyring(current, new_session);
 	flush_signal_handlers(current, 1);
@@ -186,14 +185,9 @@
 {
 	struct subprocess_info *sub_info = data;
 	pid_t pid;
-	struct k_sigaction sa;
 
 	/* Install a handler: if SIGCLD isn't handled sys_wait4 won't
 	 * populate the status, but will return -ECHILD. */
-	sa.sa.sa_handler = SIG_IGN;
-	sa.sa.sa_flags = 0;
-	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-	do_sigaction(SIGCHLD, &sa, NULL);
 	allow_signal(SIGCHLD);
 
 	pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 87c50cc..df8a8e8 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -1,7 +1,7 @@
 /* Kernel thread helper functions.
  *   Copyright (C) 2004 IBM Corporation, Rusty Russell.
  *
- * Creation is done via keventd, so that we get a clean environment
+ * Creation is done via kthreadd, so that we get a clean environment
  * even if we're invoked from userspace (think modprobe, hotplug cpu,
  * etc.).
  */
@@ -15,24 +15,22 @@
 #include <linux/mutex.h>
 #include <asm/semaphore.h>
 
-/*
- * We dont want to execute off keventd since it might
- * hold a semaphore our callers hold too:
- */
-static struct workqueue_struct *helper_wq;
+static DEFINE_SPINLOCK(kthread_create_lock);
+static LIST_HEAD(kthread_create_list);
+struct task_struct *kthreadd_task;
 
 struct kthread_create_info
 {
-	/* Information passed to kthread() from keventd. */
+	/* Information passed to kthread() from kthreadd. */
 	int (*threadfn)(void *data);
 	void *data;
 	struct completion started;
 
-	/* Result passed back to kthread_create() from keventd. */
+	/* Result passed back to kthread_create() from kthreadd. */
 	struct task_struct *result;
 	struct completion done;
 
-	struct work_struct work;
+	struct list_head list;
 };
 
 struct kthread_stop_info
@@ -60,42 +58,17 @@
 }
 EXPORT_SYMBOL(kthread_should_stop);
 
-static void kthread_exit_files(void)
-{
-	struct fs_struct *fs;
-	struct task_struct *tsk = current;
-
-	exit_fs(tsk);		/* current->fs->count--; */
-	fs = init_task.fs;
-	tsk->fs = fs;
-	atomic_inc(&fs->count);
- 	exit_files(tsk);
-	current->files = init_task.files;
-	atomic_inc(&tsk->files->count);
-}
-
 static int kthread(void *_create)
 {
 	struct kthread_create_info *create = _create;
 	int (*threadfn)(void *data);
 	void *data;
-	sigset_t blocked;
 	int ret = -EINTR;
 
-	kthread_exit_files();
-
-	/* Copy data: it's on keventd's stack */
+	/* Copy data: it's on kthread's stack */
 	threadfn = create->threadfn;
 	data = create->data;
 
-	/* Block and flush all signals (in case we're not from keventd). */
-	sigfillset(&blocked);
-	sigprocmask(SIG_BLOCK, &blocked, NULL);
-	flush_signals(current);
-
-	/* By default we can run anywhere, unlike keventd. */
-	set_cpus_allowed(current, CPU_MASK_ALL);
-
 	/* OK, tell user we're spawned, wait for stop or wakeup */
 	__set_current_state(TASK_INTERRUPTIBLE);
 	complete(&create->started);
@@ -112,11 +85,8 @@
 	return 0;
 }
 
-/* We are keventd: create a thread. */
-static void keventd_create_kthread(struct work_struct *work)
+static void create_kthread(struct kthread_create_info *create)
 {
-	struct kthread_create_info *create =
-		container_of(work, struct kthread_create_info, work);
 	int pid;
 
 	/* We want our own signal handler (we take no signals by default). */
@@ -162,17 +132,14 @@
 	create.data = data;
 	init_completion(&create.started);
 	init_completion(&create.done);
-	INIT_WORK(&create.work, keventd_create_kthread);
 
-	/*
-	 * The workqueue needs to start up first:
-	 */
-	if (!helper_wq)
-		create.work.func(&create.work);
-	else {
-		queue_work(helper_wq, &create.work);
-		wait_for_completion(&create.done);
-	}
+	spin_lock(&kthread_create_lock);
+	list_add_tail(&create.list, &kthread_create_list);
+	wake_up_process(kthreadd_task);
+	spin_unlock(&kthread_create_lock);
+
+	wait_for_completion(&create.done);
+
 	if (!IS_ERR(create.result)) {
 		va_list args;
 		va_start(args, namefmt);
@@ -180,7 +147,6 @@
 			  namefmt, args);
 		va_end(args);
 	}
-
 	return create.result;
 }
 EXPORT_SYMBOL(kthread_create);
@@ -245,12 +211,47 @@
 }
 EXPORT_SYMBOL(kthread_stop);
 
-static __init int helper_init(void)
+
+static __init void kthreadd_setup(void)
 {
-	helper_wq = create_singlethread_workqueue("kthread");
-	BUG_ON(!helper_wq);
+	struct task_struct *tsk = current;
+
+	set_task_comm(tsk, "kthreadd");
+
+	ignore_signals(tsk);
+
+	set_user_nice(tsk, -5);
+	set_cpus_allowed(tsk, CPU_MASK_ALL);
+}
+
+int kthreadd(void *unused)
+{
+	/* Setup a clean context for our children to inherit. */
+	kthreadd_setup();
+
+	current->flags |= PF_NOFREEZE;
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (list_empty(&kthread_create_list))
+			schedule();
+		__set_current_state(TASK_RUNNING);
+
+		spin_lock(&kthread_create_lock);
+		while (!list_empty(&kthread_create_list)) {
+			struct kthread_create_info *create;
+
+			create = list_entry(kthread_create_list.next,
+					    struct kthread_create_info, list);
+			list_del_init(&create->list);
+			spin_unlock(&kthread_create_lock);
+
+			create_kthread(create);
+
+			spin_lock(&kthread_create_lock);
+		}
+		spin_unlock(&kthread_create_lock);
+	}
 
 	return 0;
 }
-
-core_initcall(helper_init);
diff --git a/kernel/module.c b/kernel/module.c
index d36e454..9bd93de 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -96,9 +96,9 @@
 	mod->taints |= flag;
 }
 
-/* A thread that wants to hold a reference to a module only while it
- * is running can call ths to safely exit.
- * nfsd and lockd use this.
+/*
+ * A thread that wants to hold a reference to a module only while it
+ * is running can call this to safely exit.  nfsd and lockd use this.
  */
 void __module_put_and_exit(struct module *mod, long code)
 {
@@ -1199,7 +1199,7 @@
 	return 0;
 }
 
-/* Free a module, remove from lists, etc (must hold module mutex). */
+/* Free a module, remove from lists, etc (must hold module_mutex). */
 static void free_module(struct module *mod)
 {
 	/* Delete from various lists */
@@ -1246,7 +1246,7 @@
 
 /*
  * Ensure that an exported symbol [global namespace] does not already exist
- * in the Kernel or in some other modules exported symbol table.
+ * in the kernel or in some other module's exported symbol table.
  */
 static int verify_export_symbols(struct module *mod)
 {
diff --git a/kernel/mutex.c b/kernel/mutex.c
index e7cbbb8..303eab1 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -133,7 +133,7 @@
 
 	debug_mutex_lock_common(lock, &waiter);
 	mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
-	debug_mutex_add_waiter(lock, &waiter, task->thread_info);
+	debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
 	/* add waiting tasks to the end of the waitqueue (FIFO): */
 	list_add_tail(&waiter.list, &lock->wait_list);
@@ -159,7 +159,7 @@
 		 */
 		if (unlikely(state == TASK_INTERRUPTIBLE &&
 						signal_pending(task))) {
-			mutex_remove_waiter(lock, &waiter, task->thread_info);
+			mutex_remove_waiter(lock, &waiter, task_thread_info(task));
 			mutex_release(&lock->dep_map, 1, _RET_IP_);
 			spin_unlock_mutex(&lock->wait_lock, flags);
 
@@ -175,8 +175,8 @@
 	}
 
 	/* got the lock - rejoice! */
-	mutex_remove_waiter(lock, &waiter, task->thread_info);
-	debug_mutex_set_owner(lock, task->thread_info);
+	mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+	debug_mutex_set_owner(lock, task_thread_info(task));
 
 	/* set it to 0 if there are no waiters left: */
 	if (likely(list_empty(&lock->wait_list)))
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 0633137..b5f0543 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -30,30 +30,69 @@
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
 
+enum {
+	HIBERNATION_INVALID,
+	HIBERNATION_PLATFORM,
+	HIBERNATION_TEST,
+	HIBERNATION_TESTPROC,
+	HIBERNATION_SHUTDOWN,
+	HIBERNATION_REBOOT,
+	/* keep last */
+	__HIBERNATION_AFTER_LAST
+};
+#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
+#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
+
+static int hibernation_mode = HIBERNATION_SHUTDOWN;
+
+struct hibernation_ops *hibernation_ops;
+
+/**
+ * hibernation_set_ops - set the global hibernate operations
+ * @ops: the hibernation operations to use in subsequent hibernation transitions
+ */
+
+void hibernation_set_ops(struct hibernation_ops *ops)
+{
+	if (ops && !(ops->prepare && ops->enter && ops->finish)) {
+		WARN_ON(1);
+		return;
+	}
+	mutex_lock(&pm_mutex);
+	hibernation_ops = ops;
+	if (ops)
+		hibernation_mode = HIBERNATION_PLATFORM;
+	else if (hibernation_mode == HIBERNATION_PLATFORM)
+		hibernation_mode = HIBERNATION_SHUTDOWN;
+
+	mutex_unlock(&pm_mutex);
+}
+
+
 /**
  *	platform_prepare - prepare the machine for hibernation using the
  *	platform driver if so configured and return an error code if it fails
  */
 
-static inline int platform_prepare(void)
+static int platform_prepare(void)
 {
-	int error = 0;
-
-	switch (pm_disk_mode) {
-	case PM_DISK_TEST:
-	case PM_DISK_TESTPROC:
-	case PM_DISK_SHUTDOWN:
-	case PM_DISK_REBOOT:
-		break;
-	default:
-		if (pm_ops && pm_ops->prepare)
-			error = pm_ops->prepare(PM_SUSPEND_DISK);
-	}
-	return error;
+	return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
+		hibernation_ops->prepare() : 0;
 }
 
 /**
- *	power_down - Shut machine down for hibernate.
+ *	platform_finish - switch the machine to the normal mode of operation
+ *	using the platform driver (must be called after platform_prepare())
+ */
+
+static void platform_finish(void)
+{
+	if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
+		hibernation_ops->finish();
+}
+
+/**
+ *	power_down - Shut the machine down for hibernation.
  *
  *	Use the platform driver, if configured so; otherwise try
  *	to power off or reboot.
@@ -61,20 +100,20 @@
 
 static void power_down(void)
 {
-	switch (pm_disk_mode) {
-	case PM_DISK_TEST:
-	case PM_DISK_TESTPROC:
+	switch (hibernation_mode) {
+	case HIBERNATION_TEST:
+	case HIBERNATION_TESTPROC:
 		break;
-	case PM_DISK_SHUTDOWN:
+	case HIBERNATION_SHUTDOWN:
 		kernel_power_off();
 		break;
-	case PM_DISK_REBOOT:
+	case HIBERNATION_REBOOT:
 		kernel_restart(NULL);
 		break;
-	default:
-		if (pm_ops && pm_ops->enter) {
+	case HIBERNATION_PLATFORM:
+		if (hibernation_ops) {
 			kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-			pm_ops->enter(PM_SUSPEND_DISK);
+			hibernation_ops->enter();
 			break;
 		}
 	}
@@ -87,20 +126,6 @@
 	while(1);
 }
 
-static inline void platform_finish(void)
-{
-	switch (pm_disk_mode) {
-	case PM_DISK_TEST:
-	case PM_DISK_TESTPROC:
-	case PM_DISK_SHUTDOWN:
-	case PM_DISK_REBOOT:
-		break;
-	default:
-		if (pm_ops && pm_ops->finish)
-			pm_ops->finish(PM_SUSPEND_DISK);
-	}
-}
-
 static void unprepare_processes(void)
 {
 	thaw_processes();
@@ -120,13 +145,10 @@
 }
 
 /**
- *	pm_suspend_disk - The granpappy of hibernation power management.
- *
- *	If not, then call swsusp to do its thing, then figure out how
- *	to power down the system.
+ *	hibernate - The granpappy of the built-in hibernation management
  */
 
-int pm_suspend_disk(void)
+int hibernate(void)
 {
 	int error;
 
@@ -143,7 +165,8 @@
 	if (error)
 		goto Finish;
 
-	if (pm_disk_mode == PM_DISK_TESTPROC) {
+	mutex_lock(&pm_mutex);
+	if (hibernation_mode == HIBERNATION_TESTPROC) {
 		printk("swsusp debug: Waiting for 5 seconds.\n");
 		mdelay(5000);
 		goto Thaw;
@@ -168,7 +191,7 @@
 	if (error)
 		goto Enable_cpus;
 
-	if (pm_disk_mode == PM_DISK_TEST) {
+	if (hibernation_mode == HIBERNATION_TEST) {
 		printk("swsusp debug: Waiting for 5 seconds.\n");
 		mdelay(5000);
 		goto Enable_cpus;
@@ -205,6 +228,7 @@
 	device_resume();
 	resume_console();
  Thaw:
+	mutex_unlock(&pm_mutex);
 	unprepare_processes();
  Finish:
 	free_basic_memory_bitmaps();
@@ -220,7 +244,7 @@
  *	Called as a late_initcall (so all devices are discovered and
  *	initialized), we call swsusp to see if we have a saved image or not.
  *	If so, we quiesce devices, the restore the saved image. We will
- *	return above (in pm_suspend_disk() ) if everything goes well.
+ *	return above (in hibernate() ) if everything goes well.
  *	Otherwise, we fail gracefully and return to the normally
  *	scheduled program.
  *
@@ -315,25 +339,26 @@
 late_initcall(software_resume);
 
 
-static const char * const pm_disk_modes[] = {
-	[PM_DISK_PLATFORM]	= "platform",
-	[PM_DISK_SHUTDOWN]	= "shutdown",
-	[PM_DISK_REBOOT]	= "reboot",
-	[PM_DISK_TEST]		= "test",
-	[PM_DISK_TESTPROC]	= "testproc",
+static const char * const hibernation_modes[] = {
+	[HIBERNATION_PLATFORM]	= "platform",
+	[HIBERNATION_SHUTDOWN]	= "shutdown",
+	[HIBERNATION_REBOOT]	= "reboot",
+	[HIBERNATION_TEST]	= "test",
+	[HIBERNATION_TESTPROC]	= "testproc",
 };
 
 /**
- *	disk - Control suspend-to-disk mode
+ *	disk - Control hibernation mode
  *
  *	Suspend-to-disk can be handled in several ways. We have a few options
  *	for putting the system to sleep - using the platform driver (e.g. ACPI
- *	or other pm_ops), powering off the system or rebooting the system
- *	(for testing) as well as the two test modes.
+ *	or other hibernation_ops), powering off the system or rebooting the
+ *	system (for testing) as well as the two test modes.
  *
  *	The system can support 'platform', and that is known a priori (and
- *	encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
- *	as alternatives, as well as the test modes 'test' and 'testproc'.
+ *	encoded by the presence of hibernation_ops). However, the user may
+ *	choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
+ *	test modes, 'test' or 'testproc'.
  *
  *	show() will display what the mode is currently set to.
  *	store() will accept one of
@@ -345,7 +370,7 @@
  *	'testproc'
  *
  *	It will only change to 'platform' if the system
- *	supports it (as determined from pm_ops->pm_disk_mode).
+ *	supports it (as determined by having hibernation_ops).
  */
 
 static ssize_t disk_show(struct kset *kset, char *buf)
@@ -353,28 +378,25 @@
 	int i;
 	char *start = buf;
 
-	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
-		if (!pm_disk_modes[i])
+	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+		if (!hibernation_modes[i])
 			continue;
 		switch (i) {
-		case PM_DISK_SHUTDOWN:
-		case PM_DISK_REBOOT:
-		case PM_DISK_TEST:
-		case PM_DISK_TESTPROC:
+		case HIBERNATION_SHUTDOWN:
+		case HIBERNATION_REBOOT:
+		case HIBERNATION_TEST:
+		case HIBERNATION_TESTPROC:
 			break;
-		default:
-			if (pm_ops && pm_ops->enter &&
-			    (i == pm_ops->pm_disk_mode))
+		case HIBERNATION_PLATFORM:
+			if (hibernation_ops)
 				break;
 			/* not a valid mode, continue with loop */
 			continue;
 		}
-		if (i == pm_disk_mode)
-			buf += sprintf(buf, "[%s]", pm_disk_modes[i]);
+		if (i == hibernation_mode)
+			buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
 		else
-			buf += sprintf(buf, "%s", pm_disk_modes[i]);
-		if (i+1 != PM_DISK_MAX)
-			buf += sprintf(buf, " ");
+			buf += sprintf(buf, "%s ", hibernation_modes[i]);
 	}
 	buf += sprintf(buf, "\n");
 	return buf-start;
@@ -387,39 +409,38 @@
 	int i;
 	int len;
 	char *p;
-	suspend_disk_method_t mode = 0;
+	int mode = HIBERNATION_INVALID;
 
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 
 	mutex_lock(&pm_mutex);
-	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
-		if (!strncmp(buf, pm_disk_modes[i], len)) {
+	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+		if (!strncmp(buf, hibernation_modes[i], len)) {
 			mode = i;
 			break;
 		}
 	}
-	if (mode) {
+	if (mode != HIBERNATION_INVALID) {
 		switch (mode) {
-		case PM_DISK_SHUTDOWN:
-		case PM_DISK_REBOOT:
-		case PM_DISK_TEST:
-		case PM_DISK_TESTPROC:
-			pm_disk_mode = mode;
+		case HIBERNATION_SHUTDOWN:
+		case HIBERNATION_REBOOT:
+		case HIBERNATION_TEST:
+		case HIBERNATION_TESTPROC:
+			hibernation_mode = mode;
 			break;
-		default:
-			if (pm_ops && pm_ops->enter &&
-			    (mode == pm_ops->pm_disk_mode))
-				pm_disk_mode = mode;
+		case HIBERNATION_PLATFORM:
+			if (hibernation_ops)
+				hibernation_mode = mode;
 			else
 				error = -EINVAL;
 		}
-	} else {
+	} else
 		error = -EINVAL;
-	}
 
-	pr_debug("PM: suspend-to-disk mode set to '%s'\n",
-		 pm_disk_modes[mode]);
+	if (!error)
+		pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+			 hibernation_modes[mode]);
 	mutex_unlock(&pm_mutex);
 	return error ? error : n;
 }
diff --git a/kernel/power/main.c b/kernel/power/main.c
index f6dda68..40d56a3 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,6 @@
 DEFINE_MUTEX(pm_mutex);
 
 struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
 
 /**
  *	pm_set_ops - Set the global power method table. 
@@ -41,10 +40,6 @@
 {
 	mutex_lock(&pm_mutex);
 	pm_ops = ops;
-	if (ops && ops->pm_disk_mode != PM_DISK_INVALID) {
-		pm_disk_mode = ops->pm_disk_mode;
-	} else
-		pm_disk_mode = PM_DISK_SHUTDOWN;
 	mutex_unlock(&pm_mutex);
 }
 
@@ -184,24 +179,12 @@
 static const char * const pm_states[PM_SUSPEND_MAX] = {
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
-	[PM_SUSPEND_DISK]	= "disk",
 };
 
 static inline int valid_state(suspend_state_t state)
 {
-	/* Suspend-to-disk does not really need low-level support.
-	 * It can work with shutdown/reboot if needed. If it isn't
-	 * configured, then it cannot be supported.
-	 */
-	if (state == PM_SUSPEND_DISK)
-#ifdef CONFIG_SOFTWARE_SUSPEND
-		return 1;
-#else
-		return 0;
-#endif
-
-	/* all other states need lowlevel support and need to be
-	 * valid to the lowlevel implementation, no valid callback
+	/* All states need lowlevel support and need to be valid
+	 * to the lowlevel implementation, no valid callback
 	 * implies that none are valid. */
 	if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
 		return 0;
@@ -229,11 +212,6 @@
 	if (!mutex_trylock(&pm_mutex))
 		return -EBUSY;
 
-	if (state == PM_SUSPEND_DISK) {
-		error = pm_suspend_disk();
-		goto Unlock;
-	}
-
 	pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
 	if ((error = suspend_prepare(state)))
 		goto Unlock;
@@ -251,7 +229,7 @@
 
 /**
  *	pm_suspend - Externally visible function for suspending system.
- *	@state:		Enumarted value of state to enter.
+ *	@state:		Enumerated value of state to enter.
  *
  *	Determine whether or not value is within range, get state 
  *	structure, and enter (above).
@@ -289,7 +267,13 @@
 		if (pm_states[i] && valid_state(i))
 			s += sprintf(s,"%s ", pm_states[i]);
 	}
-	s += sprintf(s,"\n");
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	s += sprintf(s, "%s\n", "disk");
+#else
+	if (s != buf)
+		/* convert the last space to a newline */
+		*(s-1) = '\n';
+#endif
 	return (s - buf);
 }
 
@@ -304,6 +288,12 @@
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 
+	/* First, check if we are requested to hibernate */
+	if (!strncmp(buf, "disk", len)) {
+		error = hibernate();
+		return error ? error : n;
+	}
+
 	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
 		if (*s && !strncmp(buf, *s, len))
 			break;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 34b4354..5138148 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -25,12 +25,7 @@
  */
 #define SPARE_PAGES	((1024 * 1024) >> PAGE_SHIFT)
 
-extern int pm_suspend_disk(void);
-#else
-static inline int pm_suspend_disk(void)
-{
-	return -EPERM;
-}
+extern struct hibernation_ops *hibernation_ops;
 #endif
 
 extern int pfn_is_nosave(unsigned long);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index b703977..a3b7854 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -607,7 +607,8 @@
  */
 
 void __init
-register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
+__register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+			 int use_kmalloc)
 {
 	struct nosave_region *region;
 
@@ -623,8 +624,13 @@
 			goto Report;
 		}
 	}
-	/* This allocation cannot fail */
-	region = alloc_bootmem_low(sizeof(struct nosave_region));
+	if (use_kmalloc) {
+		/* during init, this shouldn't fail */
+		region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
+		BUG_ON(!region);
+	} else
+		/* This allocation cannot fail */
+		region = alloc_bootmem_low(sizeof(struct nosave_region));
 	region->start_pfn = start_pfn;
 	region->end_pfn = end_pfn;
 	list_add_tail(&region->list, &nosave_regions);
@@ -1227,7 +1233,7 @@
 	nr_copy_pages = nr_pages;
 	nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
 
-	printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages);
+	printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
 
 	return 0;
 }
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 040560d..24d7d78 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -130,16 +130,16 @@
 {
 	int error = 0;
 
-	if (pm_ops && pm_ops->prepare)
-		error = pm_ops->prepare(PM_SUSPEND_DISK);
+	if (hibernation_ops)
+		error = hibernation_ops->prepare();
 
 	return error;
 }
 
 static inline void platform_finish(void)
 {
-	if (pm_ops && pm_ops->finish)
-		pm_ops->finish(PM_SUSPEND_DISK);
+	if (hibernation_ops)
+		hibernation_ops->finish();
 }
 
 static inline int snapshot_suspend(int platform_suspend)
@@ -384,7 +384,7 @@
 		switch (arg) {
 
 		case PMOPS_PREPARE:
-			if (pm_ops && pm_ops->enter) {
+			if (hibernation_ops) {
 				data->platform_suspend = 1;
 				error = 0;
 			} else {
@@ -395,8 +395,7 @@
 		case PMOPS_ENTER:
 			if (data->platform_suspend) {
 				kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-				error = pm_ops->enter(PM_SUSPEND_DISK);
-				error = 0;
+				error = hibernation_ops->enter();
 			}
 			break;
 
diff --git a/kernel/profile.c b/kernel/profile.c
index 9bfadb2..cc91b9b 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -340,6 +340,7 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		node = cpu_to_node(cpu);
 		per_cpu(cpu_profile_flip, cpu) = 0;
 		if (!per_cpu(cpu_profile_hits, cpu)[1]) {
@@ -365,10 +366,13 @@
 		__free_page(page);
 		return NOTIFY_BAD;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		cpu_set(cpu, prof_cpu_mask);
 		break;
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		cpu_clear(cpu, prof_cpu_mask);
 		if (per_cpu(cpu_profile_hits, cpu)[0]) {
 			page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 3554b76..2c2dd84 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -558,9 +558,11 @@
 	long cpu = (long)hcpu;
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		rcu_online_cpu(cpu);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		rcu_offline_cpu(cpu);
 		break;
 	default:
diff --git a/kernel/relay.c b/kernel/relay.c
index 577f251..4311101 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -310,16 +310,13 @@
 
 /**
  *	wakeup_readers - wake up readers waiting on a channel
- *	@work: work struct that contains the the channel buffer
+ *	@data: contains the channel buffer
  *
- *	This is the work function used to defer reader waking.  The
- *	reason waking is deferred is that calling directly from write
- *	causes problems if you're writing from say the scheduler.
+ *	This is the timer function used to defer reader waking.
  */
-static void wakeup_readers(struct work_struct *work)
+static void wakeup_readers(unsigned long data)
 {
-	struct rchan_buf *buf =
-		container_of(work, struct rchan_buf, wake_readers.work);
+	struct rchan_buf *buf = (struct rchan_buf *)data;
 	wake_up_interruptible(&buf->read_wait);
 }
 
@@ -337,11 +334,9 @@
 	if (init) {
 		init_waitqueue_head(&buf->read_wait);
 		kref_init(&buf->kref);
-		INIT_DELAYED_WORK(&buf->wake_readers, NULL);
-	} else {
-		cancel_delayed_work(&buf->wake_readers);
-		flush_scheduled_work();
-	}
+		setup_timer(&buf->timer, wakeup_readers, (unsigned long)buf);
+	} else
+		del_timer_sync(&buf->timer);
 
 	buf->subbufs_produced = 0;
 	buf->subbufs_consumed = 0;
@@ -447,8 +442,7 @@
 static void relay_close_buf(struct rchan_buf *buf)
 {
 	buf->finalized = 1;
-	cancel_delayed_work(&buf->wake_readers);
-	flush_scheduled_work();
+	del_timer_sync(&buf->timer);
 	kref_put(&buf->kref, relay_remove_buf);
 }
 
@@ -490,6 +484,7 @@
 
 	switch(action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		mutex_lock(&relay_channels_mutex);
 		list_for_each_entry(chan, &relay_channels, list) {
 			if (chan->buf[hotcpu])
@@ -506,6 +501,7 @@
 		mutex_unlock(&relay_channels_mutex);
 		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		/* No need to flush the cpu : will be flushed upon
 		 * final relay_flush() call. */
 		break;
@@ -608,11 +604,14 @@
 		buf->dentry->d_inode->i_size += buf->chan->subbuf_size -
 			buf->padding[old_subbuf];
 		smp_mb();
-		if (waitqueue_active(&buf->read_wait)) {
-			PREPARE_DELAYED_WORK(&buf->wake_readers,
-					     wakeup_readers);
-			schedule_delayed_work(&buf->wake_readers, 1);
-		}
+		if (waitqueue_active(&buf->read_wait))
+			/*
+			 * Calling wake_up_interruptible() from here
+			 * will deadlock if we happen to be logging
+			 * from the scheduler (trying to re-grab
+			 * rq->lock), so defer it.
+			 */
+			__mod_timer(&buf->timer, jiffies + 1);
 	}
 
 	old = buf->data;
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
index 180978c..12879f6 100644
--- a/kernel/rtmutex.c
+++ b/kernel/rtmutex.c
@@ -56,7 +56,7 @@
  * state.
  */
 
-static void
+void
 rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
 		   unsigned long mask)
 {
@@ -81,29 +81,6 @@
 }
 
 /*
- * We can speed up the acquire/release, if the architecture
- * supports cmpxchg and if there's no debugging state to be set up
- */
-#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
-# define rt_mutex_cmpxchg(l,c,n)	(cmpxchg(&l->owner, c, n) == c)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-	unsigned long owner, *p = (unsigned long *) &lock->owner;
-
-	do {
-		owner = *p;
-	} while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
-}
-#else
-# define rt_mutex_cmpxchg(l,c,n)	(0)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-	lock->owner = (struct task_struct *)
-			((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
-}
-#endif
-
-/*
  * Calculate task priority from the waiter list priority
  *
  * Return task->normal_prio when the waiter list is empty or when
@@ -123,7 +100,7 @@
  *
  * This can be both boosting and unboosting. task->pi_lock must be held.
  */
-static void __rt_mutex_adjust_prio(struct task_struct *task)
+void __rt_mutex_adjust_prio(struct task_struct *task)
 {
 	int prio = rt_mutex_getprio(task);
 
@@ -159,11 +136,11 @@
  * Decreases task's usage by one - may thus free the task.
  * Returns 0 or -EDEADLK.
  */
-static int rt_mutex_adjust_prio_chain(struct task_struct *task,
-				      int deadlock_detect,
-				      struct rt_mutex *orig_lock,
-				      struct rt_mutex_waiter *orig_waiter,
-				      struct task_struct *top_task)
+int rt_mutex_adjust_prio_chain(struct task_struct *task,
+			       int deadlock_detect,
+			       struct rt_mutex *orig_lock,
+			       struct rt_mutex_waiter *orig_waiter,
+			       struct task_struct *top_task)
 {
 	struct rt_mutex *lock;
 	struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
@@ -524,8 +501,8 @@
  *
  * Must be called with lock->wait_lock held
  */
-static void remove_waiter(struct rt_mutex *lock,
-			  struct rt_mutex_waiter *waiter)
+void remove_waiter(struct rt_mutex *lock,
+		   struct rt_mutex_waiter *waiter)
 {
 	int first = (waiter == rt_mutex_top_waiter(lock));
 	struct task_struct *owner = rt_mutex_owner(lock);
diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h
index 9c75856..242ec7e 100644
--- a/kernel/rtmutex_common.h
+++ b/kernel/rtmutex_common.h
@@ -113,6 +113,29 @@
 }
 
 /*
+ * We can speed up the acquire/release, if the architecture
+ * supports cmpxchg and if there's no debugging state to be set up
+ */
+#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+# define rt_mutex_cmpxchg(l,c,n)	(cmpxchg(&l->owner, c, n) == c)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+	unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+	do {
+		owner = *p;
+	} while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
+}
+#else
+# define rt_mutex_cmpxchg(l,c,n)	(0)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+	lock->owner = (struct task_struct *)
+			((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
+}
+#endif
+
+/*
  * PI-futex support (proxy locking functions, etc.):
  */
 extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
@@ -120,4 +143,15 @@
 				       struct task_struct *proxy_owner);
 extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
 				  struct task_struct *proxy_owner);
+
+extern void rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
+			       unsigned long mask);
+extern void __rt_mutex_adjust_prio(struct task_struct *task);
+extern int rt_mutex_adjust_prio_chain(struct task_struct *task,
+				      int deadlock_detect,
+				      struct rt_mutex *orig_lock,
+				      struct rt_mutex_waiter *orig_waiter,
+				      struct task_struct *top_task);
+extern void remove_waiter(struct rt_mutex *lock,
+			  struct rt_mutex_waiter *waiter);
 #endif
diff --git a/kernel/sched.c b/kernel/sched.c
index a3a0408..799d23b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -169,7 +169,7 @@
 		(MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1))
 
 #define TASK_PREEMPTS_CURR(p, rq) \
-	(((p)->prio < (rq)->curr->prio) && ((p)->array == (rq)->active))
+	((p)->prio < (rq)->curr->prio)
 
 #define SCALE_PRIO(x, prio) \
 	max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
@@ -305,6 +305,7 @@
 };
 
 static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_MUTEX(sched_hotcpu_mutex);
 
 static inline int cpu_of(struct rq *rq)
 {
@@ -4076,13 +4077,13 @@
 	struct prio_array *array;
 	unsigned long flags;
 	struct rq *rq;
-	int delta;
+	int oldprio;
 
 	BUG_ON(prio < 0 || prio > MAX_PRIO);
 
 	rq = task_rq_lock(p, &flags);
 
-	delta = prio - p->prio;
+	oldprio = p->prio;
 	array = p->array;
 	if (array)
 		dequeue_task(p, array);
@@ -4098,11 +4099,13 @@
 		enqueue_task(p, array);
 		/*
 		 * Reschedule if we are currently running on this runqueue and
-		 * our priority decreased, or if our priority became higher
-		 * than the current's.
+		 * our priority decreased, or if we are not currently running on
+		 * this runqueue and our priority is higher than the current's
 		 */
-		if (TASK_PREEMPTS_CURR(p, rq) ||
-				(delta > 0 && task_running(rq, p)))
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
 			resched_task(rq->curr);
 	}
 	task_rq_unlock(rq, &flags);
@@ -4150,12 +4153,10 @@
 		enqueue_task(p, array);
 		inc_raw_weighted_load(rq, p);
 		/*
-		 * Reschedule if we are currently running on this runqueue and
-		 * our priority decreased, or if our priority became higher
-		 * than the current's.
+		 * If the task increased its priority or is running and
+		 * lowered its priority, then reschedule its CPU:
 		 */
-		if (TASK_PREEMPTS_CURR(p, rq) ||
-				(delta > 0 && task_running(rq, p)))
+		if (delta < 0 || (delta > 0 && task_running(rq, p)))
 			resched_task(rq->curr);
 	}
 out_unlock:
@@ -4382,11 +4383,13 @@
 		__activate_task(p, rq);
 		/*
 		 * Reschedule if we are currently running on this runqueue and
-		 * our priority decreased, or our priority became higher
-		 * than the current's.
+		 * our priority decreased, or if we are not currently running on
+		 * this runqueue and our priority is higher than the current's
 		 */
-		if (TASK_PREEMPTS_CURR(p, rq) ||
-				(task_running(rq, p) && p->prio > oldprio))
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
 			resched_task(rq->curr);
 	}
 	__task_rq_unlock(rq);
@@ -4518,13 +4521,13 @@
 	struct task_struct *p;
 	int retval;
 
-	lock_cpu_hotplug();
+	mutex_lock(&sched_hotcpu_mutex);
 	read_lock(&tasklist_lock);
 
 	p = find_process_by_pid(pid);
 	if (!p) {
 		read_unlock(&tasklist_lock);
-		unlock_cpu_hotplug();
+		mutex_unlock(&sched_hotcpu_mutex);
 		return -ESRCH;
 	}
 
@@ -4551,7 +4554,7 @@
 
 out_unlock:
 	put_task_struct(p);
-	unlock_cpu_hotplug();
+	mutex_unlock(&sched_hotcpu_mutex);
 	return retval;
 }
 
@@ -4608,7 +4611,7 @@
 	struct task_struct *p;
 	int retval;
 
-	lock_cpu_hotplug();
+	mutex_lock(&sched_hotcpu_mutex);
 	read_lock(&tasklist_lock);
 
 	retval = -ESRCH;
@@ -4624,7 +4627,7 @@
 
 out_unlock:
 	read_unlock(&tasklist_lock);
-	unlock_cpu_hotplug();
+	mutex_unlock(&sched_hotcpu_mutex);
 	if (retval)
 		return retval;
 
@@ -5386,7 +5389,12 @@
 	struct rq *rq;
 
 	switch (action) {
+	case CPU_LOCK_ACQUIRE:
+		mutex_lock(&sched_hotcpu_mutex);
+		break;
+
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
@@ -5400,12 +5408,14 @@
 		break;
 
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		/* Strictly unneccessary, as first user will wake it. */
 		wake_up_process(cpu_rq(cpu)->migration_thread);
 		break;
 
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		if (!cpu_rq(cpu)->migration_thread)
 			break;
 		/* Unbind it from offline cpu so it can run.  Fall thru. */
@@ -5416,6 +5426,7 @@
 		break;
 
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		migrate_live_tasks(cpu);
 		rq = cpu_rq(cpu);
 		kthread_stop(rq->migration_thread);
@@ -5431,7 +5442,7 @@
 		BUG_ON(rq->nr_running != 0);
 
 		/* No need to migrate the tasks: it was best-effort if
-		 * they didn't do lock_cpu_hotplug().  Just wake up
+		 * they didn't take sched_hotcpu_mutex.  Just wake up
 		 * the requestors. */
 		spin_lock_irq(&rq->lock);
 		while (!list_empty(&rq->migration_queue)) {
@@ -5445,6 +5456,9 @@
 		spin_unlock_irq(&rq->lock);
 		break;
 #endif
+	case CPU_LOCK_RELEASE:
+		mutex_unlock(&sched_hotcpu_mutex);
+		break;
 	}
 	return NOTIFY_OK;
 }
@@ -6820,10 +6834,10 @@
 {
 	int err;
 
-	lock_cpu_hotplug();
+	mutex_lock(&sched_hotcpu_mutex);
 	detach_destroy_domains(&cpu_online_map);
 	err = arch_init_sched_domains(&cpu_online_map);
-	unlock_cpu_hotplug();
+	mutex_unlock(&sched_hotcpu_mutex);
 
 	return err;
 }
@@ -6902,14 +6916,20 @@
 {
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
 		detach_destroy_domains(&cpu_online_map);
 		return NOTIFY_OK;
 
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		/*
 		 * Fall through and re-initialise the domains.
 		 */
@@ -6928,12 +6948,12 @@
 {
 	cpumask_t non_isolated_cpus;
 
-	lock_cpu_hotplug();
+	mutex_lock(&sched_hotcpu_mutex);
 	arch_init_sched_domains(&cpu_online_map);
 	cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map);
 	if (cpus_empty(non_isolated_cpus))
 		cpu_set(smp_processor_id(), non_isolated_cpus);
-	unlock_cpu_hotplug();
+	mutex_unlock(&sched_hotcpu_mutex);
 	/* XXX: Theoretical race here - CPU may be hotplugged now */
 	hotcpu_notifier(update_sched_domains, 0);
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 1368e67..2ac3a66 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -38,125 +38,6 @@
 
 static struct kmem_cache *sigqueue_cachep;
 
-/*
- * In POSIX a signal is sent either to a specific thread (Linux task)
- * or to the process as a whole (Linux thread group).  How the signal
- * is sent determines whether it's to one thread or the whole group,
- * which determines which signal mask(s) are involved in blocking it
- * from being delivered until later.  When the signal is delivered,
- * either it's caught or ignored by a user handler or it has a default
- * effect that applies to the whole thread group (POSIX process).
- *
- * The possible effects an unblocked signal set to SIG_DFL can have are:
- *   ignore	- Nothing Happens
- *   terminate	- kill the process, i.e. all threads in the group,
- * 		  similar to exit_group.  The group leader (only) reports
- *		  WIFSIGNALED status to its parent.
- *   coredump	- write a core dump file describing all threads using
- *		  the same mm and then kill all those threads
- *   stop 	- stop all the threads in the group, i.e. TASK_STOPPED state
- *
- * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
- * Other signals when not blocked and set to SIG_DFL behaves as follows.
- * The job control signals also have other special effects.
- *
- *	+--------------------+------------------+
- *	|  POSIX signal      |  default action  |
- *	+--------------------+------------------+
- *	|  SIGHUP            |  terminate	|
- *	|  SIGINT            |	terminate	|
- *	|  SIGQUIT           |	coredump 	|
- *	|  SIGILL            |	coredump 	|
- *	|  SIGTRAP           |	coredump 	|
- *	|  SIGABRT/SIGIOT    |	coredump 	|
- *	|  SIGBUS            |	coredump 	|
- *	|  SIGFPE            |	coredump 	|
- *	|  SIGKILL           |	terminate(+)	|
- *	|  SIGUSR1           |	terminate	|
- *	|  SIGSEGV           |	coredump 	|
- *	|  SIGUSR2           |	terminate	|
- *	|  SIGPIPE           |	terminate	|
- *	|  SIGALRM           |	terminate	|
- *	|  SIGTERM           |	terminate	|
- *	|  SIGCHLD           |	ignore   	|
- *	|  SIGCONT           |	ignore(*)	|
- *	|  SIGSTOP           |	stop(*)(+)  	|
- *	|  SIGTSTP           |	stop(*)  	|
- *	|  SIGTTIN           |	stop(*)  	|
- *	|  SIGTTOU           |	stop(*)  	|
- *	|  SIGURG            |	ignore   	|
- *	|  SIGXCPU           |	coredump 	|
- *	|  SIGXFSZ           |	coredump 	|
- *	|  SIGVTALRM         |	terminate	|
- *	|  SIGPROF           |	terminate	|
- *	|  SIGPOLL/SIGIO     |	terminate	|
- *	|  SIGSYS/SIGUNUSED  |	coredump 	|
- *	|  SIGSTKFLT         |	terminate	|
- *	|  SIGWINCH          |	ignore   	|
- *	|  SIGPWR            |	terminate	|
- *	|  SIGRTMIN-SIGRTMAX |	terminate       |
- *	+--------------------+------------------+
- *	|  non-POSIX signal  |  default action  |
- *	+--------------------+------------------+
- *	|  SIGEMT            |  coredump	|
- *	+--------------------+------------------+
- *
- * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
- * (*) Special job control effects:
- * When SIGCONT is sent, it resumes the process (all threads in the group)
- * from TASK_STOPPED state and also clears any pending/queued stop signals
- * (any of those marked with "stop(*)").  This happens regardless of blocking,
- * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
- * any pending/queued SIGCONT signals; this happens regardless of blocking,
- * catching, or ignored the stop signal, though (except for SIGSTOP) the
- * default action of stopping the process may happen later or never.
- */
-
-#ifdef SIGEMT
-#define M_SIGEMT	M(SIGEMT)
-#else
-#define M_SIGEMT	0
-#endif
-
-#if SIGRTMIN > BITS_PER_LONG
-#define M(sig) (1ULL << ((sig)-1))
-#else
-#define M(sig) (1UL << ((sig)-1))
-#endif
-#define T(sig, mask) (M(sig) & (mask))
-
-#define SIG_KERNEL_ONLY_MASK (\
-	M(SIGKILL)   |  M(SIGSTOP)                                   )
-
-#define SIG_KERNEL_STOP_MASK (\
-	M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   )
-
-#define SIG_KERNEL_COREDUMP_MASK (\
-        M(SIGQUIT)   |  M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   | \
-        M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGBUS)    |  M(SIGSYS)    | \
-        M(SIGXCPU)   |  M(SIGXFSZ)   |  M_SIGEMT                     )
-
-#define SIG_KERNEL_IGNORE_MASK (\
-        M(SIGCONT)   |  M(SIGCHLD)   |  M(SIGWINCH)  |  M(SIGURG)    )
-
-#define sig_kernel_only(sig) \
-		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_ONLY_MASK))
-#define sig_kernel_coredump(sig) \
-		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_COREDUMP_MASK))
-#define sig_kernel_ignore(sig) \
-		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_IGNORE_MASK))
-#define sig_kernel_stop(sig) \
-		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_STOP_MASK))
-
-#define sig_needs_tasklist(sig)	((sig) == SIGCONT)
-
-#define sig_user_defined(t, signr) \
-	(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&	\
-	 ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
-
-#define sig_fatal(t, signr) \
-	(!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
-	 (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
 static int sig_ignored(struct task_struct *t, int sig)
 {
@@ -328,6 +209,16 @@
 	spin_unlock_irqrestore(&t->sighand->siglock, flags);
 }
 
+void ignore_signals(struct task_struct *t)
+{
+	int i;
+
+	for (i = 0; i < _NSIG; ++i)
+		t->sighand->action[i].sa.sa_handler = SIG_IGN;
+
+	flush_signals(t);
+}
+
 /*
  * Flush all handlers for a task.
  */
@@ -1032,17 +923,6 @@
 		if (t->exit_state)
 			continue;
 
-		/*
-		 * We don't want to notify the parent, since we are
-		 * killed as part of a thread group due to another
-		 * thread doing an execve() or similar. So set the
-		 * exit signal to -1 to allow immediate reaping of
-		 * the process.  But don't detach the thread group
-		 * leader.
-		 */
-		if (t != p->group_leader)
-			t->exit_signal = -1;
-
 		/* SIGKILL will be handled before any pending SIGSTOP */
 		sigaddset(&t->pending.signal, SIGKILL);
 		signal_wake_up(t, 1);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 8b75008..0b9886a 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -593,6 +593,7 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
 		if (IS_ERR(p)) {
 			printk("ksoftirqd for %i failed\n", hotcpu);
@@ -602,16 +603,19 @@
   		per_cpu(ksoftirqd, hotcpu) = p;
  		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		wake_up_process(per_cpu(ksoftirqd, hotcpu));
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		if (!per_cpu(ksoftirqd, hotcpu))
 			break;
 		/* Unbind so it can run.  Fall thru. */
 		kthread_bind(per_cpu(ksoftirqd, hotcpu),
 			     any_online_cpu(cpu_online_map));
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		p = per_cpu(ksoftirqd, hotcpu);
 		per_cpu(ksoftirqd, hotcpu) = NULL;
 		kthread_stop(p);
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 8fa7040..0131e29 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -146,6 +146,7 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		BUG_ON(per_cpu(watchdog_task, hotcpu));
 		p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
 		if (IS_ERR(p)) {
@@ -157,16 +158,19 @@
 		kthread_bind(p, hotcpu);
  		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 		wake_up_process(per_cpu(watchdog_task, hotcpu));
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		if (!per_cpu(watchdog_task, hotcpu))
 			break;
 		/* Unbind so it can run.  Fall thru. */
 		kthread_bind(per_cpu(watchdog_task, hotcpu),
 			     any_online_cpu(cpu_online_map));
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		p = per_cpu(watchdog_task, hotcpu);
 		per_cpu(watchdog_task, hotcpu) = NULL;
 		kthread_stop(p);
diff --git a/kernel/sys.c b/kernel/sys.c
index 926bf9d..cdb7e94 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -134,19 +134,39 @@
 	return -ENOENT;
 }
 
+/**
+ * notifier_call_chain - Informs the registered notifiers about an event.
+ *	@nl:		Pointer to head of the blocking notifier chain
+ *	@val:		Value passed unmodified to notifier function
+ *	@v:		Pointer passed unmodified to notifier function
+ *	@nr_to_call:	Number of notifier functions to be called. Don't care
+ *		     	value of this parameter is -1.
+ *	@nr_calls:	Records the number of notifications sent. Don't care
+ *		   	value of this field is NULL.
+ * 	@returns:	notifier_call_chain returns the value returned by the
+ *			last notifier function called.
+ */
+
 static int __kprobes notifier_call_chain(struct notifier_block **nl,
-		unsigned long val, void *v)
+					unsigned long val, void *v,
+					int nr_to_call,	int *nr_calls)
 {
 	int ret = NOTIFY_DONE;
 	struct notifier_block *nb, *next_nb;
 
 	nb = rcu_dereference(*nl);
-	while (nb) {
+
+	while (nb && nr_to_call) {
 		next_nb = rcu_dereference(nb->next);
 		ret = nb->notifier_call(nb, val, v);
+
+		if (nr_calls)
+			(*nr_calls)++;
+
 		if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
 			break;
 		nb = next_nb;
+		nr_to_call--;
 	}
 	return ret;
 }
@@ -205,10 +225,12 @@
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
 
 /**
- *	atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *	__atomic_notifier_call_chain - Call functions in an atomic notifier chain
  *	@nh: Pointer to head of the atomic notifier chain
  *	@val: Value passed unmodified to notifier function
  *	@v: Pointer passed unmodified to notifier function
+ *	@nr_to_call: See the comment for notifier_call_chain.
+ *	@nr_calls: See the comment for notifier_call_chain.
  *
  *	Calls each function in a notifier chain in turn.  The functions
  *	run in an atomic context, so they must not block.
@@ -222,19 +244,27 @@
  *	of the last notifier function called.
  */
  
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-		unsigned long val, void *v)
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+					unsigned long val, void *v,
+					int nr_to_call, int *nr_calls)
 {
 	int ret;
 
 	rcu_read_lock();
-	ret = notifier_call_chain(&nh->head, val, v);
+	ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
 	rcu_read_unlock();
 	return ret;
 }
 
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
 
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 /*
  *	Blocking notifier chain routines.  All access to the chain is
  *	synchronized by an rwsem.
@@ -304,10 +334,12 @@
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
 
 /**
- *	blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ *	__blocking_notifier_call_chain - Call functions in a blocking notifier chain
  *	@nh: Pointer to head of the blocking notifier chain
  *	@val: Value passed unmodified to notifier function
  *	@v: Pointer passed unmodified to notifier function
+ *	@nr_to_call: See comment for notifier_call_chain.
+ *	@nr_calls: See comment for notifier_call_chain.
  *
  *	Calls each function in a notifier chain in turn.  The functions
  *	run in a process context, so they are allowed to block.
@@ -320,8 +352,9 @@
  *	of the last notifier function called.
  */
  
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-		unsigned long val, void *v)
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+				   unsigned long val, void *v,
+				   int nr_to_call, int *nr_calls)
 {
 	int ret = NOTIFY_DONE;
 
@@ -332,12 +365,19 @@
 	 */
 	if (rcu_dereference(nh->head)) {
 		down_read(&nh->rwsem);
-		ret = notifier_call_chain(&nh->head, val, v);
+		ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
+					nr_calls);
 		up_read(&nh->rwsem);
 	}
 	return ret;
 }
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
 
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
 /*
@@ -383,10 +423,12 @@
 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
 
 /**
- *	raw_notifier_call_chain - Call functions in a raw notifier chain
+ *	__raw_notifier_call_chain - Call functions in a raw notifier chain
  *	@nh: Pointer to head of the raw notifier chain
  *	@val: Value passed unmodified to notifier function
  *	@v: Pointer passed unmodified to notifier function
+ *	@nr_to_call: See comment for notifier_call_chain.
+ *	@nr_calls: See comment for notifier_call_chain
  *
  *	Calls each function in a notifier chain in turn.  The functions
  *	run in an undefined context.
@@ -400,10 +442,19 @@
  *	of the last notifier function called.
  */
 
+int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+			      unsigned long val, void *v,
+			      int nr_to_call, int *nr_calls)
+{
+	return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+}
+
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
+
 int raw_notifier_call_chain(struct raw_notifier_head *nh,
 		unsigned long val, void *v)
 {
-	return notifier_call_chain(&nh->head, val, v);
+	return __raw_notifier_call_chain(nh, val, v, -1, NULL);
 }
 
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +529,12 @@
 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
 
 /**
- *	srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *	__srcu_notifier_call_chain - Call functions in an SRCU notifier chain
  *	@nh: Pointer to head of the SRCU notifier chain
  *	@val: Value passed unmodified to notifier function
  *	@v: Pointer passed unmodified to notifier function
+ *	@nr_to_call: See comment for notifier_call_chain.
+ *	@nr_calls: See comment for notifier_call_chain
  *
  *	Calls each function in a notifier chain in turn.  The functions
  *	run in a process context, so they are allowed to block.
@@ -494,18 +547,25 @@
  *	of the last notifier function called.
  */
 
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-		unsigned long val, void *v)
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+			       unsigned long val, void *v,
+			       int nr_to_call, int *nr_calls)
 {
 	int ret;
 	int idx;
 
 	idx = srcu_read_lock(&nh->srcu);
-	ret = notifier_call_chain(&nh->head, val, v);
+	ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
 	srcu_read_unlock(&nh->srcu, idx);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
 
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
 
 /**
@@ -881,7 +941,7 @@
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	case LINUX_REBOOT_CMD_SW_SUSPEND:
 		{
-			int ret = pm_suspend(PM_SUSPEND_DISK);
+			int ret = hibernate();
 			unlock_kernel();
 			return ret;
 		}
@@ -1292,7 +1352,7 @@
 }
 
 /*
- * Samma på svenska..
+ * Samma på svenska..
  */
 asmlinkage long sys_setfsgid(gid_t gid)
 {
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index f0664bd..4073353 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -77,6 +77,7 @@
 extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
+extern int sysctl_stat_interval;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -857,6 +858,17 @@
 		.extra2		= &one_hundred,
 	},
 #endif
+#ifdef CONFIG_SMP
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "stat_interval",
+		.data		= &sysctl_stat_interval,
+		.maxlen		= sizeof(sysctl_stat_interval),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+		.strategy	= &sysctl_jiffies,
+	},
+#endif
 #if defined(CONFIG_X86_32) || \
    (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
 	{
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index fe5c7db..3db5c3c 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -74,15 +74,17 @@
 static struct timer_list watchdog_timer;
 static DEFINE_SPINLOCK(watchdog_lock);
 static cycle_t watchdog_last;
+static int watchdog_resumed;
+
 /*
- * Interval: 0.5sec Treshold: 0.0625s
+ * Interval: 0.5sec Threshold: 0.0625s
  */
 #define WATCHDOG_INTERVAL (HZ >> 1)
-#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4)
+#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)
 
 static void clocksource_ratewd(struct clocksource *cs, int64_t delta)
 {
-	if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD)
+	if (delta > -WATCHDOG_THRESHOLD && delta < WATCHDOG_THRESHOLD)
 		return;
 
 	printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
@@ -98,15 +100,26 @@
 	struct clocksource *cs, *tmp;
 	cycle_t csnow, wdnow;
 	int64_t wd_nsec, cs_nsec;
+	int resumed;
 
 	spin_lock(&watchdog_lock);
 
+	resumed = watchdog_resumed;
+	if (unlikely(resumed))
+		watchdog_resumed = 0;
+
 	wdnow = watchdog->read();
 	wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask);
 	watchdog_last = wdnow;
 
 	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
 		csnow = cs->read();
+
+		if (unlikely(resumed)) {
+			cs->wd_last = csnow;
+			continue;
+		}
+
 		/* Initialized ? */
 		if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
 			if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&
@@ -136,6 +149,13 @@
 	}
 	spin_unlock(&watchdog_lock);
 }
+static void clocksource_resume_watchdog(void)
+{
+	spin_lock(&watchdog_lock);
+	watchdog_resumed = 1;
+	spin_unlock(&watchdog_lock);
+}
+
 static void clocksource_check_watchdog(struct clocksource *cs)
 {
 	struct clocksource *cse;
@@ -182,9 +202,34 @@
 	if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
 		cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
 }
+
+static inline void clocksource_resume_watchdog(void) { }
 #endif
 
 /**
+ * clocksource_resume - resume the clocksource(s)
+ */
+void clocksource_resume(void)
+{
+	struct list_head *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&clocksource_lock, flags);
+
+	list_for_each(tmp, &clocksource_list) {
+		struct clocksource *cs;
+
+		cs = list_entry(tmp, struct clocksource, list);
+		if (cs->resume)
+			cs->resume();
+	}
+
+	clocksource_resume_watchdog();
+
+	spin_unlock_irqrestore(&clocksource_lock, flags);
+}
+
+/**
  * clocksource_get_next - Returns the selected clocksource
  *
  */
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index b734ca4..8bbcfb7 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -65,7 +65,7 @@
 	SEQ_printf(m, ", %s/%d", tmp, timer->start_pid);
 #endif
 	SEQ_printf(m, "\n");
-	SEQ_printf(m, " # expires at %Ld nsecs [in %Ld nsecs]\n",
+	SEQ_printf(m, " # expires at %Lu nsecs [in %Lu nsecs]\n",
 		(unsigned long long)ktime_to_ns(timer->expires),
 		(unsigned long long)(ktime_to_ns(timer->expires) - now));
 }
@@ -111,14 +111,14 @@
 {
 	SEQ_printf(m, "  .index:      %d\n",
 			base->index);
-	SEQ_printf(m, "  .resolution: %Ld nsecs\n",
+	SEQ_printf(m, "  .resolution: %Lu nsecs\n",
 			(unsigned long long)ktime_to_ns(base->resolution));
 	SEQ_printf(m,   "  .get_time:   ");
 	print_name_offset(m, base->get_time);
 	SEQ_printf(m,   "\n");
 #ifdef CONFIG_HIGH_RES_TIMERS
-	SEQ_printf(m, "  .offset:     %Ld nsecs\n",
-			ktime_to_ns(base->offset));
+	SEQ_printf(m, "  .offset:     %Lu nsecs\n",
+		   (unsigned long long) ktime_to_ns(base->offset));
 #endif
 	SEQ_printf(m,   "active timers:\n");
 	print_active_timers(m, base, now);
@@ -135,10 +135,11 @@
 		print_base(m, cpu_base->clock_base + i, now);
 	}
 #define P(x) \
-	SEQ_printf(m, "  .%-15s: %Ld\n", #x, (u64)(cpu_base->x))
+	SEQ_printf(m, "  .%-15s: %Lu\n", #x, \
+		   (unsigned long long)(cpu_base->x))
 #define P_ns(x) \
-	SEQ_printf(m, "  .%-15s: %Ld nsecs\n", #x, \
-		(u64)(ktime_to_ns(cpu_base->x)))
+	SEQ_printf(m, "  .%-15s: %Lu nsecs\n", #x, \
+		   (unsigned long long)(ktime_to_ns(cpu_base->x)))
 
 #ifdef CONFIG_HIGH_RES_TIMERS
 	P_ns(expires_next);
@@ -150,10 +151,11 @@
 
 #ifdef CONFIG_TICK_ONESHOT
 # define P(x) \
-	SEQ_printf(m, "  .%-15s: %Ld\n", #x, (u64)(ts->x))
+	SEQ_printf(m, "  .%-15s: %Lu\n", #x, \
+		   (unsigned long long)(ts->x))
 # define P_ns(x) \
-	SEQ_printf(m, "  .%-15s: %Ld nsecs\n", #x, \
-		(u64)(ktime_to_ns(ts->x)))
+	SEQ_printf(m, "  .%-15s: %Lu nsecs\n", #x, \
+		   (unsigned long long)(ktime_to_ns(ts->x)))
 	{
 		struct tick_sched *ts = tick_get_tick_sched(cpu);
 		P(nohz_mode);
@@ -167,7 +169,8 @@
 		P(last_jiffies);
 		P(next_jiffies);
 		P_ns(idle_expires);
-		SEQ_printf(m, "jiffies: %Ld\n", (u64)jiffies);
+		SEQ_printf(m, "jiffies: %Lu\n",
+			   (unsigned long long)jiffies);
 	}
 #endif
 
diff --git a/kernel/timer.c b/kernel/timer.c
index 7a64483..59a28b1 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -92,24 +92,24 @@
 /* Functions below help us manage 'deferrable' flag */
 static inline unsigned int tbase_get_deferrable(tvec_base_t *base)
 {
-	return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG);
+	return (unsigned int)((unsigned long)base & TBASE_DEFERRABLE_FLAG);
 }
 
 static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
 {
-	return ((tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG));
+	return (tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG);
 }
 
 static inline void timer_set_deferrable(struct timer_list *timer)
 {
-	timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
-	                               TBASE_DEFERRABLE_FLAG));
+	timer->base = (tvec_base_t *)((unsigned long)timer->base |
+	                               TBASE_DEFERRABLE_FLAG);
 }
 
 static inline void
 timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
 {
-	timer->base = (tvec_base_t *)((unsigned long)(new_base) |
+	timer->base = (tvec_base_t *)((unsigned long)new_base |
 	                              tbase_get_deferrable(timer->base));
 }
 
@@ -1293,11 +1293,13 @@
 	long cpu = (long)hcpu;
 	switch(action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		if (init_timers_cpu(cpu) < 0)
 			return NOTIFY_BAD;
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		migrate_timers(cpu);
 		break;
 #endif
@@ -1497,6 +1499,8 @@
 		prev = &curr->next;
 	}
 
+	clocksource_resume();
+
 	write_seqlock_irqsave(&xtime_lock, flags);
 	if (ti == time_interpolator) {
 		/* we lost the best time-interpolator: */
diff --git a/kernel/wait.c b/kernel/wait.c
index 59a82f6..444ddbf 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -61,7 +61,7 @@
  * The spin_unlock() itself is semi-permeable and only protects
  * one way (it only protects stuff inside the critical region and
  * stops them from bleeding out - it would still allow subsequent
- * loads to move into the the critical region).
+ * loads to move into the critical region).
  */
 void fastcall
 prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index b6fa5e6..fb56fed 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -36,30 +36,20 @@
 /*
  * The per-CPU workqueue (if single thread, we always use the first
  * possible cpu).
- *
- * The sequence counters are for flush_scheduled_work().  It wants to wait
- * until all currently-scheduled works are completed, but it doesn't
- * want to be livelocked by new, incoming ones.  So it waits until
- * remove_sequence is >= the insert_sequence which pertained when
- * flush_scheduled_work() was called.
  */
 struct cpu_workqueue_struct {
 
 	spinlock_t lock;
 
-	long remove_sequence;	/* Least-recently added (next to run) */
-	long insert_sequence;	/* Next to add */
-
 	struct list_head worklist;
 	wait_queue_head_t more_work;
-	wait_queue_head_t work_done;
+	struct work_struct *current_work;
 
 	struct workqueue_struct *wq;
 	struct task_struct *thread;
+	int should_stop;
 
 	int run_depth;		/* Detect run_workqueue() recursion depth */
-
-	int freezeable;		/* Freeze the thread during suspend */
 } ____cacheline_aligned;
 
 /*
@@ -68,8 +58,10 @@
  */
 struct workqueue_struct {
 	struct cpu_workqueue_struct *cpu_wq;
+	struct list_head list;
 	const char *name;
-	struct list_head list; 	/* Empty if single thread */
+	int singlethread;
+	int freezeable;		/* Freeze threads during suspend */
 };
 
 /* All the per-cpu workqueues on the system, for hotplug cpu to add/remove
@@ -77,107 +69,69 @@
 static DEFINE_MUTEX(workqueue_mutex);
 static LIST_HEAD(workqueues);
 
-static int singlethread_cpu;
+static int singlethread_cpu __read_mostly;
+static cpumask_t cpu_singlethread_map __read_mostly;
+/* optimization, we could use cpu_possible_map */
+static cpumask_t cpu_populated_map __read_mostly;
 
 /* If it's single threaded, it isn't in the list of workqueues. */
 static inline int is_single_threaded(struct workqueue_struct *wq)
 {
-	return list_empty(&wq->list);
+	return wq->singlethread;
+}
+
+static const cpumask_t *wq_cpu_map(struct workqueue_struct *wq)
+{
+	return is_single_threaded(wq)
+		? &cpu_singlethread_map : &cpu_populated_map;
+}
+
+static
+struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
+{
+	if (unlikely(is_single_threaded(wq)))
+		cpu = singlethread_cpu;
+	return per_cpu_ptr(wq->cpu_wq, cpu);
 }
 
 /*
  * Set the workqueue on which a work item is to be run
  * - Must *only* be called if the pending flag is set
  */
-static inline void set_wq_data(struct work_struct *work, void *wq)
+static inline void set_wq_data(struct work_struct *work,
+				struct cpu_workqueue_struct *cwq)
 {
 	unsigned long new;
 
 	BUG_ON(!work_pending(work));
 
-	new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING);
+	new = (unsigned long) cwq | (1UL << WORK_STRUCT_PENDING);
 	new |= WORK_STRUCT_FLAG_MASK & *work_data_bits(work);
 	atomic_long_set(&work->data, new);
 }
 
-static inline void *get_wq_data(struct work_struct *work)
+static inline
+struct cpu_workqueue_struct *get_wq_data(struct work_struct *work)
 {
 	return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
 }
 
-static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)
+static void insert_work(struct cpu_workqueue_struct *cwq,
+				struct work_struct *work, int tail)
 {
-	int ret = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cwq->lock, flags);
+	set_wq_data(work, cwq);
 	/*
-	 * We need to re-validate the work info after we've gotten
-	 * the cpu_workqueue lock. We can run the work now iff:
-	 *
-	 *  - the wq_data still matches the cpu_workqueue_struct
-	 *  - AND the work is still marked pending
-	 *  - AND the work is still on a list (which will be this
-	 *    workqueue_struct list)
-	 *
-	 * All these conditions are important, because we
-	 * need to protect against the work being run right
-	 * now on another CPU (all but the last one might be
-	 * true if it's currently running and has not been
-	 * released yet, for example).
+	 * Ensure that we get the right work->data if we see the
+	 * result of list_add() below, see try_to_grab_pending().
 	 */
-	if (get_wq_data(work) == cwq
-	    && work_pending(work)
-	    && !list_empty(&work->entry)) {
-		work_func_t f = work->func;
-		list_del_init(&work->entry);
-		spin_unlock_irqrestore(&cwq->lock, flags);
-
-		if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
-			work_release(work);
-		f(work);
-
-		spin_lock_irqsave(&cwq->lock, flags);
-		cwq->remove_sequence++;
-		wake_up(&cwq->work_done);
-		ret = 1;
-	}
-	spin_unlock_irqrestore(&cwq->lock, flags);
-	return ret;
+	smp_wmb();
+	if (tail)
+		list_add_tail(&work->entry, &cwq->worklist);
+	else
+		list_add(&work->entry, &cwq->worklist);
+	wake_up(&cwq->more_work);
 }
 
-/**
- * run_scheduled_work - run scheduled work synchronously
- * @work: work to run
- *
- * This checks if the work was pending, and runs it
- * synchronously if so. It returns a boolean to indicate
- * whether it had any scheduled work to run or not.
- *
- * NOTE! This _only_ works for normal work_structs. You
- * CANNOT use this for delayed work, because the wq data
- * for delayed work will not point properly to the per-
- * CPU workqueue struct, but will change!
- */
-int fastcall run_scheduled_work(struct work_struct *work)
-{
-	for (;;) {
-		struct cpu_workqueue_struct *cwq;
-
-		if (!work_pending(work))
-			return 0;
-		if (list_empty(&work->entry))
-			return 0;
-		/* NOTE! This depends intimately on __queue_work! */
-		cwq = get_wq_data(work);
-		if (!cwq)
-			return 0;
-		if (__run_work(cwq, work))
-			return 1;
-	}
-}
-EXPORT_SYMBOL(run_scheduled_work);
-
 /* Preempt must be disabled. */
 static void __queue_work(struct cpu_workqueue_struct *cwq,
 			 struct work_struct *work)
@@ -185,10 +139,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&cwq->lock, flags);
-	set_wq_data(work, cwq);
-	list_add_tail(&work->entry, &cwq->worklist);
-	cwq->insert_sequence++;
-	wake_up(&cwq->more_work);
+	insert_work(cwq, work, 1);
 	spin_unlock_irqrestore(&cwq->lock, flags);
 }
 
@@ -204,16 +155,14 @@
  */
 int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
 {
-	int ret = 0, cpu = get_cpu();
+	int ret = 0;
 
 	if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
-		if (unlikely(is_single_threaded(wq)))
-			cpu = singlethread_cpu;
 		BUG_ON(!list_empty(&work->entry));
-		__queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
+		__queue_work(wq_per_cpu(wq, get_cpu()), work);
+		put_cpu();
 		ret = 1;
 	}
-	put_cpu();
 	return ret;
 }
 EXPORT_SYMBOL_GPL(queue_work);
@@ -221,13 +170,10 @@
 void delayed_work_timer_fn(unsigned long __data)
 {
 	struct delayed_work *dwork = (struct delayed_work *)__data;
-	struct workqueue_struct *wq = get_wq_data(&dwork->work);
-	int cpu = smp_processor_id();
+	struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work);
+	struct workqueue_struct *wq = cwq->wq;
 
-	if (unlikely(is_single_threaded(wq)))
-		cpu = singlethread_cpu;
-
-	__queue_work(per_cpu_ptr(wq->cpu_wq, cpu), &dwork->work);
+	__queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work);
 }
 
 /**
@@ -241,27 +187,11 @@
 int fastcall queue_delayed_work(struct workqueue_struct *wq,
 			struct delayed_work *dwork, unsigned long delay)
 {
-	int ret = 0;
-	struct timer_list *timer = &dwork->timer;
-	struct work_struct *work = &dwork->work;
-
-	timer_stats_timer_set_start_info(timer);
+	timer_stats_timer_set_start_info(&dwork->timer);
 	if (delay == 0)
-		return queue_work(wq, work);
+		return queue_work(wq, &dwork->work);
 
-	if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
-		BUG_ON(timer_pending(timer));
-		BUG_ON(!list_empty(&work->entry));
-
-		/* This stores wq for the moment, for the timer_fn */
-		set_wq_data(work, wq);
-		timer->expires = jiffies + delay;
-		timer->data = (unsigned long)dwork;
-		timer->function = delayed_work_timer_fn;
-		add_timer(timer);
-		ret = 1;
-	}
-	return ret;
+	return queue_delayed_work_on(-1, wq, dwork, delay);
 }
 EXPORT_SYMBOL_GPL(queue_delayed_work);
 
@@ -285,12 +215,16 @@
 		BUG_ON(timer_pending(timer));
 		BUG_ON(!list_empty(&work->entry));
 
-		/* This stores wq for the moment, for the timer_fn */
-		set_wq_data(work, wq);
+		/* This stores cwq for the moment, for the timer_fn */
+		set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
 		timer->expires = jiffies + delay;
 		timer->data = (unsigned long)dwork;
 		timer->function = delayed_work_timer_fn;
-		add_timer_on(timer, cpu);
+
+		if (unlikely(cpu >= 0))
+			add_timer_on(timer, cpu);
+		else
+			add_timer(timer);
 		ret = 1;
 	}
 	return ret;
@@ -299,13 +233,7 @@
 
 static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
-	unsigned long flags;
-
-	/*
-	 * Keep taking off work from the queue until
-	 * done.
-	 */
-	spin_lock_irqsave(&cwq->lock, flags);
+	spin_lock_irq(&cwq->lock);
 	cwq->run_depth++;
 	if (cwq->run_depth > 3) {
 		/* morton gets to eat his hat */
@@ -318,12 +246,12 @@
 						struct work_struct, entry);
 		work_func_t f = work->func;
 
+		cwq->current_work = work;
 		list_del_init(cwq->worklist.next);
-		spin_unlock_irqrestore(&cwq->lock, flags);
+		spin_unlock_irq(&cwq->lock);
 
 		BUG_ON(get_wq_data(work) != cwq);
-		if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
-			work_release(work);
+		work_clear_pending(work);
 		f(work);
 
 		if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
@@ -337,63 +265,81 @@
 			dump_stack();
 		}
 
-		spin_lock_irqsave(&cwq->lock, flags);
-		cwq->remove_sequence++;
-		wake_up(&cwq->work_done);
+		spin_lock_irq(&cwq->lock);
+		cwq->current_work = NULL;
 	}
 	cwq->run_depth--;
-	spin_unlock_irqrestore(&cwq->lock, flags);
+	spin_unlock_irq(&cwq->lock);
+}
+
+/*
+ * NOTE: the caller must not touch *cwq if this func returns true
+ */
+static int cwq_should_stop(struct cpu_workqueue_struct *cwq)
+{
+	int should_stop = cwq->should_stop;
+
+	if (unlikely(should_stop)) {
+		spin_lock_irq(&cwq->lock);
+		should_stop = cwq->should_stop && list_empty(&cwq->worklist);
+		if (should_stop)
+			cwq->thread = NULL;
+		spin_unlock_irq(&cwq->lock);
+	}
+
+	return should_stop;
 }
 
 static int worker_thread(void *__cwq)
 {
 	struct cpu_workqueue_struct *cwq = __cwq;
-	DECLARE_WAITQUEUE(wait, current);
-	struct k_sigaction sa;
-	sigset_t blocked;
+	DEFINE_WAIT(wait);
 
-	if (!cwq->freezeable)
+	if (!cwq->wq->freezeable)
 		current->flags |= PF_NOFREEZE;
 
 	set_user_nice(current, -5);
 
-	/* Block and flush all signals */
-	sigfillset(&blocked);
-	sigprocmask(SIG_BLOCK, &blocked, NULL);
-	flush_signals(current);
-
-	/*
-	 * We inherited MPOL_INTERLEAVE from the booting kernel.
-	 * Set MPOL_DEFAULT to insure node local allocations.
-	 */
-	numa_default_policy();
-
-	/* SIG_IGN makes children autoreap: see do_notify_parent(). */
-	sa.sa.sa_handler = SIG_IGN;
-	sa.sa.sa_flags = 0;
-	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
-
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (!kthread_should_stop()) {
-		if (cwq->freezeable)
-			try_to_freeze();
-
-		add_wait_queue(&cwq->more_work, &wait);
-		if (list_empty(&cwq->worklist))
+	for (;;) {
+		prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
+		if (!freezing(current) && !cwq->should_stop
+		    && list_empty(&cwq->worklist))
 			schedule();
-		else
-			__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&cwq->more_work, &wait);
+		finish_wait(&cwq->more_work, &wait);
 
-		if (!list_empty(&cwq->worklist))
-			run_workqueue(cwq);
-		set_current_state(TASK_INTERRUPTIBLE);
+		try_to_freeze();
+
+		if (cwq_should_stop(cwq))
+			break;
+
+		run_workqueue(cwq);
 	}
-	__set_current_state(TASK_RUNNING);
+
 	return 0;
 }
 
+struct wq_barrier {
+	struct work_struct	work;
+	struct completion	done;
+};
+
+static void wq_barrier_func(struct work_struct *work)
+{
+	struct wq_barrier *barr = container_of(work, struct wq_barrier, work);
+	complete(&barr->done);
+}
+
+static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
+					struct wq_barrier *barr, int tail)
+{
+	INIT_WORK(&barr->work, wq_barrier_func);
+	__set_bit(WORK_STRUCT_PENDING, work_data_bits(&barr->work));
+
+	init_completion(&barr->done);
+
+	insert_work(cwq, &barr->work, tail);
+}
+
 static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
 {
 	if (cwq->thread == current) {
@@ -403,21 +349,18 @@
 		 */
 		run_workqueue(cwq);
 	} else {
-		DEFINE_WAIT(wait);
-		long sequence_needed;
+		struct wq_barrier barr;
+		int active = 0;
 
 		spin_lock_irq(&cwq->lock);
-		sequence_needed = cwq->insert_sequence;
-
-		while (sequence_needed - cwq->remove_sequence > 0) {
-			prepare_to_wait(&cwq->work_done, &wait,
-					TASK_UNINTERRUPTIBLE);
-			spin_unlock_irq(&cwq->lock);
-			schedule();
-			spin_lock_irq(&cwq->lock);
+		if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
+			insert_wq_barrier(cwq, &barr, 1);
+			active = 1;
 		}
-		finish_wait(&cwq->work_done, &wait);
 		spin_unlock_irq(&cwq->lock);
+
+		if (active)
+			wait_for_completion(&barr.done);
 	}
 }
 
@@ -428,151 +371,145 @@
  * Forces execution of the workqueue and blocks until its completion.
  * This is typically used in driver shutdown handlers.
  *
- * This function will sample each workqueue's current insert_sequence number and
- * will sleep until the head sequence is greater than or equal to that.  This
- * means that we sleep until all works which were queued on entry have been
- * handled, but we are not livelocked by new incoming ones.
+ * We sleep until all works which were queued on entry have been handled,
+ * but we are not livelocked by new incoming ones.
  *
  * This function used to run the workqueues itself.  Now we just wait for the
  * helper threads to do it.
  */
 void fastcall flush_workqueue(struct workqueue_struct *wq)
 {
+	const cpumask_t *cpu_map = wq_cpu_map(wq);
+	int cpu;
+
 	might_sleep();
-
-	if (is_single_threaded(wq)) {
-		/* Always use first cpu's area. */
-		flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
-	} else {
-		int cpu;
-
-		mutex_lock(&workqueue_mutex);
-		for_each_online_cpu(cpu)
-			flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
-		mutex_unlock(&workqueue_mutex);
-	}
+	for_each_cpu_mask(cpu, *cpu_map)
+		flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
 }
 EXPORT_SYMBOL_GPL(flush_workqueue);
 
-static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
-						   int cpu, int freezeable)
-{
-	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-	struct task_struct *p;
-
-	spin_lock_init(&cwq->lock);
-	cwq->wq = wq;
-	cwq->thread = NULL;
-	cwq->insert_sequence = 0;
-	cwq->remove_sequence = 0;
-	cwq->freezeable = freezeable;
-	INIT_LIST_HEAD(&cwq->worklist);
-	init_waitqueue_head(&cwq->more_work);
-	init_waitqueue_head(&cwq->work_done);
-
-	if (is_single_threaded(wq))
-		p = kthread_create(worker_thread, cwq, "%s", wq->name);
-	else
-		p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
-	if (IS_ERR(p))
-		return NULL;
-	cwq->thread = p;
-	return p;
-}
-
-struct workqueue_struct *__create_workqueue(const char *name,
-					    int singlethread, int freezeable)
-{
-	int cpu, destroy = 0;
-	struct workqueue_struct *wq;
-	struct task_struct *p;
-
-	wq = kzalloc(sizeof(*wq), GFP_KERNEL);
-	if (!wq)
-		return NULL;
-
-	wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
-	if (!wq->cpu_wq) {
-		kfree(wq);
-		return NULL;
-	}
-
-	wq->name = name;
-	mutex_lock(&workqueue_mutex);
-	if (singlethread) {
-		INIT_LIST_HEAD(&wq->list);
-		p = create_workqueue_thread(wq, singlethread_cpu, freezeable);
-		if (!p)
-			destroy = 1;
-		else
-			wake_up_process(p);
-	} else {
-		list_add(&wq->list, &workqueues);
-		for_each_online_cpu(cpu) {
-			p = create_workqueue_thread(wq, cpu, freezeable);
-			if (p) {
-				kthread_bind(p, cpu);
-				wake_up_process(p);
-			} else
-				destroy = 1;
-		}
-	}
-	mutex_unlock(&workqueue_mutex);
-
-	/*
-	 * Was there any error during startup? If yes then clean up:
-	 */
-	if (destroy) {
-		destroy_workqueue(wq);
-		wq = NULL;
-	}
-	return wq;
-}
-EXPORT_SYMBOL_GPL(__create_workqueue);
-
-static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
+/*
+ * Upon a successful return, the caller "owns" WORK_STRUCT_PENDING bit,
+ * so this work can't be re-armed in any way.
+ */
+static int try_to_grab_pending(struct work_struct *work)
 {
 	struct cpu_workqueue_struct *cwq;
-	unsigned long flags;
-	struct task_struct *p;
+	int ret = 0;
 
-	cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-	spin_lock_irqsave(&cwq->lock, flags);
-	p = cwq->thread;
-	cwq->thread = NULL;
-	spin_unlock_irqrestore(&cwq->lock, flags);
-	if (p)
-		kthread_stop(p);
+	if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work)))
+		return 1;
+
+	/*
+	 * The queueing is in progress, or it is already queued. Try to
+	 * steal it from ->worklist without clearing WORK_STRUCT_PENDING.
+	 */
+
+	cwq = get_wq_data(work);
+	if (!cwq)
+		return ret;
+
+	spin_lock_irq(&cwq->lock);
+	if (!list_empty(&work->entry)) {
+		/*
+		 * This work is queued, but perhaps we locked the wrong cwq.
+		 * In that case we must see the new value after rmb(), see
+		 * insert_work()->wmb().
+		 */
+		smp_rmb();
+		if (cwq == get_wq_data(work)) {
+			list_del_init(&work->entry);
+			ret = 1;
+		}
+	}
+	spin_unlock_irq(&cwq->lock);
+
+	return ret;
+}
+
+static void wait_on_cpu_work(struct cpu_workqueue_struct *cwq,
+				struct work_struct *work)
+{
+	struct wq_barrier barr;
+	int running = 0;
+
+	spin_lock_irq(&cwq->lock);
+	if (unlikely(cwq->current_work == work)) {
+		insert_wq_barrier(cwq, &barr, 0);
+		running = 1;
+	}
+	spin_unlock_irq(&cwq->lock);
+
+	if (unlikely(running))
+		wait_for_completion(&barr.done);
+}
+
+static void wait_on_work(struct work_struct *work)
+{
+	struct cpu_workqueue_struct *cwq;
+	struct workqueue_struct *wq;
+	const cpumask_t *cpu_map;
+	int cpu;
+
+	might_sleep();
+
+	cwq = get_wq_data(work);
+	if (!cwq)
+		return;
+
+	wq = cwq->wq;
+	cpu_map = wq_cpu_map(wq);
+
+	for_each_cpu_mask(cpu, *cpu_map)
+		wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
 }
 
 /**
- * destroy_workqueue - safely terminate a workqueue
- * @wq: target workqueue
+ * cancel_work_sync - block until a work_struct's callback has terminated
+ * @work: the work which is to be flushed
  *
- * Safely destroy a workqueue. All work currently pending will be done first.
+ * cancel_work_sync() will cancel the work if it is queued. If the work's
+ * callback appears to be running, cancel_work_sync() will block until it
+ * has completed.
+ *
+ * It is possible to use this function if the work re-queues itself. It can
+ * cancel the work even if it migrates to another workqueue, however in that
+ * case it only guarantees that work->func() has completed on the last queued
+ * workqueue.
+ *
+ * cancel_work_sync(&delayed_work->work) should be used only if ->timer is not
+ * pending, otherwise it goes into a busy-wait loop until the timer expires.
+ *
+ * The caller must ensure that workqueue_struct on which this work was last
+ * queued can't be destroyed before this function returns.
  */
-void destroy_workqueue(struct workqueue_struct *wq)
+void cancel_work_sync(struct work_struct *work)
 {
-	int cpu;
-
-	flush_workqueue(wq);
-
-	/* We don't need the distraction of CPUs appearing and vanishing. */
-	mutex_lock(&workqueue_mutex);
-	if (is_single_threaded(wq))
-		cleanup_workqueue_thread(wq, singlethread_cpu);
-	else {
-		for_each_online_cpu(cpu)
-			cleanup_workqueue_thread(wq, cpu);
-		list_del(&wq->list);
-	}
-	mutex_unlock(&workqueue_mutex);
-	free_percpu(wq->cpu_wq);
-	kfree(wq);
+	while (!try_to_grab_pending(work))
+		cpu_relax();
+	wait_on_work(work);
+	work_clear_pending(work);
 }
-EXPORT_SYMBOL_GPL(destroy_workqueue);
+EXPORT_SYMBOL_GPL(cancel_work_sync);
 
-static struct workqueue_struct *keventd_wq;
+/**
+ * cancel_rearming_delayed_work - reliably kill off a delayed work.
+ * @dwork: the delayed work struct
+ *
+ * It is possible to use this function if @dwork rearms itself via queue_work()
+ * or queue_delayed_work(). See also the comment for cancel_work_sync().
+ */
+void cancel_rearming_delayed_work(struct delayed_work *dwork)
+{
+	while (!del_timer(&dwork->timer) &&
+	       !try_to_grab_pending(&dwork->work))
+		cpu_relax();
+	wait_on_work(&dwork->work);
+	work_clear_pending(&dwork->work);
+}
+EXPORT_SYMBOL(cancel_rearming_delayed_work);
+
+static struct workqueue_struct *keventd_wq __read_mostly;
 
 /**
  * schedule_work - put work task in global workqueue
@@ -638,7 +575,7 @@
 	if (!works)
 		return -ENOMEM;
 
-	mutex_lock(&workqueue_mutex);
+	preempt_disable();		/* CPU hotplug */
 	for_each_online_cpu(cpu) {
 		struct work_struct *work = per_cpu_ptr(works, cpu);
 
@@ -646,7 +583,7 @@
 		set_bit(WORK_STRUCT_PENDING, work_data_bits(work));
 		__queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work);
 	}
-	mutex_unlock(&workqueue_mutex);
+	preempt_enable();
 	flush_workqueue(keventd_wq);
 	free_percpu(works);
 	return 0;
@@ -659,29 +596,6 @@
 EXPORT_SYMBOL(flush_scheduled_work);
 
 /**
- * cancel_rearming_delayed_workqueue - reliably kill off a delayed work whose handler rearms the delayed work.
- * @wq:   the controlling workqueue structure
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
-				       struct delayed_work *dwork)
-{
-	while (!cancel_delayed_work(dwork))
-		flush_workqueue(wq);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_workqueue);
-
-/**
- * cancel_rearming_delayed_work - reliably kill off a delayed keventd work whose handler rearms the delayed work.
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_work(struct delayed_work *dwork)
-{
-	cancel_rearming_delayed_workqueue(keventd_wq, dwork);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_work);
-
-/**
  * execute_in_process_context - reliably execute the routine with user context
  * @fn:		the function to execute
  * @ew:		guaranteed storage for the execute work structure (must
@@ -728,94 +642,209 @@
 
 }
 
-/* Take the work from this (downed) CPU. */
-static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+static struct cpu_workqueue_struct *
+init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-	struct list_head list;
-	struct work_struct *work;
 
-	spin_lock_irq(&cwq->lock);
-	list_replace_init(&cwq->worklist, &list);
+	cwq->wq = wq;
+	spin_lock_init(&cwq->lock);
+	INIT_LIST_HEAD(&cwq->worklist);
+	init_waitqueue_head(&cwq->more_work);
 
-	while (!list_empty(&list)) {
-		printk("Taking work for %s\n", wq->name);
-		work = list_entry(list.next,struct work_struct,entry);
-		list_del(&work->entry);
-		__queue_work(per_cpu_ptr(wq->cpu_wq, smp_processor_id()), work);
-	}
-	spin_unlock_irq(&cwq->lock);
+	return cwq;
 }
 
-/* We're holding the cpucontrol mutex here */
-static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
-				  unsigned long action,
-				  void *hcpu)
+static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 {
-	unsigned int hotcpu = (unsigned long)hcpu;
+	struct workqueue_struct *wq = cwq->wq;
+	const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
+	struct task_struct *p;
+
+	p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
+	/*
+	 * Nobody can add the work_struct to this cwq,
+	 *	if (caller is __create_workqueue)
+	 *		nobody should see this wq
+	 *	else // caller is CPU_UP_PREPARE
+	 *		cpu is not on cpu_online_map
+	 * so we can abort safely.
+	 */
+	if (IS_ERR(p))
+		return PTR_ERR(p);
+
+	cwq->thread = p;
+	cwq->should_stop = 0;
+
+	return 0;
+}
+
+static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+	struct task_struct *p = cwq->thread;
+
+	if (p != NULL) {
+		if (cpu >= 0)
+			kthread_bind(p, cpu);
+		wake_up_process(p);
+	}
+}
+
+struct workqueue_struct *__create_workqueue(const char *name,
+					    int singlethread, int freezeable)
+{
+	struct workqueue_struct *wq;
+	struct cpu_workqueue_struct *cwq;
+	int err = 0, cpu;
+
+	wq = kzalloc(sizeof(*wq), GFP_KERNEL);
+	if (!wq)
+		return NULL;
+
+	wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
+	if (!wq->cpu_wq) {
+		kfree(wq);
+		return NULL;
+	}
+
+	wq->name = name;
+	wq->singlethread = singlethread;
+	wq->freezeable = freezeable;
+	INIT_LIST_HEAD(&wq->list);
+
+	if (singlethread) {
+		cwq = init_cpu_workqueue(wq, singlethread_cpu);
+		err = create_workqueue_thread(cwq, singlethread_cpu);
+		start_workqueue_thread(cwq, -1);
+	} else {
+		mutex_lock(&workqueue_mutex);
+		list_add(&wq->list, &workqueues);
+
+		for_each_possible_cpu(cpu) {
+			cwq = init_cpu_workqueue(wq, cpu);
+			if (err || !cpu_online(cpu))
+				continue;
+			err = create_workqueue_thread(cwq, cpu);
+			start_workqueue_thread(cwq, cpu);
+		}
+		mutex_unlock(&workqueue_mutex);
+	}
+
+	if (err) {
+		destroy_workqueue(wq);
+		wq = NULL;
+	}
+	return wq;
+}
+EXPORT_SYMBOL_GPL(__create_workqueue);
+
+static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+	struct wq_barrier barr;
+	int alive = 0;
+
+	spin_lock_irq(&cwq->lock);
+	if (cwq->thread != NULL) {
+		insert_wq_barrier(cwq, &barr, 1);
+		cwq->should_stop = 1;
+		alive = 1;
+	}
+	spin_unlock_irq(&cwq->lock);
+
+	if (alive) {
+		wait_for_completion(&barr.done);
+
+		while (unlikely(cwq->thread != NULL))
+			cpu_relax();
+		/*
+		 * Wait until cwq->thread unlocks cwq->lock,
+		 * it won't touch *cwq after that.
+		 */
+		smp_rmb();
+		spin_unlock_wait(&cwq->lock);
+	}
+}
+
+/**
+ * destroy_workqueue - safely terminate a workqueue
+ * @wq: target workqueue
+ *
+ * Safely destroy a workqueue. All work currently pending will be done first.
+ */
+void destroy_workqueue(struct workqueue_struct *wq)
+{
+	const cpumask_t *cpu_map = wq_cpu_map(wq);
+	struct cpu_workqueue_struct *cwq;
+	int cpu;
+
+	mutex_lock(&workqueue_mutex);
+	list_del(&wq->list);
+	mutex_unlock(&workqueue_mutex);
+
+	for_each_cpu_mask(cpu, *cpu_map) {
+		cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+		cleanup_workqueue_thread(cwq, cpu);
+	}
+
+	free_percpu(wq->cpu_wq);
+	kfree(wq);
+}
+EXPORT_SYMBOL_GPL(destroy_workqueue);
+
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+						unsigned long action,
+						void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	struct cpu_workqueue_struct *cwq;
 	struct workqueue_struct *wq;
 
+	action &= ~CPU_TASKS_FROZEN;
+
 	switch (action) {
+	case CPU_LOCK_ACQUIRE:
+		mutex_lock(&workqueue_mutex);
+		return NOTIFY_OK;
+
+	case CPU_LOCK_RELEASE:
+		mutex_unlock(&workqueue_mutex);
+		return NOTIFY_OK;
+
 	case CPU_UP_PREPARE:
-		mutex_lock(&workqueue_mutex);
-		/* Create a new workqueue thread for it. */
-		list_for_each_entry(wq, &workqueues, list) {
-			if (!create_workqueue_thread(wq, hotcpu, 0)) {
-				printk("workqueue for %i failed\n", hotcpu);
-				return NOTIFY_BAD;
-			}
+		cpu_set(cpu, cpu_populated_map);
+	}
+
+	list_for_each_entry(wq, &workqueues, list) {
+		cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+
+		switch (action) {
+		case CPU_UP_PREPARE:
+			if (!create_workqueue_thread(cwq, cpu))
+				break;
+			printk(KERN_ERR "workqueue for %i failed\n", cpu);
+			return NOTIFY_BAD;
+
+		case CPU_ONLINE:
+			start_workqueue_thread(cwq, cpu);
+			break;
+
+		case CPU_UP_CANCELED:
+			start_workqueue_thread(cwq, -1);
+		case CPU_DEAD:
+			cleanup_workqueue_thread(cwq, cpu);
+			break;
 		}
-		break;
-
-	case CPU_ONLINE:
-		/* Kick off worker threads. */
-		list_for_each_entry(wq, &workqueues, list) {
-			struct cpu_workqueue_struct *cwq;
-
-			cwq = per_cpu_ptr(wq->cpu_wq, hotcpu);
-			kthread_bind(cwq->thread, hotcpu);
-			wake_up_process(cwq->thread);
-		}
-		mutex_unlock(&workqueue_mutex);
-		break;
-
-	case CPU_UP_CANCELED:
-		list_for_each_entry(wq, &workqueues, list) {
-			if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
-				continue;
-			/* Unbind so it can run. */
-			kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
-				     any_online_cpu(cpu_online_map));
-			cleanup_workqueue_thread(wq, hotcpu);
-		}
-		mutex_unlock(&workqueue_mutex);
-		break;
-
-	case CPU_DOWN_PREPARE:
-		mutex_lock(&workqueue_mutex);
-		break;
-
-	case CPU_DOWN_FAILED:
-		mutex_unlock(&workqueue_mutex);
-		break;
-
-	case CPU_DEAD:
-		list_for_each_entry(wq, &workqueues, list)
-			cleanup_workqueue_thread(wq, hotcpu);
-		list_for_each_entry(wq, &workqueues, list)
-			take_over_work(wq, hotcpu);
-		mutex_unlock(&workqueue_mutex);
-		break;
 	}
 
 	return NOTIFY_OK;
 }
 
-void init_workqueues(void)
+void __init init_workqueues(void)
 {
+	cpu_populated_map = cpu_online_map;
 	singlethread_cpu = first_cpu(cpu_possible_map);
+	cpu_singlethread_map = cpumask_of_cpu(singlethread_cpu);
 	hotcpu_notifier(workqueue_cpu_callback, 0);
 	keventd_wq = create_workqueue("events");
 	BUG_ON(!keventd_wq);
 }
-
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index d69ddbe..402eb4e 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1004,7 +1004,7 @@
        struct radix_tree_preload *rtp;
 
        /* Free per-cpu pool of perloaded nodes */
-       if (action == CPU_DEAD) {
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
                rtp = &per_cpu(radix_tree_preloads, cpu);
                while (rtp->nr) {
                        kmem_cache_free(radix_tree_node_cachep,
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index a4b730a..5b0d852 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -56,6 +56,7 @@
  * rs_init - Initialize a Reed-Solomon codec
  * @symsize:	symbol size, bits (1-8)
  * @gfpoly:	Field generator polynomial coefficients
+ * @gffunc:	Field generator function
  * @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)
@@ -63,8 +64,8 @@
  * 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)
+static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
+                                  int fcr, int prim, int nroots)
 {
 	struct rs_control *rs;
 	int i, j, sr, root, iprim;
@@ -82,6 +83,7 @@
 	rs->prim = prim;
 	rs->nroots = nroots;
 	rs->gfpoly = gfpoly;
+	rs->gffunc = gffunc;
 
 	/* Allocate the arrays */
 	rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
@@ -99,17 +101,26 @@
 	/* 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 (gfpoly) {
+		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;
+		}
+	} else {
+		sr = gffunc(0);
+		for (i = 0; i < rs->nn; i++) {
+			rs->index_of[sr] = i;
+			rs->alpha_to[i] = sr;
+			sr = gffunc(sr);
+		}
 	}
 	/* If it's not primitive, exit */
-	if(sr != 1)
+	if(sr != rs->alpha_to[0])
 		goto errpol;
 
 	/* Find prim-th root of 1, used in decoding */
@@ -173,18 +184,22 @@
 }
 
 /**
- * init_rs - Find a matching or allocate a new rs control structure
+ * init_rs_internal - 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;
+ *  @gffunc:	pointer to function to generate the next field element,
+ *		or the multiplicative identity element if given 0.  Used
+ *		instead of gfpoly if gfpoly is 0
  *  @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)
+static struct rs_control *init_rs_internal(int symsize, int gfpoly,
+                                           int (*gffunc)(int), int fcr,
+                                           int prim, int nroots)
 {
 	struct list_head	*tmp;
 	struct rs_control	*rs;
@@ -208,6 +223,8 @@
 			continue;
 		if (gfpoly != rs->gfpoly)
 			continue;
+		if (gffunc != rs->gffunc)
+			continue;
 		if (fcr != rs->fcr)
 			continue;
 		if (prim != rs->prim)
@@ -220,7 +237,7 @@
 	}
 
 	/* Create a new one */
-	rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
+	rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
 	if (rs) {
 		rs->users = 1;
 		list_add(&rs->list, &rslist);
@@ -230,6 +247,42 @@
 	return rs;
 }
 
+/**
+ * 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)
+{
+	return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+}
+
+/**
+ * init_rs_non_canonical - Find a matching or allocate a new rs control
+ *                         structure, for fields with non-canonical
+ *                         representation
+ *  @symsize:	the symbol size (number of bits)
+ *  @gffunc:	pointer to function to generate the next field element,
+ *		or the multiplicative identity element if given 0.  Used
+ *		instead of gfpoly if gfpoly is 0
+ *  @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_non_canonical(int symsize, int (*gffunc)(int),
+                                         int fcr, int prim, int nroots)
+{
+	return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+}
+
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
@@ -321,6 +374,7 @@
 #endif
 
 EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
 EXPORT_SYMBOL_GPL(free_rs);
 
 MODULE_LICENSE("GPL");
diff --git a/mm/Kconfig b/mm/Kconfig
index 1ac718f..a17da8b 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -166,5 +166,5 @@
 config NR_QUICK
 	int
 	depends on QUICKLIST
+	default "2" if SUPERH
 	default "1"
-
diff --git a/mm/filemap.c b/mm/filemap.c
index 9cbf4fe..7b48b2a 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -750,6 +750,7 @@
 	read_unlock_irq(&mapping->tree_lock);
 	return i;
 }
+EXPORT_SYMBOL(find_get_pages_contig);
 
 /**
  * find_get_pages_tag - find and return pages that match @tag
@@ -778,6 +779,7 @@
 	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
+EXPORT_SYMBOL(find_get_pages_tag);
 
 /**
  * grab_cache_page_nowait - returns locked page at given index in given cache
@@ -1782,7 +1784,7 @@
 retry:
 	page = __read_cache_page(mapping, index, filler, data);
 	if (IS_ERR(page))
-		goto out;
+		return page;
 	mark_page_accessed(page);
 	if (PageUptodate(page))
 		goto out;
@@ -1800,9 +1802,9 @@
 	err = filler(data, page);
 	if (err < 0) {
 		page_cache_release(page);
-		page = ERR_PTR(err);
+		return ERR_PTR(err);
 	}
- out:
+out:
 	mark_page_accessed(page);
 	return page;
 }
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index cbb3358..1b49dab 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -434,7 +434,6 @@
 	unsigned blocksize;
 	unsigned length;
 	struct page *page;
-	void *kaddr;
 
 	BUG_ON(!mapping->a_ops->get_xip_page);
 
@@ -458,11 +457,7 @@
 		else
 			return PTR_ERR(page);
 	}
-	kaddr = kmap_atomic(page, KM_USER0);
-	memset(kaddr + offset, 0, length);
-	kunmap_atomic(kaddr, KM_USER0);
-
-	flush_dcache_page(page);
+	zero_user_page(page, offset, length, KM_USER0);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 36db012..eb7180d 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -140,6 +140,8 @@
 	return page;
 
 fail:
+	if (vma->vm_flags & VM_MAYSHARE)
+		resv_huge_pages++;
 	spin_unlock(&hugetlb_lock);
 	return NULL;
 }
@@ -172,6 +174,17 @@
 }
 __setup("hugepages=", hugetlb_setup);
 
+static unsigned int cpuset_mems_nr(unsigned int *array)
+{
+	int node;
+	unsigned int nr = 0;
+
+	for_each_node_mask(node, cpuset_current_mems_allowed)
+		nr += array[node];
+
+	return nr;
+}
+
 #ifdef CONFIG_SYSCTL
 static void update_and_free_page(struct page *page)
 {
@@ -817,6 +830,26 @@
 	chg = region_chg(&inode->i_mapping->private_list, from, to);
 	if (chg < 0)
 		return chg;
+	/*
+	 * When cpuset is configured, it breaks the strict hugetlb page
+	 * reservation as the accounting is done on a global variable. Such
+	 * reservation is completely rubbish in the presence of cpuset because
+	 * the reservation is not checked against page availability for the
+	 * current cpuset. Application can still potentially OOM'ed by kernel
+	 * with lack of free htlb page in cpuset that the task is in.
+	 * Attempt to enforce strict accounting with cpuset is almost
+	 * impossible (or too ugly) because cpuset is too fluid that
+	 * task or memory node can be dynamically moved between cpusets.
+	 *
+	 * The change of semantics for shared hugetlb mapping with cpuset is
+	 * undesirable. However, in order to preserve some of the semantics,
+	 * we fall back to check against current free page availability as
+	 * a best attempt and hopefully to minimize the impact of changing
+	 * semantics that cpuset has.
+	 */
+	if (chg > cpuset_mems_nr(free_huge_pages_node))
+		return -ENOMEM;
+
 	ret = hugetlb_acct_memory(chg);
 	if (ret < 0)
 		return ret;
diff --git a/mm/mmap.c b/mm/mmap.c
index cc1f543..68b9ad2 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1720,7 +1720,7 @@
 
 /*
  * Split a vma into two pieces at address 'addr', a new vma is allocated
- * either for the first part or the the tail.
+ * either for the first part or the tail.
  */
 int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
 	      unsigned long addr, int new_below)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6fd0b74..f9b5d6d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -691,43 +691,26 @@
 
 #ifdef CONFIG_NUMA
 /*
- * Called from the slab reaper to drain pagesets on a particular node that
- * belongs to the currently executing processor.
+ * Called from the vmstat counter updater to drain pagesets of this
+ * currently executing processor on remote nodes after they have
+ * expired.
+ *
  * Note that this function must be called with the thread pinned to
  * a single processor.
  */
-void drain_node_pages(int nodeid)
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
 {
-	int i;
-	enum zone_type z;
 	unsigned long flags;
+	int to_drain;
 
-	for (z = 0; z < MAX_NR_ZONES; z++) {
-		struct zone *zone = NODE_DATA(nodeid)->node_zones + z;
-		struct per_cpu_pageset *pset;
-
-		if (!populated_zone(zone))
-			continue;
-
-		pset = zone_pcp(zone, smp_processor_id());
-		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-			struct per_cpu_pages *pcp;
-
-			pcp = &pset->pcp[i];
-			if (pcp->count) {
-				int to_drain;
-
-				local_irq_save(flags);
-				if (pcp->count >= pcp->batch)
-					to_drain = pcp->batch;
-				else
-					to_drain = pcp->count;
-				free_pages_bulk(zone, to_drain, &pcp->list, 0);
-				pcp->count -= to_drain;
-				local_irq_restore(flags);
-			}
-		}
-	}
+	local_irq_save(flags);
+	if (pcp->count >= pcp->batch)
+		to_drain = pcp->batch;
+	else
+		to_drain = pcp->count;
+	free_pages_bulk(zone, to_drain, &pcp->list, 0);
+	pcp->count -= to_drain;
+	local_irq_restore(flags);
 }
 #endif
 
@@ -2148,11 +2131,14 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		if (process_zones(cpu))
 			ret = NOTIFY_BAD;
 		break;
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		free_zone_pagesets(cpu);
 		break;
 	default:
@@ -3012,7 +2998,7 @@
 {
 	int cpu = (unsigned long)hcpu;
 
-	if (action == CPU_DEAD) {
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
 		local_irq_disable();
 		__drain_pages(cpu);
 		vm_events_fold_cpu(cpu);
diff --git a/mm/slab.c b/mm/slab.c
index acda7e2..944b205 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -928,12 +928,6 @@
 {
 	int node = __get_cpu_var(reap_node);
 
-	/*
-	 * Also drain per cpu pages on remote zones
-	 */
-	if (node != numa_node_id())
-		drain_node_pages(node);
-
 	node = next_node(node, node_online_map);
 	if (unlikely(node >= MAX_NUMNODES))
 		node = first_node(node_online_map);
@@ -1186,8 +1180,11 @@
 	int memsize = sizeof(struct kmem_list3);
 
 	switch (action) {
-	case CPU_UP_PREPARE:
+	case CPU_LOCK_ACQUIRE:
 		mutex_lock(&cache_chain_mutex);
+		break;
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		/*
 		 * We need to do this right in the beginning since
 		 * alloc_arraycache's are going to use this list.
@@ -1274,17 +1271,28 @@
 		}
 		break;
 	case CPU_ONLINE:
-		mutex_unlock(&cache_chain_mutex);
+	case CPU_ONLINE_FROZEN:
 		start_cpu_timer(cpu);
 		break;
 #ifdef CONFIG_HOTPLUG_CPU
-	case CPU_DOWN_PREPARE:
-		mutex_lock(&cache_chain_mutex);
-		break;
-	case CPU_DOWN_FAILED:
-		mutex_unlock(&cache_chain_mutex);
-		break;
+  	case CPU_DOWN_PREPARE:
+  	case CPU_DOWN_PREPARE_FROZEN:
+		/*
+		 * Shutdown cache reaper. Note that the cache_chain_mutex is
+		 * held so that if cache_reap() is invoked it cannot do
+		 * anything expensive but will only modify reap_work
+		 * and reschedule the timer.
+		*/
+		cancel_rearming_delayed_work(&per_cpu(reap_work, cpu));
+		/* Now the cache_reaper is guaranteed to be not running. */
+		per_cpu(reap_work, cpu).work.func = NULL;
+  		break;
+  	case CPU_DOWN_FAILED:
+  	case CPU_DOWN_FAILED_FROZEN:
+		start_cpu_timer(cpu);
+  		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		/*
 		 * Even if all the cpus of a node are down, we don't free the
 		 * kmem_list3 of any cache. This to avoid a race between
@@ -1296,6 +1304,7 @@
 		/* fall thru */
 #endif
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 		list_for_each_entry(cachep, &cache_chain, next) {
 			struct array_cache *nc;
 			struct array_cache *shared;
@@ -1354,6 +1363,8 @@
 				continue;
 			drain_freelist(cachep, l3, l3->free_objects);
 		}
+		break;
+	case CPU_LOCK_RELEASE:
 		mutex_unlock(&cache_chain_mutex);
 		break;
 	}
@@ -3742,7 +3753,6 @@
 
 /**
  * krealloc - reallocate memory. The contents will remain unchanged.
- *
  * @p: object to reallocate memory for.
  * @new_size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
@@ -4140,7 +4150,6 @@
 	check_irq_on();
 	mutex_unlock(&cache_chain_mutex);
 	next_reap_node();
-	refresh_cpu_vm_stats(smp_processor_id());
 out:
 	/* Set up the next iteration */
 	schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC));
diff --git a/mm/slub.c b/mm/slub.c
index 5db3da5..bd2efae 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -66,11 +66,11 @@
  * SLUB assigns one slab for allocation to each processor.
  * Allocations only occur from these slabs called cpu slabs.
  *
- * Slabs with free elements are kept on a partial list.
- * There is no list for full slabs. If an object in a full slab is
+ * Slabs with free elements are kept on a partial list and during regular
+ * operations no list for full slabs is used. If an object in a full slab is
  * freed then the slab will show up again on the partial lists.
- * Otherwise there is no need to track full slabs unless we have to
- * track full slabs for debugging purposes.
+ * We track full slabs for debugging purposes though because otherwise we
+ * cannot scan all objects.
  *
  * Slabs are freed when they become empty. Teardown and setup is
  * minimal so we rely on the page allocators per cpu caches for
@@ -87,13 +87,36 @@
  * 			the fast path.
  */
 
+static inline int SlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+	return PageError(page);
+#else
+	return 0;
+#endif
+}
+
+static inline void SetSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+	SetPageError(page);
+#endif
+}
+
+static inline void ClearSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+	ClearPageError(page);
+#endif
+}
+
 /*
  * Issues still to be resolved:
  *
  * - The per cpu array is updated for each new slab and and is a remote
  *   cacheline for most nodes. This could become a bouncing cacheline given
- *   enough frequent updates. There are 16 pointers in a cacheline.so at
- *   max 16 cpus could compete. Likely okay.
+ *   enough frequent updates. There are 16 pointers in a cacheline, so at
+ *   max 16 cpus could compete for the cacheline which may be okay.
  *
  * - Support PAGE_ALLOC_DEBUG. Should be easy to do.
  *
@@ -137,6 +160,7 @@
 
 #define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
 				SLAB_POISON | SLAB_STORE_USER)
+
 /*
  * Set of flags that will prevent slab merging
  */
@@ -157,6 +181,11 @@
 /* Internal SLUB flags */
 #define __OBJECT_POISON 0x80000000	/* Poison object */
 
+/* Not all arches define cache_line_size */
+#ifndef cache_line_size
+#define cache_line_size()	L1_CACHE_BYTES
+#endif
+
 static int kmem_size = sizeof(struct kmem_cache);
 
 #ifdef CONFIG_SMP
@@ -166,7 +195,7 @@
 static enum {
 	DOWN,		/* No slab functionality available */
 	PARTIAL,	/* kmem_cache_open() works but kmalloc does not */
-	UP,		/* Everything works */
+	UP,		/* Everything works but does not show up in sysfs */
 	SYSFS		/* Sysfs up */
 } slab_state = DOWN;
 
@@ -174,7 +203,19 @@
 static DECLARE_RWSEM(slub_lock);
 LIST_HEAD(slab_caches);
 
-#ifdef CONFIG_SYSFS
+/*
+ * Tracking user of a slab.
+ */
+struct track {
+	void *addr;		/* Called from address */
+	int cpu;		/* Was running on cpu */
+	int pid;		/* Pid context */
+	unsigned long when;	/* When did the operation occur */
+};
+
+enum track_item { TRACK_ALLOC, TRACK_FREE };
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
 static int sysfs_slab_add(struct kmem_cache *);
 static int sysfs_slab_alias(struct kmem_cache *, const char *);
 static void sysfs_slab_remove(struct kmem_cache *);
@@ -202,6 +243,63 @@
 #endif
 }
 
+static inline int check_valid_pointer(struct kmem_cache *s,
+				struct page *page, const void *object)
+{
+	void *base;
+
+	if (!object)
+		return 1;
+
+	base = page_address(page);
+	if (object < base || object >= base + s->objects * s->size ||
+		(object - base) % s->size) {
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Slow version of get and set free pointer.
+ *
+ * This version requires touching the cache lines of kmem_cache which
+ * we avoid to do in the fast alloc free paths. There we obtain the offset
+ * from the page struct.
+ */
+static inline void *get_freepointer(struct kmem_cache *s, void *object)
+{
+	return *(void **)(object + s->offset);
+}
+
+static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+{
+	*(void **)(object + s->offset) = fp;
+}
+
+/* Loop over all objects in a slab */
+#define for_each_object(__p, __s, __addr) \
+	for (__p = (__addr); __p < (__addr) + (__s)->objects * (__s)->size;\
+			__p += (__s)->size)
+
+/* Scan freelist */
+#define for_each_free_object(__p, __s, __free) \
+	for (__p = (__free); __p; __p = get_freepointer((__s), __p))
+
+/* Determine object index from a given position */
+static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
+{
+	return (p - addr) / s->size;
+}
+
+#ifdef CONFIG_SLUB_DEBUG
+/*
+ * Debug settings:
+ */
+static int slub_debug;
+
+static char *slub_debug_slabs;
+
 /*
  * Object debugging
  */
@@ -237,35 +335,6 @@
 	}
 }
 
-/*
- * Slow version of get and set free pointer.
- *
- * This requires touching the cache lines of kmem_cache.
- * The offset can also be obtained from the page. In that
- * case it is in the cacheline that we already need to touch.
- */
-static void *get_freepointer(struct kmem_cache *s, void *object)
-{
-	return *(void **)(object + s->offset);
-}
-
-static void set_freepointer(struct kmem_cache *s, void *object, void *fp)
-{
-	*(void **)(object + s->offset) = fp;
-}
-
-/*
- * Tracking user of a slab.
- */
-struct track {
-	void *addr;		/* Called from address */
-	int cpu;		/* Was running on cpu */
-	int pid;		/* Pid context */
-	unsigned long when;	/* When did the operation occur */
-};
-
-enum track_item { TRACK_ALLOC, TRACK_FREE };
-
 static struct track *get_track(struct kmem_cache *s, void *object,
 	enum track_item alloc)
 {
@@ -400,24 +469,6 @@
 	return 1;
 }
 
-
-static int check_valid_pointer(struct kmem_cache *s, struct page *page,
-					 void *object)
-{
-	void *base;
-
-	if (!object)
-		return 1;
-
-	base = page_address(page);
-	if (object < base || object >= base + s->objects * s->size ||
-		(object - base) % s->size) {
-		return 0;
-	}
-
-	return 1;
-}
-
 /*
  * Object layout:
  *
@@ -425,26 +476,34 @@
  * 	Bytes of the object to be managed.
  * 	If the freepointer may overlay the object then the free
  * 	pointer is the first word of the object.
+ *
  * 	Poisoning uses 0x6b (POISON_FREE) and the last byte is
  * 	0xa5 (POISON_END)
  *
  * object + s->objsize
  * 	Padding to reach word boundary. This is also used for Redzoning.
- * 	Padding is extended to word size if Redzoning is enabled
- * 	and objsize == inuse.
+ * 	Padding is extended by another word if Redzoning is enabled and
+ * 	objsize == inuse.
+ *
  * 	We fill with 0xbb (RED_INACTIVE) for inactive objects and with
  * 	0xcc (RED_ACTIVE) for objects in use.
  *
  * object + s->inuse
+ * 	Meta data starts here.
+ *
  * 	A. Free pointer (if we cannot overwrite object on free)
  * 	B. Tracking data for SLAB_STORE_USER
- * 	C. Padding to reach required alignment boundary
- * 		Padding is done using 0x5a (POISON_INUSE)
+ * 	C. Padding to reach required alignment boundary or at mininum
+ * 		one word if debuggin is on to be able to detect writes
+ * 		before the word boundary.
+ *
+ *	Padding is done using 0x5a (POISON_INUSE)
  *
  * object + s->size
+ * 	Nothing is used beyond s->size.
  *
- * If slabcaches are merged then the objsize and inuse boundaries are to
- * be ignored. And therefore no slab options that rely on these boundaries
+ * If slabcaches are merged then the objsize and inuse boundaries are mostly
+ * ignored. And therefore no slab options that rely on these boundaries
  * may be used with merged slabcaches.
  */
 
@@ -570,8 +629,7 @@
 		/*
 		 * No choice but to zap it and thus loose the remainder
 		 * of the free objects in this slab. May cause
-		 * another error because the object count maybe
-		 * wrong now.
+		 * another error because the object count is now wrong.
 		 */
 		set_freepointer(s, p, NULL);
 		return 0;
@@ -611,9 +669,8 @@
 }
 
 /*
- * Determine if a certain object on a page is on the freelist and
- * therefore free. Must hold the slab lock for cpu slabs to
- * guarantee that the chains are consistent.
+ * Determine if a certain object on a page is on the freelist. Must hold the
+ * slab lock to guarantee that the chains are in a consistent state.
  */
 static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 {
@@ -659,7 +716,7 @@
 }
 
 /*
- * Tracking of fully allocated slabs for debugging
+ * Tracking of fully allocated slabs for debugging purposes.
  */
 static void add_full(struct kmem_cache_node *n, struct page *page)
 {
@@ -710,7 +767,7 @@
 		/*
 		 * If this is a slab page then lets do the best we can
 		 * to avoid issues in the future. Marking all objects
-		 * as used avoids touching the remainder.
+		 * as used avoids touching the remaining objects.
 		 */
 		printk(KERN_ERR "@@@ SLUB: %s slab 0x%p. Marking all objects used.\n",
 			s->name, page);
@@ -764,6 +821,113 @@
 	return 0;
 }
 
+static void trace(struct kmem_cache *s, struct page *page, void *object, int alloc)
+{
+	if (s->flags & SLAB_TRACE) {
+		printk(KERN_INFO "TRACE %s %s 0x%p inuse=%d fp=0x%p\n",
+			s->name,
+			alloc ? "alloc" : "free",
+			object, page->inuse,
+			page->freelist);
+
+		if (!alloc)
+			print_section("Object", (void *)object, s->objsize);
+
+		dump_stack();
+	}
+}
+
+static int __init setup_slub_debug(char *str)
+{
+	if (!str || *str != '=')
+		slub_debug = DEBUG_DEFAULT_FLAGS;
+	else {
+		str++;
+		if (*str == 0 || *str == ',')
+			slub_debug = DEBUG_DEFAULT_FLAGS;
+		else
+		for( ;*str && *str != ','; str++)
+			switch (*str) {
+			case 'f' : case 'F' :
+				slub_debug |= SLAB_DEBUG_FREE;
+				break;
+			case 'z' : case 'Z' :
+				slub_debug |= SLAB_RED_ZONE;
+				break;
+			case 'p' : case 'P' :
+				slub_debug |= SLAB_POISON;
+				break;
+			case 'u' : case 'U' :
+				slub_debug |= SLAB_STORE_USER;
+				break;
+			case 't' : case 'T' :
+				slub_debug |= SLAB_TRACE;
+				break;
+			default:
+				printk(KERN_ERR "slub_debug option '%c' "
+					"unknown. skipped\n",*str);
+			}
+	}
+
+	if (*str == ',')
+		slub_debug_slabs = str + 1;
+	return 1;
+}
+
+__setup("slub_debug", setup_slub_debug);
+
+static void kmem_cache_open_debug_check(struct kmem_cache *s)
+{
+	/*
+	 * The page->offset field is only 16 bit wide. This is an offset
+	 * in units of words from the beginning of an object. If the slab
+	 * size is bigger then we cannot move the free pointer behind the
+	 * object anymore.
+	 *
+	 * On 32 bit platforms the limit is 256k. On 64bit platforms
+	 * the limit is 512k.
+	 *
+	 * Debugging or ctor/dtors may create a need to move the free
+	 * pointer. Fail if this happens.
+	 */
+	if (s->size >= 65535 * sizeof(void *)) {
+		BUG_ON(s->flags & (SLAB_RED_ZONE | SLAB_POISON |
+				SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
+		BUG_ON(s->ctor || s->dtor);
+	}
+	else
+		/*
+		 * Enable debugging if selected on the kernel commandline.
+		 */
+		if (slub_debug && (!slub_debug_slabs ||
+		    strncmp(slub_debug_slabs, s->name,
+		    	strlen(slub_debug_slabs)) == 0))
+				s->flags |= slub_debug;
+}
+#else
+
+static inline int alloc_object_checks(struct kmem_cache *s,
+		struct page *page, void *object) { return 0; }
+
+static inline int free_object_checks(struct kmem_cache *s,
+		struct page *page, void *object) { return 0; }
+
+static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+static inline void remove_full(struct kmem_cache *s, struct page *page) {}
+static inline void trace(struct kmem_cache *s, struct page *page,
+			void *object, int alloc) {}
+static inline void init_object(struct kmem_cache *s,
+			void *object, int active) {}
+static inline void init_tracking(struct kmem_cache *s, void *object) {}
+static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
+			{ return 1; }
+static inline int check_object(struct kmem_cache *s, struct page *page,
+			void *object, int active) { return 1; }
+static inline void set_track(struct kmem_cache *s, void *object,
+			enum track_item alloc, void *addr) {}
+static inline void kmem_cache_open_debug_check(struct kmem_cache *s) {}
+#define slub_debug 0
+#endif
 /*
  * Slab allocation and freeing
  */
@@ -797,7 +961,7 @@
 static void setup_object(struct kmem_cache *s, struct page *page,
 				void *object)
 {
-	if (PageError(page)) {
+	if (SlabDebug(page)) {
 		init_object(s, object, 0);
 		init_tracking(s, object);
 	}
@@ -832,7 +996,7 @@
 	page->flags |= 1 << PG_slab;
 	if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
 			SLAB_STORE_USER | SLAB_TRACE))
-		page->flags |= 1 << PG_error;
+		SetSlabDebug(page);
 
 	start = page_address(page);
 	end = start + s->objects * s->size;
@@ -841,7 +1005,7 @@
 		memset(start, POISON_INUSE, PAGE_SIZE << s->order);
 
 	last = start;
-	for (p = start + s->size; p < end; p += s->size) {
+	for_each_object(p, s, start) {
 		setup_object(s, page, last);
 		set_freepointer(s, last, p);
 		last = p;
@@ -861,13 +1025,11 @@
 {
 	int pages = 1 << s->order;
 
-	if (unlikely(PageError(page) || s->dtor)) {
-		void *start = page_address(page);
-		void *end = start + (pages << PAGE_SHIFT);
+	if (unlikely(SlabDebug(page) || s->dtor)) {
 		void *p;
 
 		slab_pad_check(s, page);
-		for (p = start; p <= end - s->size; p += s->size) {
+		for_each_object(p, s, page_address(page)) {
 			if (s->dtor)
 				s->dtor(p, s, 0);
 			check_object(s, page, p, 0);
@@ -910,7 +1072,8 @@
 
 	atomic_long_dec(&n->nr_slabs);
 	reset_page_mapcount(page);
-	page->flags &= ~(1 << PG_slab | 1 << PG_error);
+	ClearSlabDebug(page);
+	__ClearPageSlab(page);
 	free_slab(s, page);
 }
 
@@ -966,9 +1129,9 @@
 }
 
 /*
- * Lock page and remove it from the partial list
+ * Lock slab and remove from the partial list.
  *
- * Must hold list_lock
+ * Must hold list_lock.
  */
 static int lock_and_del_slab(struct kmem_cache_node *n, struct page *page)
 {
@@ -981,7 +1144,7 @@
 }
 
 /*
- * Try to get a partial slab from a specific node
+ * Try to allocate a partial slab from a specific node.
  */
 static struct page *get_partial_node(struct kmem_cache_node *n)
 {
@@ -990,7 +1153,8 @@
 	/*
 	 * Racy check. If we mistakenly see no partial slabs then we
 	 * just allocate an empty slab. If we mistakenly try to get a
-	 * partial slab then get_partials() will return NULL.
+	 * partial slab and there is none available then get_partials()
+	 * will return NULL.
 	 */
 	if (!n || !n->nr_partial)
 		return NULL;
@@ -1006,8 +1170,7 @@
 }
 
 /*
- * Get a page from somewhere. Search in increasing NUMA
- * distances.
+ * Get a page from somewhere. Search in increasing NUMA distances.
  */
 static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
 {
@@ -1017,24 +1180,22 @@
 	struct page *page;
 
 	/*
-	 * The defrag ratio allows to configure the tradeoffs between
-	 * inter node defragmentation and node local allocations.
-	 * A lower defrag_ratio increases the tendency to do local
-	 * allocations instead of scanning throught the partial
-	 * lists on other nodes.
+	 * The defrag ratio allows a configuration of the tradeoffs between
+	 * inter node defragmentation and node local allocations. A lower
+	 * defrag_ratio increases the tendency to do local allocations
+	 * instead of attempting to obtain partial slabs from other nodes.
 	 *
-	 * If defrag_ratio is set to 0 then kmalloc() always
-	 * returns node local objects. If its higher then kmalloc()
-	 * may return off node objects in order to avoid fragmentation.
-	 *
-	 * A higher ratio means slabs may be taken from other nodes
-	 * thus reducing the number of partial slabs on those nodes.
+	 * If the defrag_ratio is set to 0 then kmalloc() always
+	 * returns node local objects. If the ratio is higher then kmalloc()
+	 * may return off node objects because partial slabs are obtained
+	 * from other nodes and filled up.
 	 *
 	 * If /sys/slab/xx/defrag_ratio is set to 100 (which makes
-	 * defrag_ratio = 1000) then every (well almost) allocation
-	 * will first attempt to defrag slab caches on other nodes. This
-	 * means scanning over all nodes to look for partial slabs which
-	 * may be a bit expensive to do on every slab allocation.
+	 * defrag_ratio = 1000) then every (well almost) allocation will
+	 * first attempt to defrag slab caches on other nodes. This means
+	 * scanning over all nodes to look for partial slabs which may be
+	 * expensive if we do it every time we are trying to find a slab
+	 * with available objects.
 	 */
 	if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
 		return NULL;
@@ -1087,18 +1248,19 @@
 
 		if (page->freelist)
 			add_partial(n, page);
-		else if (PageError(page) && (s->flags & SLAB_STORE_USER))
+		else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER))
 			add_full(n, page);
 		slab_unlock(page);
 
 	} else {
 		if (n->nr_partial < MIN_PARTIAL) {
 			/*
-			 * Adding an empty page to the partial slabs in order
-			 * to avoid page allocator overhead. This page needs to
-			 * come after all the others that are not fully empty
-			 * in order to make sure that we do maximum
-			 * defragmentation.
+			 * Adding an empty slab to the partial slabs in order
+			 * to avoid page allocator overhead. This slab needs
+			 * to come after the other slabs with objects in
+			 * order to fill them up. That way the size of the
+			 * partial list stays small. kmem_cache_shrink can
+			 * reclaim empty slabs from the partial list.
 			 */
 			add_partial_tail(n, page);
 			slab_unlock(page);
@@ -1166,11 +1328,11 @@
  * 1. The page struct
  * 2. The first cacheline of the object to be allocated.
  *
- * The only cache lines that are read (apart from code) is the
+ * The only other cache lines that are read (apart from code) is the
  * per cpu array in the kmem_cache struct.
  *
  * Fastpath is not possible if we need to get a new slab or have
- * debugging enabled (which means all slabs are marked with PageError)
+ * debugging enabled (which means all slabs are marked with SlabDebug)
  */
 static void *slab_alloc(struct kmem_cache *s,
 				gfp_t gfpflags, int node, void *addr)
@@ -1193,7 +1355,7 @@
 	object = page->freelist;
 	if (unlikely(!object))
 		goto another_slab;
-	if (unlikely(PageError(page)))
+	if (unlikely(SlabDebug(page)))
 		goto debug;
 
 have_object:
@@ -1220,9 +1382,11 @@
 		cpu = smp_processor_id();
 		if (s->cpu_slab[cpu]) {
 			/*
-			 * Someone else populated the cpu_slab while we enabled
-			 * interrupts, or we have got scheduled on another cpu.
-			 * The page may not be on the requested node.
+			 * Someone else populated the cpu_slab while we
+			 * enabled interrupts, or we have gotten scheduled
+			 * on another cpu. The page may not be on the
+			 * requested node even if __GFP_THISNODE was
+			 * specified. So we need to recheck.
 			 */
 			if (node == -1 ||
 				page_to_nid(s->cpu_slab[cpu]) == node) {
@@ -1235,7 +1399,7 @@
 				slab_lock(page);
 				goto redo;
 			}
-			/* Dump the current slab */
+			/* New slab does not fit our expectations */
 			flush_slab(s, s->cpu_slab[cpu], cpu);
 		}
 		slab_lock(page);
@@ -1248,12 +1412,7 @@
 		goto another_slab;
 	if (s->flags & SLAB_STORE_USER)
 		set_track(s, object, TRACK_ALLOC, addr);
-	if (s->flags & SLAB_TRACE) {
-		printk(KERN_INFO "TRACE %s alloc 0x%p inuse=%d fp=0x%p\n",
-			s->name, object, page->inuse,
-			page->freelist);
-		dump_stack();
-	}
+	trace(s, page, object, 1);
 	init_object(s, object, 1);
 	goto have_object;
 }
@@ -1276,7 +1435,8 @@
  * The fastpath only writes the cacheline of the page struct and the first
  * cacheline of the object.
  *
- * No special cachelines need to be read
+ * We read the cpu_slab cacheline to check if the slab is the per cpu
+ * slab for this processor.
  */
 static void slab_free(struct kmem_cache *s, struct page *page,
 					void *x, void *addr)
@@ -1288,7 +1448,7 @@
 	local_irq_save(flags);
 	slab_lock(page);
 
-	if (unlikely(PageError(page)))
+	if (unlikely(SlabDebug(page)))
 		goto debug;
 checks_ok:
 	prior = object[page->offset] = page->freelist;
@@ -1321,7 +1481,7 @@
 slab_empty:
 	if (prior)
 		/*
-		 * Slab on the partial list.
+		 * Slab still on the partial list.
 		 */
 		remove_partial(s, page);
 
@@ -1337,13 +1497,7 @@
 		remove_full(s, page);
 	if (s->flags & SLAB_STORE_USER)
 		set_track(s, x, TRACK_FREE, addr);
-	if (s->flags & SLAB_TRACE) {
-		printk(KERN_INFO "TRACE %s free 0x%p inuse=%d fp=0x%p\n",
-			s->name, object, page->inuse,
-			page->freelist);
-		print_section("Object", (void *)object, s->objsize);
-		dump_stack();
-	}
+	trace(s, page, object, 0);
 	init_object(s, object, 0);
 	goto checks_ok;
 }
@@ -1370,22 +1524,16 @@
 }
 
 /*
- * kmem_cache_open produces objects aligned at "size" and the first object
- * is placed at offset 0 in the slab (We have no metainformation on the
- * slab, all slabs are in essence "off slab").
- *
- * In order to get the desired alignment one just needs to align the
- * size.
+ * Object placement in a slab is made very easy because we always start at
+ * offset 0. If we tune the size of the object to the alignment then we can
+ * get the required alignment by putting one properly sized object after
+ * another.
  *
  * Notice that the allocation order determines the sizes of the per cpu
  * caches. Each processor has always one slab available for allocations.
  * Increasing the allocation order reduces the number of times that slabs
- * must be moved on and off the partial lists and therefore may influence
+ * must be moved on and off the partial lists and is therefore a factor in
  * locking overhead.
- *
- * The offset is used to relocate the free list link in each object. It is
- * therefore possible to move the free list link behind the object. This
- * is necessary for RCU to work properly and also useful for debugging.
  */
 
 /*
@@ -1396,76 +1544,110 @@
  */
 static int slub_min_order;
 static int slub_max_order = DEFAULT_MAX_ORDER;
-
-/*
- * Minimum number of objects per slab. This is necessary in order to
- * reduce locking overhead. Similar to the queue size in SLAB.
- */
 static int slub_min_objects = DEFAULT_MIN_OBJECTS;
 
 /*
  * Merge control. If this is set then no merging of slab caches will occur.
+ * (Could be removed. This was introduced to pacify the merge skeptics.)
  */
 static int slub_nomerge;
 
 /*
- * Debug settings:
- */
-static int slub_debug;
-
-static char *slub_debug_slabs;
-
-/*
  * Calculate the order of allocation given an slab object size.
  *
- * The order of allocation has significant impact on other elements
- * of the system. Generally order 0 allocations should be preferred
- * since they do not cause fragmentation in the page allocator. Larger
- * objects may have problems with order 0 because there may be too much
- * space left unused in a slab. We go to a higher order if more than 1/8th
- * of the slab would be wasted.
+ * The order of allocation has significant impact on performance and other
+ * system components. Generally order 0 allocations should be preferred since
+ * order 0 does not cause fragmentation in the page allocator. Larger objects
+ * be problematic to put into order 0 slabs because there may be too much
+ * unused space left. We go to a higher order if more than 1/8th of the slab
+ * would be wasted.
  *
- * In order to reach satisfactory performance we must ensure that
- * a minimum number of objects is in one slab. Otherwise we may
- * generate too much activity on the partial lists. This is less a
- * concern for large slabs though. slub_max_order specifies the order
- * where we begin to stop considering the number of objects in a slab.
+ * In order to reach satisfactory performance we must ensure that a minimum
+ * number of objects is in one slab. Otherwise we may generate too much
+ * activity on the partial lists which requires taking the list_lock. This is
+ * less a concern for large slabs though which are rarely used.
  *
- * Higher order allocations also allow the placement of more objects
- * in a slab and thereby reduce object handling overhead. If the user
- * has requested a higher mininum order then we start with that one
- * instead of zero.
+ * slub_max_order specifies the order where we begin to stop considering the
+ * number of objects in a slab as critical. If we reach slub_max_order then
+ * we try to keep the page order as low as possible. So we accept more waste
+ * of space in favor of a small page order.
+ *
+ * Higher order allocations also allow the placement of more objects in a
+ * slab and thereby reduce object handling overhead. If the user has
+ * requested a higher mininum order then we start with that one instead of
+ * the smallest order which will fit the object.
  */
-static int calculate_order(int size)
+static inline int slab_order(int size, int min_objects,
+				int max_order, int fract_leftover)
 {
 	int order;
 	int rem;
 
-	for (order = max(slub_min_order, fls(size - 1) - PAGE_SHIFT);
-			order < MAX_ORDER; order++) {
+	for (order = max(slub_min_order,
+				fls(min_objects * size - 1) - PAGE_SHIFT);
+			order <= max_order; order++) {
+
 		unsigned long slab_size = PAGE_SIZE << order;
 
-		if (slub_max_order > order &&
-				slab_size < slub_min_objects * size)
-			continue;
-
-		if (slab_size < size)
+		if (slab_size < min_objects * size)
 			continue;
 
 		rem = slab_size % size;
 
-		if (rem <= (PAGE_SIZE << order) / 8)
+		if (rem <= slab_size / fract_leftover)
 			break;
 
 	}
-	if (order >= MAX_ORDER)
-		return -E2BIG;
+
 	return order;
 }
 
+static inline int calculate_order(int size)
+{
+	int order;
+	int min_objects;
+	int fraction;
+
+	/*
+	 * Attempt to find best configuration for a slab. This
+	 * works by first attempting to generate a layout with
+	 * the best configuration and backing off gradually.
+	 *
+	 * First we reduce the acceptable waste in a slab. Then
+	 * we reduce the minimum objects required in a slab.
+	 */
+	min_objects = slub_min_objects;
+	while (min_objects > 1) {
+		fraction = 8;
+		while (fraction >= 4) {
+			order = slab_order(size, min_objects,
+						slub_max_order, fraction);
+			if (order <= slub_max_order)
+				return order;
+			fraction /= 2;
+		}
+		min_objects /= 2;
+	}
+
+	/*
+	 * We were unable to place multiple objects in a slab. Now
+	 * lets see if we can place a single object there.
+	 */
+	order = slab_order(size, 1, slub_max_order, 1);
+	if (order <= slub_max_order)
+		return order;
+
+	/*
+	 * Doh this slab cannot be placed using slub_max_order.
+	 */
+	order = slab_order(size, 1, MAX_ORDER, 1);
+	if (order <= MAX_ORDER)
+		return order;
+	return -ENOSYS;
+}
+
 /*
- * Function to figure out which alignment to use from the
- * various ways of specifying it.
+ * Figure out what the alignment of the objects will be.
  */
 static unsigned long calculate_alignment(unsigned long flags,
 		unsigned long align, unsigned long size)
@@ -1480,8 +1662,8 @@
 	 * then use it.
 	 */
 	if ((flags & SLAB_HWCACHE_ALIGN) &&
-			size > L1_CACHE_BYTES / 2)
-		return max_t(unsigned long, align, L1_CACHE_BYTES);
+			size > cache_line_size() / 2)
+		return max_t(unsigned long, align, cache_line_size());
 
 	if (align < ARCH_SLAB_MINALIGN)
 		return ARCH_SLAB_MINALIGN;
@@ -1619,22 +1801,23 @@
 	 */
 	size = ALIGN(size, sizeof(void *));
 
+#ifdef CONFIG_SLUB_DEBUG
 	/*
-	 * If we are redzoning then check if there is some space between the
+	 * If we are Redzoning then check if there is some space between the
 	 * end of the object and the free pointer. If not then add an
-	 * additional word, so that we can establish a redzone between
-	 * the object and the freepointer to be able to check for overwrites.
+	 * additional word to have some bytes to store Redzone information.
 	 */
 	if ((flags & SLAB_RED_ZONE) && size == s->objsize)
 		size += sizeof(void *);
+#endif
 
 	/*
-	 * With that we have determined how much of the slab is in actual
-	 * use by the object. This is the potential offset to the free
-	 * pointer.
+	 * With that we have determined the number of bytes in actual use
+	 * by the object. This is the potential offset to the free pointer.
 	 */
 	s->inuse = size;
 
+#ifdef CONFIG_SLUB_DEBUG
 	if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) ||
 		s->ctor || s->dtor)) {
 		/*
@@ -1656,7 +1839,7 @@
 		 */
 		size += 2 * sizeof(struct track);
 
-	if (flags & DEBUG_DEFAULT_FLAGS)
+	if (flags & SLAB_RED_ZONE)
 		/*
 		 * Add some empty padding so that we can catch
 		 * overwrites from earlier objects rather than let
@@ -1665,10 +1848,12 @@
 		 * of the object.
 		 */
 		size += sizeof(void *);
+#endif
+
 	/*
 	 * Determine the alignment based on various parameters that the
-	 * user specified (this is unecessarily complex due to the attempt
-	 * to be compatible with SLAB. Should be cleaned up some day).
+	 * user specified and the dynamic determination of cache line size
+	 * on bootup.
 	 */
 	align = calculate_alignment(flags, align, s->objsize);
 
@@ -1700,23 +1885,6 @@
 
 }
 
-static int __init finish_bootstrap(void)
-{
-	struct list_head *h;
-	int err;
-
-	slab_state = SYSFS;
-
-	list_for_each(h, &slab_caches) {
-		struct kmem_cache *s =
-			container_of(h, struct kmem_cache, list);
-
-		err = sysfs_slab_add(s);
-		BUG_ON(err);
-	}
-	return 0;
-}
-
 static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
 		const char *name, size_t size,
 		size_t align, unsigned long flags,
@@ -1730,32 +1898,7 @@
 	s->objsize = size;
 	s->flags = flags;
 	s->align = align;
-
-	/*
-	 * The page->offset field is only 16 bit wide. This is an offset
-	 * in units of words from the beginning of an object. If the slab
-	 * size is bigger then we cannot move the free pointer behind the
-	 * object anymore.
-	 *
-	 * On 32 bit platforms the limit is 256k. On 64bit platforms
-	 * the limit is 512k.
-	 *
-	 * Debugging or ctor/dtors may create a need to move the free
-	 * pointer. Fail if this happens.
-	 */
-	if (s->size >= 65535 * sizeof(void *)) {
-		BUG_ON(flags & (SLAB_RED_ZONE | SLAB_POISON |
-				SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
-		BUG_ON(ctor || dtor);
-	}
-	else
-		/*
-		 * Enable debugging if selected on the kernel commandline.
-		 */
-		if (slub_debug && (!slub_debug_slabs ||
-		    strncmp(slub_debug_slabs, name,
-		    	strlen(slub_debug_slabs)) == 0))
-				s->flags |= slub_debug;
+	kmem_cache_open_debug_check(s);
 
 	if (!calculate_sizes(s))
 		goto error;
@@ -1783,7 +1926,6 @@
 int kmem_ptr_validate(struct kmem_cache *s, const void *object)
 {
 	struct page * page;
-	void *addr;
 
 	page = get_object_page(object);
 
@@ -1791,13 +1933,7 @@
 		/* No slab or wrong slab */
 		return 0;
 
-	addr = page_address(page);
-	if (object < addr || object >= addr + s->objects * s->size)
-		/* Out of bounds */
-		return 0;
-
-	if ((object - addr) % s->size)
-		/* Improperly aligned */
+	if (!check_valid_pointer(s, page, object))
 		return 0;
 
 	/*
@@ -1826,7 +1962,8 @@
 EXPORT_SYMBOL(kmem_cache_name);
 
 /*
- * Attempt to free all slabs on a node
+ * Attempt to free all slabs on a node. Return the number of slabs we
+ * were unable to free.
  */
 static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
 			struct list_head *list)
@@ -1847,7 +1984,7 @@
 }
 
 /*
- * Release all resources used by slab cache
+ * Release all resources used by a slab cache.
  */
 static int kmem_cache_close(struct kmem_cache *s)
 {
@@ -1932,45 +2069,6 @@
 
 __setup("slub_nomerge", setup_slub_nomerge);
 
-static int __init setup_slub_debug(char *str)
-{
-	if (!str || *str != '=')
-		slub_debug = DEBUG_DEFAULT_FLAGS;
-	else {
-		str++;
-		if (*str == 0 || *str == ',')
-			slub_debug = DEBUG_DEFAULT_FLAGS;
-		else
-		for( ;*str && *str != ','; str++)
-			switch (*str) {
-			case 'f' : case 'F' :
-				slub_debug |= SLAB_DEBUG_FREE;
-				break;
-			case 'z' : case 'Z' :
-				slub_debug |= SLAB_RED_ZONE;
-				break;
-			case 'p' : case 'P' :
-				slub_debug |= SLAB_POISON;
-				break;
-			case 'u' : case 'U' :
-				slub_debug |= SLAB_STORE_USER;
-				break;
-			case 't' : case 'T' :
-				slub_debug |= SLAB_TRACE;
-				break;
-			default:
-				printk(KERN_ERR "slub_debug option '%c' "
-					"unknown. skipped\n",*str);
-			}
-	}
-
-	if (*str == ',')
-		slub_debug_slabs = str + 1;
-	return 1;
-}
-
-__setup("slub_debug", setup_slub_debug);
-
 static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
 		const char *name, int size, gfp_t gfp_flags)
 {
@@ -2108,13 +2206,14 @@
 EXPORT_SYMBOL(kfree);
 
 /*
- *  kmem_cache_shrink removes empty slabs from the partial lists
- *  and then sorts the partially allocated slabs by the number
- *  of items in use. The slabs with the most items in use
- *  come first. New allocations will remove these from the
- *  partial list because they are full. The slabs with the
- *  least items are placed last. If it happens that the objects
- *  are freed then the page can be returned to the page allocator.
+ * kmem_cache_shrink removes empty slabs from the partial lists and sorts
+ * the remaining slabs by the number of items in use. The slabs with the
+ * most items in use come first. New allocations will then fill those up
+ * and thus they can be removed from the partial lists.
+ *
+ * The slabs with the least items are placed last. This results in them
+ * being allocated from last increasing the chance that the last objects
+ * are freed in them.
  */
 int kmem_cache_shrink(struct kmem_cache *s)
 {
@@ -2143,12 +2242,10 @@
 		spin_lock_irqsave(&n->list_lock, flags);
 
 		/*
-		 * Build lists indexed by the items in use in
-		 * each slab or free slabs if empty.
+		 * Build lists indexed by the items in use in each slab.
 		 *
-		 * Note that concurrent frees may occur while
-		 * we hold the list_lock. page->inuse here is
-		 * the upper limit.
+		 * Note that concurrent frees may occur while we hold the
+		 * list_lock. page->inuse here is the upper limit.
 		 */
 		list_for_each_entry_safe(page, t, &n->partial, lru) {
 			if (!page->inuse && slab_trylock(page)) {
@@ -2172,8 +2269,8 @@
 			goto out;
 
 		/*
-		 * Rebuild the partial list with the slabs filled up
-		 * most first and the least used slabs at the end.
+		 * Rebuild the partial list with the slabs filled up most
+		 * first and the least used slabs at the end.
 		 */
 		for (i = s->objects - 1; i >= 0; i--)
 			list_splice(slabs_by_inuse + i, n->partial.prev);
@@ -2189,7 +2286,6 @@
 
 /**
  * krealloc - reallocate memory. The contents will remain unchanged.
- *
  * @p: object to reallocate memory for.
  * @new_size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
@@ -2201,9 +2297,8 @@
  */
 void *krealloc(const void *p, size_t new_size, gfp_t flags)
 {
-	struct kmem_cache *new_cache;
 	void *ret;
-	struct page *page;
+	size_t ks;
 
 	if (unlikely(!p))
 		return kmalloc(new_size, flags);
@@ -2213,19 +2308,13 @@
 		return NULL;
 	}
 
-	page = virt_to_head_page(p);
-
-	new_cache = get_slab(new_size, flags);
-
-	/*
- 	 * If new size fits in the current cache, bail out.
- 	 */
-	if (likely(page->slab == new_cache))
+	ks = ksize(p);
+	if (ks >= new_size)
 		return (void *)p;
 
 	ret = kmalloc(new_size, flags);
 	if (ret) {
-		memcpy(ret, p, min(new_size, ksize(p)));
+		memcpy(ret, p, min(new_size, ks));
 		kfree(p);
 	}
 	return ret;
@@ -2243,7 +2332,7 @@
 #ifdef CONFIG_NUMA
 	/*
 	 * Must first have the slab cache available for the allocations of the
-	 * struct kmalloc_cache_node's. There is special bootstrap code in
+	 * struct kmem_cache_node's. There is special bootstrap code in
 	 * kmem_cache_open for slab_state == DOWN.
 	 */
 	create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
@@ -2280,7 +2369,7 @@
 
 	printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
 		" Processors=%d, Nodes=%d\n",
-		KMALLOC_SHIFT_HIGH, L1_CACHE_BYTES,
+		KMALLOC_SHIFT_HIGH, cache_line_size(),
 		slub_min_order, slub_max_order, slub_min_objects,
 		nr_cpu_ids, nr_node_ids);
 }
@@ -2415,8 +2504,8 @@
 }
 
 /*
- * Use the cpu notifier to insure that the slab are flushed
- * when necessary.
+ * Use the cpu notifier to insure that the cpu slabs are flushed when
+ * necessary.
  */
 static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
 		unsigned long action, void *hcpu)
@@ -2425,7 +2514,9 @@
 
 	switch (action) {
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		for_all_slabs(__flush_cpu_slab, cpu);
 		break;
 	default:
@@ -2439,94 +2530,122 @@
 
 #endif
 
-#ifdef CONFIG_NUMA
-
-/*****************************************************************
- * Generic reaper used to support the page allocator
- * (the cpu slabs are reaped by a per slab workqueue).
- *
- * Maybe move this to the page allocator?
- ****************************************************************/
-
-static DEFINE_PER_CPU(unsigned long, reap_node);
-
-static void init_reap_node(int cpu)
+void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
 {
-	int node;
+	struct kmem_cache *s = get_slab(size, gfpflags);
 
-	node = next_node(cpu_to_node(cpu), node_online_map);
-	if (node == MAX_NUMNODES)
-		node = first_node(node_online_map);
+	if (!s)
+		return NULL;
 
-	__get_cpu_var(reap_node) = node;
+	return slab_alloc(s, gfpflags, -1, caller);
 }
 
-static void next_reap_node(void)
+void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
+					int node, void *caller)
 {
-	int node = __get_cpu_var(reap_node);
+	struct kmem_cache *s = get_slab(size, gfpflags);
 
-	/*
-	 * Also drain per cpu pages on remote zones
-	 */
-	if (node != numa_node_id())
-		drain_node_pages(node);
+	if (!s)
+		return NULL;
 
-	node = next_node(node, node_online_map);
-	if (unlikely(node >= MAX_NUMNODES))
-		node = first_node(node_online_map);
-	__get_cpu_var(reap_node) = node;
-}
-#else
-#define init_reap_node(cpu) do { } while (0)
-#define next_reap_node(void) do { } while (0)
-#endif
-
-#define REAPTIMEOUT_CPUC	(2*HZ)
-
-#ifdef CONFIG_SMP
-static DEFINE_PER_CPU(struct delayed_work, reap_work);
-
-static void cache_reap(struct work_struct *unused)
-{
-	next_reap_node();
-	refresh_cpu_vm_stats(smp_processor_id());
-	schedule_delayed_work(&__get_cpu_var(reap_work),
-				      REAPTIMEOUT_CPUC);
+	return slab_alloc(s, gfpflags, node, caller);
 }
 
-static void __devinit start_cpu_timer(int cpu)
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
+static int validate_slab(struct kmem_cache *s, struct page *page)
 {
-	struct delayed_work *reap_work = &per_cpu(reap_work, cpu);
+	void *p;
+	void *addr = page_address(page);
+	DECLARE_BITMAP(map, s->objects);
 
-	/*
-	 * When this gets called from do_initcalls via cpucache_init(),
-	 * init_workqueues() has already run, so keventd will be setup
-	 * at that time.
-	 */
-	if (keventd_up() && reap_work->work.func == NULL) {
-		init_reap_node(cpu);
-		INIT_DELAYED_WORK(reap_work, cache_reap);
-		schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu);
+	if (!check_slab(s, page) ||
+			!on_freelist(s, page, NULL))
+		return 0;
+
+	/* Now we know that a valid freelist exists */
+	bitmap_zero(map, s->objects);
+
+	for_each_free_object(p, s, page->freelist) {
+		set_bit(slab_index(p, s, addr), map);
+		if (!check_object(s, page, p, 0))
+			return 0;
+	}
+
+	for_each_object(p, s, addr)
+		if (!test_bit(slab_index(p, s, addr), map))
+			if (!check_object(s, page, p, 1))
+				return 0;
+	return 1;
+}
+
+static void validate_slab_slab(struct kmem_cache *s, struct page *page)
+{
+	if (slab_trylock(page)) {
+		validate_slab(s, page);
+		slab_unlock(page);
+	} else
+		printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
+			s->name, page);
+
+	if (s->flags & DEBUG_DEFAULT_FLAGS) {
+		if (!SlabDebug(page))
+			printk(KERN_ERR "SLUB %s: SlabDebug not set "
+				"on slab 0x%p\n", s->name, page);
+	} else {
+		if (SlabDebug(page))
+			printk(KERN_ERR "SLUB %s: SlabDebug set on "
+				"slab 0x%p\n", s->name, page);
 	}
 }
 
-static int __init cpucache_init(void)
+static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
 {
-	int cpu;
+	unsigned long count = 0;
+	struct page *page;
+	unsigned long flags;
 
-	/*
-	 * Register the timers that drain pcp pages and update vm statistics
-	 */
-	for_each_online_cpu(cpu)
-		start_cpu_timer(cpu);
-	return 0;
+	spin_lock_irqsave(&n->list_lock, flags);
+
+	list_for_each_entry(page, &n->partial, lru) {
+		validate_slab_slab(s, page);
+		count++;
+	}
+	if (count != n->nr_partial)
+		printk(KERN_ERR "SLUB %s: %ld partial slabs counted but "
+			"counter=%ld\n", s->name, count, n->nr_partial);
+
+	if (!(s->flags & SLAB_STORE_USER))
+		goto out;
+
+	list_for_each_entry(page, &n->full, lru) {
+		validate_slab_slab(s, page);
+		count++;
+	}
+	if (count != atomic_long_read(&n->nr_slabs))
+		printk(KERN_ERR "SLUB: %s %ld slabs counted but "
+			"counter=%ld\n", s->name, count,
+			atomic_long_read(&n->nr_slabs));
+
+out:
+	spin_unlock_irqrestore(&n->list_lock, flags);
+	return count;
 }
-__initcall(cpucache_init);
-#endif
+
+static unsigned long validate_slab_cache(struct kmem_cache *s)
+{
+	int node;
+	unsigned long count = 0;
+
+	flush_all(s);
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+
+		count += validate_slab_node(s, n);
+	}
+	return count;
+}
 
 #ifdef SLUB_RESILIENCY_TEST
-static unsigned long validate_slab_cache(struct kmem_cache *s);
-
 static void resiliency_test(void)
 {
 	u8 *p;
@@ -2582,134 +2701,20 @@
 #endif
 
 /*
- * These are not as efficient as kmalloc for the non debug case.
- * We do not have the page struct available so we have to touch one
- * cacheline in struct kmem_cache to check slab flags.
- */
-void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
-{
-	struct kmem_cache *s = get_slab(size, gfpflags);
-
-	if (!s)
-		return NULL;
-
-	return slab_alloc(s, gfpflags, -1, caller);
-}
-
-void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
-					int node, void *caller)
-{
-	struct kmem_cache *s = get_slab(size, gfpflags);
-
-	if (!s)
-		return NULL;
-
-	return slab_alloc(s, gfpflags, node, caller);
-}
-
-#ifdef CONFIG_SYSFS
-
-static int validate_slab(struct kmem_cache *s, struct page *page)
-{
-	void *p;
-	void *addr = page_address(page);
-	unsigned long map[BITS_TO_LONGS(s->objects)];
-
-	if (!check_slab(s, page) ||
-			!on_freelist(s, page, NULL))
-		return 0;
-
-	/* Now we know that a valid freelist exists */
-	bitmap_zero(map, s->objects);
-
-	for(p = page->freelist; p; p = get_freepointer(s, p)) {
-		set_bit((p - addr) / s->size, map);
-		if (!check_object(s, page, p, 0))
-			return 0;
-	}
-
-	for(p = addr; p < addr + s->objects * s->size; p += s->size)
-		if (!test_bit((p - addr) / s->size, map))
-			if (!check_object(s, page, p, 1))
-				return 0;
-	return 1;
-}
-
-static void validate_slab_slab(struct kmem_cache *s, struct page *page)
-{
-	if (slab_trylock(page)) {
-		validate_slab(s, page);
-		slab_unlock(page);
-	} else
-		printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
-			s->name, page);
-
-	if (s->flags & DEBUG_DEFAULT_FLAGS) {
-		if (!PageError(page))
-			printk(KERN_ERR "SLUB %s: PageError not set "
-				"on slab 0x%p\n", s->name, page);
-	} else {
-		if (PageError(page))
-			printk(KERN_ERR "SLUB %s: PageError set on "
-				"slab 0x%p\n", s->name, page);
-	}
-}
-
-static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
-{
-	unsigned long count = 0;
-	struct page *page;
-	unsigned long flags;
-
-	spin_lock_irqsave(&n->list_lock, flags);
-
-	list_for_each_entry(page, &n->partial, lru) {
-		validate_slab_slab(s, page);
-		count++;
-	}
-	if (count != n->nr_partial)
-		printk(KERN_ERR "SLUB %s: %ld partial slabs counted but "
-			"counter=%ld\n", s->name, count, n->nr_partial);
-
-	if (!(s->flags & SLAB_STORE_USER))
-		goto out;
-
-	list_for_each_entry(page, &n->full, lru) {
-		validate_slab_slab(s, page);
-		count++;
-	}
-	if (count != atomic_long_read(&n->nr_slabs))
-		printk(KERN_ERR "SLUB: %s %ld slabs counted but "
-			"counter=%ld\n", s->name, count,
-			atomic_long_read(&n->nr_slabs));
-
-out:
-	spin_unlock_irqrestore(&n->list_lock, flags);
-	return count;
-}
-
-static unsigned long validate_slab_cache(struct kmem_cache *s)
-{
-	int node;
-	unsigned long count = 0;
-
-	flush_all(s);
-	for_each_online_node(node) {
-		struct kmem_cache_node *n = get_node(s, node);
-
-		count += validate_slab_node(s, n);
-	}
-	return count;
-}
-
-/*
- * Generate lists of locations where slabcache objects are allocated
+ * Generate lists of code addresses where slabcache objects are allocated
  * and freed.
  */
 
 struct location {
 	unsigned long count;
 	void *addr;
+	long long sum_time;
+	long min_time;
+	long max_time;
+	long min_pid;
+	long max_pid;
+	cpumask_t cpus;
+	nodemask_t nodes;
 };
 
 struct loc_track {
@@ -2750,11 +2755,12 @@
 }
 
 static int add_location(struct loc_track *t, struct kmem_cache *s,
-						void *addr)
+				const struct track *track)
 {
 	long start, end, pos;
 	struct location *l;
 	void *caddr;
+	unsigned long age = jiffies - track->when;
 
 	start = -1;
 	end = t->count;
@@ -2770,19 +2776,36 @@
 			break;
 
 		caddr = t->loc[pos].addr;
-		if (addr == caddr) {
-			t->loc[pos].count++;
+		if (track->addr == caddr) {
+
+			l = &t->loc[pos];
+			l->count++;
+			if (track->when) {
+				l->sum_time += age;
+				if (age < l->min_time)
+					l->min_time = age;
+				if (age > l->max_time)
+					l->max_time = age;
+
+				if (track->pid < l->min_pid)
+					l->min_pid = track->pid;
+				if (track->pid > l->max_pid)
+					l->max_pid = track->pid;
+
+				cpu_set(track->cpu, l->cpus);
+			}
+			node_set(page_to_nid(virt_to_page(track)), l->nodes);
 			return 1;
 		}
 
-		if (addr < caddr)
+		if (track->addr < caddr)
 			end = pos;
 		else
 			start = pos;
 	}
 
 	/*
-	 * Not found. Insert new tracking element
+	 * Not found. Insert new tracking element.
 	 */
 	if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max))
 		return 0;
@@ -2793,7 +2816,16 @@
 			(t->count - pos) * sizeof(struct location));
 	t->count++;
 	l->count = 1;
-	l->addr = addr;
+	l->addr = track->addr;
+	l->sum_time = age;
+	l->min_time = age;
+	l->max_time = age;
+	l->min_pid = track->pid;
+	l->max_pid = track->pid;
+	cpus_clear(l->cpus);
+	cpu_set(track->cpu, l->cpus);
+	nodes_clear(l->nodes);
+	node_set(page_to_nid(virt_to_page(track)), l->nodes);
 	return 1;
 }
 
@@ -2801,19 +2833,16 @@
 		struct page *page, enum track_item alloc)
 {
 	void *addr = page_address(page);
-	unsigned long map[BITS_TO_LONGS(s->objects)];
+	DECLARE_BITMAP(map, s->objects);
 	void *p;
 
 	bitmap_zero(map, s->objects);
-	for (p = page->freelist; p; p = get_freepointer(s, p))
-		set_bit((p - addr) / s->size, map);
+	for_each_free_object(p, s, page->freelist)
+		set_bit(slab_index(p, s, addr), map);
 
-	for (p = addr; p < addr + s->objects * s->size; p += s->size)
-		if (!test_bit((p - addr) / s->size, map)) {
-			void *addr = get_track(s, p, alloc)->addr;
-
-			add_location(t, s, addr);
-		}
+	for_each_object(p, s, addr)
+		if (!test_bit(slab_index(p, s, addr), map))
+			add_location(t, s, get_track(s, p, alloc));
 }
 
 static int list_locations(struct kmem_cache *s, char *buf,
@@ -2847,15 +2876,47 @@
 	}
 
 	for (i = 0; i < t.count; i++) {
-		void *addr = t.loc[i].addr;
+		struct location *l = &t.loc[i];
 
 		if (n > PAGE_SIZE - 100)
 			break;
-		n += sprintf(buf + n, "%7ld ", t.loc[i].count);
-		if (addr)
-			n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr);
+		n += sprintf(buf + n, "%7ld ", l->count);
+
+		if (l->addr)
+			n += sprint_symbol(buf + n, (unsigned long)l->addr);
 		else
 			n += sprintf(buf + n, "<not-available>");
+
+		if (l->sum_time != l->min_time) {
+			unsigned long remainder;
+
+			n += sprintf(buf + n, " age=%ld/%ld/%ld",
+			l->min_time,
+			div_long_long_rem(l->sum_time, l->count, &remainder),
+			l->max_time);
+		} else
+			n += sprintf(buf + n, " age=%ld",
+				l->min_time);
+
+		if (l->min_pid != l->max_pid)
+			n += sprintf(buf + n, " pid=%ld-%ld",
+				l->min_pid, l->max_pid);
+		else
+			n += sprintf(buf + n, " pid=%ld",
+				l->min_pid);
+
+		if (num_online_cpus() > 1 && !cpus_empty(l->cpus)) {
+			n += sprintf(buf + n, " cpus=");
+			n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+					l->cpus);
+		}
+
+		if (num_online_nodes() > 1 && !nodes_empty(l->nodes)) {
+			n += sprintf(buf + n, " nodes=");
+			n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+					l->nodes);
+		}
+
 		n += sprintf(buf + n, "\n");
 	}
 
@@ -3491,6 +3552,7 @@
 
 static int __init slab_sysfs_init(void)
 {
+	struct list_head *h;
 	int err;
 
 	err = subsystem_register(&slab_subsys);
@@ -3499,7 +3561,15 @@
 		return -ENOSYS;
 	}
 
-	finish_bootstrap();
+	slab_state = SYSFS;
+
+	list_for_each(h, &slab_caches) {
+		struct kmem_cache *s =
+			container_of(h, struct kmem_cache, list);
+
+		err = sysfs_slab_add(s);
+		BUG_ON(err);
+	}
 
 	while (alias_list) {
 		struct saved_alias *al = alias_list;
@@ -3515,6 +3585,4 @@
 }
 
 __initcall(slab_sysfs_init);
-#else
-__initcall(finish_bootstrap);
 #endif
diff --git a/mm/swap.c b/mm/swap.c
index 218c52a..d3cb966 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -488,7 +488,7 @@
 	long *committed;
 
 	committed = &per_cpu(committed_space, (long)hcpu);
-	if (action == CPU_DEAD) {
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
 		atomic_add(*committed, &vm_committed_space);
 		*committed = 0;
 		__lru_add_drain((long)hcpu);
diff --git a/mm/truncate.c b/mm/truncate.c
index 0f4b6d1..4fbe1a2 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -12,6 +12,7 @@
 #include <linux/swap.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
+#include <linux/highmem.h>
 #include <linux/pagevec.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/buffer_head.h>	/* grr. try_to_release_page,
@@ -46,7 +47,7 @@
 
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
-	memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+	zero_user_page(page, partial, PAGE_CACHE_SIZE - partial, KM_USER0);
 	if (PagePrivate(page))
 		do_invalidatepage(page, partial);
 }
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1c8e75a1..1be5a63 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1528,7 +1528,7 @@
 	pg_data_t *pgdat;
 	cpumask_t mask;
 
-	if (action == CPU_ONLINE) {
+	if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) {
 		for_each_online_pgdat(pgdat) {
 			mask = node_to_cpumask(pgdat->node_id);
 			if (any_online_cpu(mask) != NR_CPUS)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 6c488d6..9832d9a 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -281,6 +281,17 @@
 
 /*
  * Update the zone counters for one cpu.
+ *
+ * Note that refresh_cpu_vm_stats strives to only access
+ * node local memory. The per cpu pagesets on remote zones are placed
+ * in the memory local to the processor using that pageset. So the
+ * loop over all zones will access a series of cachelines local to
+ * the processor.
+ *
+ * The call to zone_page_state_add updates the cachelines with the
+ * statistics in the remote zone struct as well as the global cachelines
+ * with the global counters. These could cause remote node cache line
+ * bouncing and will have to be only done when necessary.
  */
 void refresh_cpu_vm_stats(int cpu)
 {
@@ -289,21 +300,54 @@
 	unsigned long flags;
 
 	for_each_zone(zone) {
-		struct per_cpu_pageset *pcp;
+		struct per_cpu_pageset *p;
 
 		if (!populated_zone(zone))
 			continue;
 
-		pcp = zone_pcp(zone, cpu);
+		p = zone_pcp(zone, cpu);
 
 		for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-			if (pcp->vm_stat_diff[i]) {
+			if (p->vm_stat_diff[i]) {
 				local_irq_save(flags);
-				zone_page_state_add(pcp->vm_stat_diff[i],
+				zone_page_state_add(p->vm_stat_diff[i],
 					zone, i);
-				pcp->vm_stat_diff[i] = 0;
+				p->vm_stat_diff[i] = 0;
+#ifdef CONFIG_NUMA
+				/* 3 seconds idle till flush */
+				p->expire = 3;
+#endif
 				local_irq_restore(flags);
 			}
+#ifdef CONFIG_NUMA
+		/*
+		 * Deal with draining the remote pageset of this
+		 * processor
+		 *
+		 * Check if there are pages remaining in this pageset
+		 * if not then there is nothing to expire.
+		 */
+		if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
+			continue;
+
+		/*
+		 * We never drain zones local to this processor.
+		 */
+		if (zone_to_nid(zone) == numa_node_id()) {
+			p->expire = 0;
+			continue;
+		}
+
+		p->expire--;
+		if (p->expire)
+			continue;
+
+		if (p->pcp[0].count)
+			drain_zone_pages(zone, p->pcp + 0);
+
+		if (p->pcp[1].count)
+			drain_zone_pages(zone, p->pcp + 1);
+#endif
 	}
 }
 
@@ -640,6 +684,24 @@
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
+int sysctl_stat_interval __read_mostly = HZ;
+
+static void vmstat_update(struct work_struct *w)
+{
+	refresh_cpu_vm_stats(smp_processor_id());
+	schedule_delayed_work(&__get_cpu_var(vmstat_work),
+		sysctl_stat_interval);
+}
+
+static void __devinit start_cpu_timer(int cpu)
+{
+	struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
+
+	INIT_DELAYED_WORK(vmstat_work, vmstat_update);
+	schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
+}
+
 /*
  * Use the cpu notifier to insure that the thresholds are recalculated
  * when necessary.
@@ -648,10 +710,24 @@
 		unsigned long action,
 		void *hcpu)
 {
+	long cpu = (long)hcpu;
+
 	switch (action) {
-	case CPU_UP_PREPARE:
-	case CPU_UP_CANCELED:
+	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
+		start_cpu_timer(cpu);
+		break;
+	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
+		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
+		per_cpu(vmstat_work, cpu).work.func = NULL;
+		break;
+	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
+		start_cpu_timer(cpu);
+		break;
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		refresh_zone_stat_thresholds();
 		break;
 	default:
@@ -665,8 +741,13 @@
 
 int __init setup_vmstat(void)
 {
+	int cpu;
+
 	refresh_zone_stat_thresholds();
 	register_cpu_notifier(&vmstat_notifier);
+
+	for_each_online_cpu(cpu)
+		start_cpu_timer(cpu);
 	return 0;
 }
 module_init(setup_vmstat)
diff --git a/net/core/dev.c b/net/core/dev.c
index 4317c1b..8301e2a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3450,7 +3450,7 @@
 	unsigned int cpu, oldcpu = (unsigned long)ocpu;
 	struct softnet_data *sd, *oldsd;
 
-	if (action != CPU_DEAD)
+	if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)
 		return NOTIFY_OK;
 
 	local_irq_disable();
diff --git a/net/core/flow.c b/net/core/flow.c
index 5d25697..0514305 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -338,7 +338,7 @@
 			  unsigned long action,
 			  void *hcpu)
 {
-	if (action == CPU_DEAD)
+	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
 		__flow_cache_shrink((unsigned long)hcpu, 0);
 	return NOTIFY_OK;
 }
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 9fbe87c..bfa910b 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1839,7 +1839,7 @@
 }
 
 /*
- * The DECnet spec requires the the "routing layer" accepts packets which
+ * The DECnet spec requires that the "routing layer" accepts packets which
  * are at least 230 bytes in size. This excludes any headers which the NSP
  * layer might add, so we always assume that we'll be using the maximal
  * length header on data packets. The variation in length is due to the
diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
index 305a09d..960ad13 100644
--- a/net/ieee80211/ieee80211_geo.c
+++ b/net/ieee80211/ieee80211_geo.c
@@ -94,6 +94,21 @@
 	return -1;
 }
 
+u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+{
+	const struct ieee80211_channel * ch;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+		return 0;
+
+	ch = ieee80211_get_channel(ieee, channel);
+	if (!ch->channel)
+		return 0;
+	return ch->freq;
+}
+
 u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
 {
 	int i;
@@ -174,6 +189,7 @@
 EXPORT_SYMBOL(ieee80211_get_channel_flags);
 EXPORT_SYMBOL(ieee80211_is_valid_channel);
 EXPORT_SYMBOL(ieee80211_freq_to_channel);
+EXPORT_SYMBOL(ieee80211_channel_to_freq);
 EXPORT_SYMBOL(ieee80211_channel_to_index);
 EXPORT_SYMBOL(ieee80211_set_geo);
 EXPORT_SYMBOL(ieee80211_get_geo);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index cee5e13..523a137 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -89,15 +89,17 @@
 		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
 	}
 
-	/* Add frequency/channel */
+	/* Add channel and frequency */
 	iwe.cmd = SIOCGIWFREQ;
-/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
-	iwe.u.freq.e = 3; */
 	iwe.u.freq.m = network->channel;
 	iwe.u.freq.e = 0;
 	iwe.u.freq.i = 0;
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
 
+	iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+	iwe.u.freq.e = 6;
+	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	if (network->capability & WLAN_CAPABILITY_PRIVACY)
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index e62aee0..c68196c 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -130,7 +130,7 @@
 	tristate "MULTIPATH: round robin algorithm"
 	depends on IP_ROUTE_MULTIPATH_CACHED
 	help
-	  Mulitpath routes are chosen according to Round Robin
+	  Multipath routes are chosen according to Round Robin
 
 config IP_ROUTE_MULTIPATH_RANDOM
 	tristate "MULTIPATH: random algorithm"
@@ -651,7 +651,7 @@
 	select CRYPTO
 	select CRYPTO_MD5
 	---help---
-	  RFC2385 specifices a method of giving MD5 protection to TCP sessions.
+	  RFC2385 specifies a method of giving MD5 protection to TCP sessions.
 	  Its main (only?) use is to protect BGP sessions between core routers
 	  on the Internet.
 
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index e1f1848..86a2b52 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -629,7 +629,7 @@
  * @domain: the domain to add
  *
  * Description:
- * Adds the @domain to the the DOI specified by @doi_def, this function
+ * Adds the @domain to the DOI specified by @doi_def, this function
  * should only be called by external functions (i.e. NetLabel).  This function
  * does allocate memory.  Returns zero on success, negative values on failure.
  *
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index b3050a6..68fe1d4 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -2387,6 +2387,7 @@
 	EnterFunction(2);
 	ip_vs_trash_cleanup();
 	cancel_rearming_delayed_work(&defense_work);
+	cancel_work_sync(&defense_work.work);
 	ip_vs_kill_estimator(&ip_vs_stats);
 	unregister_sysctl_table(sysctl_header);
 	proc_net_remove("ip_vs_stats");
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index ff366f7..dd7c128 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -18,7 +18,7 @@
  * The SED algorithm attempts to minimize each job's expected delay until
  * completion. The expected delay that the job will experience is
  * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
- * jobs on the the ith server and Ui is the fixed service rate (weight) of
+ * jobs on the ith server and Ui is the fixed service rate (weight) of
  * the ith server. The SED algorithm adopts a greedy policy that each does
  * what is in its own best interest, i.e. to join the queue which would
  * minimize its expected delay of completion.
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 113e0c4..66026df 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -983,7 +983,7 @@
 }
 
 /* return:
- * 	1  if the the UDP system should process it
+ * 	1  if the UDP system should process it
  *	0  if we should drop this packet
  * 	-1 if it should get processed by xfrm4_rcv_encap
  */
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index bbe99f8..838b8dd 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -28,7 +28,7 @@
 	  packets which enables users to receive the filtered packets
 	  with QUEUE target using libipq.
 
-	  THis option enables the old IPv6-only "ip6_queue" implementation
+	  This option enables the old IPv6-only "ip6_queue" implementation
 	  which has been obsoleted by the new "nfnetlink_queue" code (see
 	  CONFIG_NETFILTER_NETLINK_QUEUE).
 
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index fb3faf7..b733306 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -556,6 +556,7 @@
 
 	switch (action) {
 	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
 		if (!percpu_populate(iucv_irq_data,
 				     sizeof(struct iucv_irq_data),
 				     GFP_KERNEL|GFP_DMA, cpu))
@@ -567,15 +568,20 @@
 		}
 		break;
 	case CPU_UP_CANCELED:
+	case CPU_UP_CANCELED_FROZEN:
 	case CPU_DEAD:
+	case CPU_DEAD_FROZEN:
 		percpu_depopulate(iucv_param, cpu);
 		percpu_depopulate(iucv_irq_data, cpu);
 		break;
 	case CPU_ONLINE:
+	case CPU_ONLINE_FROZEN:
 	case CPU_DOWN_FAILED:
+	case CPU_DOWN_FAILED_FROZEN:
 		smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
 		break;
 	case CPU_DOWN_PREPARE:
+	case CPU_DOWN_PREPARE_FROZEN:
 		cpumask = iucv_buffer_cpumask;
 		cpu_clear(cpu, cpumask);
 		if (cpus_empty(cpumask))
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7d9fa38..6b8a103 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -324,7 +324,7 @@
 		memset(&laddr, 0, sizeof(laddr));
 		memset(&daddr, 0, sizeof(daddr));
 		/*
-		 * FIXME: check if the the address is multicast,
+		 * FIXME: check if the address is multicast,
 		 * 	  only SOCK_DGRAM can do this.
 		 */
 		memcpy(laddr.mac, addr->sllc_mac, IFHWADDRLEN);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index ea6211c..a567dae 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -197,7 +197,7 @@
 
 	  Please note that not all PPTP modes of operation are supported yet.
 	  Specifically these limitations exist:
-	    - Blindy assumes that control connections are always established
+	    - Blindly assumes that control connections are always established
 	      in PNS->PAC direction. This is a violation of RFC2637.
 	    - Only supports a single call within each session
 
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index c31af29..117cbfd 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -177,7 +177,7 @@
 	struct nf_conntrack_expect *i;
 
 	write_lock_bh(&nf_conntrack_lock);
-	/* choose the the oldest expectation to evict */
+	/* choose the oldest expectation to evict */
 	list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
 		if (expect_matches(i, exp) && del_timer(&i->timeout)) {
 			nf_ct_unlink_expect(i);
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 83ef411..77fb7b0 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -3,7 +3,7 @@
  *
  * This file is part of the SCTP kernel reference Implementation
  *
- * This file contains the code relating the the chunk abstraction.
+ * This file contains the code relating the chunk abstraction.
  *
  * The SCTP reference implementation is free software;
  * you can redistribute it and/or modify it under the terms of
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 9f1a908..83a76ba 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2586,7 +2586,7 @@
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
@@ -4547,7 +4547,7 @@
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index db298b5..099a983 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -924,6 +924,7 @@
 gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
 {
 	struct rsc *rsci;
+	int        rc;
 
 	if (rsip->major_status != GSS_S_COMPLETE)
 		return gss_write_null_verf(rqstp);
@@ -932,7 +933,9 @@
 		rsip->major_status = GSS_S_NO_CONTEXT;
 		return gss_write_null_verf(rqstp);
 	}
-	return gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+	rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+	cache_put(&rsci->h, &rsc_cache);
+	return rc;
 }
 
 /*
@@ -1089,6 +1092,8 @@
 		}
 		goto complete;
 	case RPC_GSS_PROC_DESTROY:
+		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+			goto auth_err;
 		set_bit(CACHE_NEGATIVE, &rsci->h.flags);
 		if (resv->iov_len + 4 > PAGE_SIZE)
 			goto drop;
@@ -1196,13 +1201,7 @@
 	if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
 				integ_len))
 		BUG();
-	if (resbuf->page_len == 0
-			&& resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
-			< PAGE_SIZE) {
-		BUG_ON(resbuf->tail[0].iov_len);
-		/* Use head for everything */
-		resv = &resbuf->head[0];
-	} else if (resbuf->tail[0].iov_base == NULL) {
+	if (resbuf->tail[0].iov_base == NULL) {
 		if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
 			goto out_err;
 		resbuf->tail[0].iov_base = resbuf->head[0].iov_base
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index ad39b47..a2f1893 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -845,6 +845,8 @@
 
 int register_rpc_pipefs(void)
 {
+	int err;
+
 	rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
 				sizeof(struct rpc_inode),
 				0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -852,7 +854,12 @@
 				init_once, NULL);
 	if (!rpc_inode_cachep)
 		return -ENOMEM;
-	register_filesystem(&rpc_pipe_fs_type);
+	err = register_filesystem(&rpc_pipe_fs_type);
+	if (err) {
+		kmem_cache_destroy(rpc_inode_cachep);
+		return err;
+	}
+
 	return 0;
 }
 
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 9901451..b011eb6 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -736,6 +736,11 @@
 	__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
 }
 
+struct rpc_buffer {
+	size_t	len;
+	char	data[];
+};
+
 /**
  * rpc_malloc - allocate an RPC buffer
  * @task: RPC task that will use this buffer
@@ -754,18 +759,22 @@
  */
 void *rpc_malloc(struct rpc_task *task, size_t size)
 {
-	size_t *buf;
+	struct rpc_buffer *buf;
 	gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
 
-	size += sizeof(size_t);
+	size += sizeof(struct rpc_buffer);
 	if (size <= RPC_BUFFER_MAXSIZE)
 		buf = mempool_alloc(rpc_buffer_mempool, gfp);
 	else
 		buf = kmalloc(size, gfp);
-	*buf = size;
+
+	if (!buf)
+		return NULL;
+
+	buf->len = size;
 	dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
 			task->tk_pid, size, buf);
-	return ++buf;
+	return &buf->data;
 }
 
 /**
@@ -775,15 +784,18 @@
  */
 void rpc_free(void *buffer)
 {
-	size_t size, *buf = buffer;
+	size_t size;
+	struct rpc_buffer *buf;
 
 	if (!buffer)
 		return;
-	size = *buf;
-	buf--;
+
+	buf = container_of(buffer, struct rpc_buffer, data);
+	size = buf->len;
 
 	dprintk("RPC:       freeing buffer of size %zu at %p\n",
 			size, buf);
+
 	if (size <= RPC_BUFFER_MAXSIZE)
 		mempool_free(buf, rpc_buffer_mempool);
 	else
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 43ecf62..0d35bc7 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -146,9 +146,11 @@
 	int err = register_rpc_pipefs();
 	if (err)
 		goto out;
-	err = rpc_init_mempool() != 0;
-	if (err)
+	err = rpc_init_mempool();
+	if (err) {
+		unregister_rpc_pipefs();
 		goto out;
+	}
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
 #endif
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b7503c1..e673ef9 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -907,7 +907,7 @@
 	 * better idea of reply size
 	 */
 	if (procp->pc_xdrressize)
-		svc_reserve(rqstp, procp->pc_xdrressize<<2);
+		svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
 
 	/* Call the function that processes the request. */
 	if (!versp->vs_dispatch) {
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index f5c3808..af7c5f0 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -64,7 +64,7 @@
 }
 
 /* A request, which was authenticated, has now executed.
- * Time to finalise the the credentials and verifier
+ * Time to finalise the credentials and verifier
  * and release and resources
  */
 int svc_authorise(struct svc_rqst *rqstp)
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 2bd23ea..07dcd20 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -385,7 +385,7 @@
 {
 	struct ip_map *ipm;
 	struct svc_sock *svsk = rqstp->rq_sock;
-	spin_lock_bh(&svsk->sk_defer_lock);
+	spin_lock(&svsk->sk_lock);
 	ipm = svsk->sk_info_authunix;
 	if (ipm != NULL) {
 		if (!cache_valid(&ipm->h)) {
@@ -395,13 +395,13 @@
 			 * same IP address.
 			 */
 			svsk->sk_info_authunix = NULL;
-			spin_unlock_bh(&svsk->sk_defer_lock);
+			spin_unlock(&svsk->sk_lock);
 			cache_put(&ipm->h, &ip_map_cache);
 			return NULL;
 		}
 		cache_get(&ipm->h);
 	}
-	spin_unlock_bh(&svsk->sk_defer_lock);
+	spin_unlock(&svsk->sk_lock);
 	return ipm;
 }
 
@@ -410,14 +410,14 @@
 {
 	struct svc_sock *svsk = rqstp->rq_sock;
 
-	spin_lock_bh(&svsk->sk_defer_lock);
+	spin_lock(&svsk->sk_lock);
 	if (svsk->sk_sock->type == SOCK_STREAM &&
 	    svsk->sk_info_authunix == NULL) {
 		/* newly cached, keep the reference */
 		svsk->sk_info_authunix = ipm;
 		ipm = NULL;
 	}
-	spin_unlock_bh(&svsk->sk_defer_lock);
+	spin_unlock(&svsk->sk_lock);
 	if (ipm)
 		cache_put(&ipm->h, &ip_map_cache);
 }
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 22f61ae..5baf48d 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -53,7 +53,8 @@
  * 	svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
  *	when both need to be taken (rare), svc_serv->sv_lock is first.
  *	BKL protects svc_serv->sv_nrthread.
- *	svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list
+ *	svc_sock->sk_lock protects the svc_sock->sk_deferred list
+ *             and the ->sk_info_authunix cache.
  *	svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
  *
  *	Some flags can be set to certain values at any time
@@ -787,15 +788,20 @@
 	}
 
 	clear_bit(SK_DATA, &svsk->sk_flags);
-	while ((err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
-				     0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 ||
-	       (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
-		if (err == -EAGAIN) {
-			svc_sock_received(svsk);
-			return err;
+	skb = NULL;
+	err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
+			     0, 0, MSG_PEEK | MSG_DONTWAIT);
+	if (err >= 0)
+		skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
+
+	if (skb == NULL) {
+		if (err != -EAGAIN) {
+			/* possibly an icmp error */
+			dprintk("svc: recvfrom returned error %d\n", -err);
+			set_bit(SK_DATA, &svsk->sk_flags);
 		}
-		/* possibly an icmp error */
-		dprintk("svc: recvfrom returned error %d\n", -err);
+		svc_sock_received(svsk);
+		return -EAGAIN;
 	}
 	rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
 	if (skb->tstamp.tv64 == 0) {
@@ -1633,7 +1639,7 @@
 	svsk->sk_server = serv;
 	atomic_set(&svsk->sk_inuse, 1);
 	svsk->sk_lastrecv = get_seconds();
-	spin_lock_init(&svsk->sk_defer_lock);
+	spin_lock_init(&svsk->sk_lock);
 	INIT_LIST_HEAD(&svsk->sk_deferred);
 	INIT_LIST_HEAD(&svsk->sk_ready);
 	mutex_init(&svsk->sk_mutex);
@@ -1857,9 +1863,9 @@
 	dprintk("revisit queued\n");
 	svsk = dr->svsk;
 	dr->svsk = NULL;
-	spin_lock_bh(&svsk->sk_defer_lock);
+	spin_lock(&svsk->sk_lock);
 	list_add(&dr->handle.recent, &svsk->sk_deferred);
-	spin_unlock_bh(&svsk->sk_defer_lock);
+	spin_unlock(&svsk->sk_lock);
 	set_bit(SK_DEFERRED, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
 	svc_sock_put(svsk);
@@ -1925,7 +1931,7 @@
 
 	if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
 		return NULL;
-	spin_lock_bh(&svsk->sk_defer_lock);
+	spin_lock(&svsk->sk_lock);
 	clear_bit(SK_DEFERRED, &svsk->sk_flags);
 	if (!list_empty(&svsk->sk_deferred)) {
 		dr = list_entry(svsk->sk_deferred.next,
@@ -1934,6 +1940,6 @@
 		list_del_init(&dr->handle.recent);
 		set_bit(SK_DEFERRED, &svsk->sk_flags);
 	}
-	spin_unlock_bh(&svsk->sk_defer_lock);
+	spin_unlock(&svsk->sk_lock);
 	return dr;
 }
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index d6071cb..f4d2f68 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -211,7 +211,7 @@
  * Document all external or internal functions in a file.
  * Call kernel-doc with following parameters:
  * kernel-doc -docbook -nofunction function_name1 filename
- * function names are obtained from all the the src files
+ * function names are obtained from all the src files
  * by find_export_symbols.
  * intfunc uses -nofunction
  * extfunc uses -function
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index a325a0c..e5bf649 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -337,6 +337,7 @@
     }
     return $version;
 }
+my $kernelversion = get_kernel_version();
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
@@ -610,7 +611,7 @@
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'function'}."</refname>\n";
@@ -687,7 +688,7 @@
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
@@ -772,7 +773,7 @@
     print "<refmeta>\n";
     print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>enum ".$args{'enum'}."</refname>\n";
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 480e18b..113dc77 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1343,6 +1343,7 @@
 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
 			      " .exit = cleanup_module,\n"
 			      "#endif\n");
+	buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
 	buf_printf(b, "};\n");
 }
 
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 23b5104..b32a459 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -137,7 +137,7 @@
 
 	  Examples:
 	  For the Fedora Core 3 or 4 Linux distributions, enable this option
-	  and set the value via the next option. For Fedore Core 5 and later,
+	  and set the value via the next option. For Fedora Core 5 and later,
 	  do not enable this option.
 
 	  If you are unsure how to answer this question, answer N.
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b292752..829ca38 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -146,7 +146,7 @@
 	default y
 	help
 	  Say Y here to include code for verbose procfs contents (provides
-          usefull information to developers when a problem occurs). On the
+          useful information to developers when a problem occurs).  On the
           other side, it makes the ALSA subsystem larger.
 
 config SND_VERBOSE_PRINTK
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index 974dd73..593a3aa 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -100,7 +100,7 @@
  *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  *    05.01.2001   0.29  Hopefully updates will not be required anymore when Creative bumps
  *                       the CT5880 revision.
- *                       suggested by Stephan Müller <smueller@chronox.de>
+ *                       suggested by Stephan Müller <smueller@chronox.de>
  *    31.01.2001   0.30  Register/Unregister gameport
  *                       Fix SETTRIGGER non OSS API conformity
  *    14.07.2001   0.31  Add list of laptops needing amplifier control
diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c
index 4af6aaf..36c3ea6 100644
--- a/sound/oss/pas2_pcm.c
+++ b/sound/oss/pas2_pcm.c
@@ -85,7 +85,7 @@
 	 * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
 	 *
 	 * I cleared bit 5 of these values, since that bit controls the master
-	 * mute flag. (Olav Wölfelschneider)
+	 * mute flag. (Olav Wölfelschneider)
 	 *
 	 */
 #if !defined NO_AUTO_FILTER_SET
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index d98d311..3bc1f6e 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -18,7 +18,7 @@
  *	Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
  *	Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support 
  *	Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
- *	Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
+ *	Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
  *      Muli Ben-Yehuda <mulix@mulix.org>
  *
  *
@@ -89,7 +89,7 @@
  *	use set_current_state, properly release resources on failure in
  *	trident_probe, get rid of check_region
  *  v0.14.9c
- *	August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
+ *	August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
  *	added support for Tvia (formerly Integraphics/IGST) CyberPro5050
  *	this chip is often found in settop boxes (combined video+audio)
  *  v0.14.9b
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index a9eec2a..3bfb210 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1083,7 +1083,7 @@
 		unsigned short val;
 		snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
 		/* Do the read twice due to buffers on some ac97 codecs.
-		 * e.g. The STAC9704 returns exactly what you wrote the the register
+		 * e.g. The STAC9704 returns exactly what you wrote to the register
 		 * if you read it immediately. This causes the detect routine to fail.
 		 */
 		val = snd_ac97_read(ac97, reg);
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index e65d669..e47861c 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -63,7 +63,7 @@
 					/* look to CS8414 datasheet */
 #define ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK 0x04
 					/* S/PDIF output status clock */
-					/* (writting on rising edge - 0->1) */
+					/* (writing on rising edge - 0->1) */
 					/* all except Delta44 */
 					/* look to CS8404A datasheet */
 #define ICE1712_DELTA_SPDIF_OUT_STAT_DATA 0x08
@@ -100,7 +100,7 @@
 					/* AKM4524 serial data */
 #define ICE1712_DELTA_CODEC_SERIAL_CLOCK 0x20
 					/* AKM4524 serial clock */
-					/* (writting on rising edge - 0->1 */
+					/* (writing on rising edge - 0->1 */
 #define ICE1712_DELTA_CODEC_CHIP_A	0x40
 #define ICE1712_DELTA_CODEC_CHIP_B	0x80
 					/* 1 - select chip A or B */
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 21386da..ac007ce 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -472,7 +472,7 @@
 	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
 	struct mixart_stream *stream = subs->runtime->private_data;
 
-	/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
+	/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
 
 	snd_printdd("snd_mixart_prepare\n");
 
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
index 4c4b882..b8ccfee 100644
--- a/sound/soc/pxa/pxa2xx-ac97.h
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -1,5 +1,5 @@
 /*
- * linux/sound/arm/pxa2xx-ac97.h
+ * linux/sound/soc/pxa/pxa2xx-ac97.h
  *
  * 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
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
index a2484f0..4435bd9 100644
--- a/sound/soc/pxa/pxa2xx-i2s.h
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -1,5 +1,5 @@
 /*
- * linux/sound/arm/pxa2xx-i2s.h
+ * linux/sound/soc/pxa/pxa2xx-i2s.h
  *
  * 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
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 25a2a73..e07085a 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -673,7 +673,7 @@
 }
 
 /*
- * Send prepared cmd string. It works by writting a JUMP cmd into
+ * Send prepared cmd string. It works by writing a JUMP cmd into
  * the last WAIT cmd and force DBRI to reread the cmd.
  * The JUMP cmd points to the new cmd string.
  * It also releases the cmdlock spinlock.