Merge branches 'at91', 'ep93xx', 'iop', 'kprobes', 'ks8695', 'misc', 'msm', 's3c2410', 'sa1100' and 'vfp' into devel

* at91: (24 commits)
  [ARM] 4615/4: sam926[13]ek buttons updated
  [ARM] 4765/1: [AT91] AT91CAP9A-DK board support
  [ARM] 4764/1: [AT91] AT91CAP9 core support
  [ARM] 4738/1: at91sam9261: Remove udc pullup enabling in board initialisation
  [ARM] 4761/1: [AT91] Board-support for NEW_LEDs
  [ARM] 4760/1: [AT91] SPI CS0 errata on AT91RM9200
  [ARM] 4759/1: [AT91] Buttons on CSB300
  [ARM] 4758/1: [AT91] LEDs
  [ARM] 4757/1: [AT91] UART initialization
  [ARM] 4756/1: [AT91] Makefile cleanup
  [ARM] 4755/1: [AT91] NAND update
  [ARM] 4754/1: [AT91] SSC library support
  [ARM] 4753/1: [AT91] Use DMA_BIT_MASK
  [ARM] 4752/1: [AT91] RTT, RTC and WDT peripherals on SAM9
  [ARM] 4751/1: [AT91] ISI peripheral on SAM9263
  [ARM] 4750/1: [AT91] STN LCD displays on SAM9261
  [ARM] 4734/1: at91sam9263ek: include IRQ for Ethernet PHY
  [ARM] 4646/1: AT91: configurable HZ, default to 128
  [ARM] 4688/1: at91: speed-up irq processing
  [ARM] 4657/1: AT91: Header definition update
  ...

* ep93xx:
  [ARM] 4671/1: ep93xx: remove obsolete gpio_line_* operations
  [ARM] 4670/1: ep93xx: implement IRQT_BOTHEDGE gpio irq sense type
  [ARM] 4669/1: ep93xx: simplify GPIO code and cleanups
  [ARM] 4668/1: ep93xx: implement new GPIO API

* iop:
  [ARM] 4770/1: GLAN Tank: correct physmap_flash_data width field
  [ARM] 4732/1: GLAN Tank: register rtc-rs5c372 i2c device
  [ARM] 4708/1: iop: update defconfigs for 2.6.24

* kprobes:
  ARM kprobes: let's enable it
  ARM kprobes: special hook for the kprobes breakpoint handler
  ARM kprobes: prevent some functions involved with kprobes from being probed
  ARM kprobes: don't let a single-stepped stmdb corrupt the exception stack
  ARM kprobes: add the kprobes hook to the page fault handler
  ARM kprobes: core code
  ARM kprobes: instruction single-stepping support

* ks8695:
  [ARM] 4603/1: KS8695: debugfs interface to view pin state
  [ARM] 4601/1: KS8695: PCI support

* misc:
  [ARM] remove duplicate includes
  [ARM] CONFIG_DEBUG_STACK_USAGE
  [ARM] 4689/1: small comment wrap fix
  [ARM] 4687/1: Trivial arch/arm/kernel/entry-common.S comment fix
  [ARM] 4666/1: ixp4xx: fix sparse warnings in include/asm-arm/arch-ixp4xx/io.h
  [ARM] remove reference to non-existent MTD_OBSOLETE_CHIPS
  [SERIAL] 21285: Report baud rate back via termios
  [ARM] Remove pointless casts from void pointers,
  [ARM] Misc minor interrupt handler cleanups
  [ARM] Remove at91_lcdc.h
  [ARM] ARRAY_SIZE() cleanup
  [ARM] Update mach-types

* msm:
  [ARM] msm: dma support for MSM7X00A
  [ARM] msm: board file for MACH_HALIBUT (QCT MSM7200A)
  [ARM] msm: irq and timer support for ARCH_MSM7X00A
  [ARM] msm: core platform support for ARCH_MSM7X00A

* s3c2410: (33 commits)
  [ARM] 4795/1: S3C244X: Add armclk and setparent call
  [ARM] 4794/1: S3C24XX: Comonise S3C2440 and S3C2442 clock code
  [ARM] 4793/1: S3C24XX: Add IRQ->GPIO pin mapping function
  [ARM] 4792/1: S3C24XX: Remove warnings from debug-macro.S
  [ARM] 4791/1: S3C2412: Make fclk a parent of msysclk
  [ARM] 4790/1: S3C2412: Fix parent selection for msysclk.
  [ARM] 4789/1: S3C2412: Add missing CLKDIVN register values
  [ARM] 4788/1: S3C24XX: Fix paramet to s3c2410_dma_ctrl if S3C2410_DMAF_AUTOSTART used.
  [ARM] 4787/1: S3C24XX: s3c2410_dma_request() should return the allocated channel number
  [ARM] 4786/1: S3C2412: Add SPI FIFO controll constants
  [ARM] 4785/1: S3C24XX: Add _SHIFT definitions for S3C2410_BANKCON registers
  [ARM] 4784/1: S3C24XX: Fix GPIO restore glitches
  [ARM] 4783/1: S3C24XX: Add s3c2410_gpio_getpull()
  [ARM] 4782/1: S3C24XX: Define FIQ_START for any FIQ users
  [ARM] 4781/1: S3C24XX: DMA suspend and resume support
  [ARM] 4780/1: S3C2412: Allow for seperate DMA channels for TX and RX
  [ARM] 4779/1: S3C2412: Add s3c2412_gpio_set_sleepcfg() call
  [ARM] 4778/1: S3C2412: Add armclk and init from DVS state
  [ARM] 4777/1: S3C24XX: Ensure clk_set_rate() checks the set_rate method for the clk
  [ARM] 4775/1: s3c2410: fix compilation error if only s3c2442 cpu is selected
  ...

* sa1100:
  [ARM] sa1100: add clock source support

* vfp:
  [ARM] 4584/2: ARMv7: Add Advanced SIMD (NEON) extension support
  [ARM] 4583/1: ARMv7: Add VFPv3 support
  [ARM] 4582/2: Add support for the common VFP subarchitecture
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
index 254e769..3d2f31b 100644
--- a/Documentation/DocBook/s390-drivers.tmpl
+++ b/Documentation/DocBook/s390-drivers.tmpl
@@ -116,6 +116,7 @@
 !Iinclude/asm-s390/ccwdev.h
 !Edrivers/s390/cio/device.c
 !Edrivers/s390/cio/device_ops.c
+!Edrivers/s390/cio/airq.c
     </sect1>
     <sect1 id="cmf">
      <title>The channel-measurement facility</title>
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index fb94f5a..ba0aacd 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -50,7 +50,7 @@
   			cpu_possible_map = cpu_present_map + additional_cpus
 
 (*) Option valid only for following architectures
-- x86_64, ia64, s390
+- x86_64, ia64
 
 ia64 and x86_64 use the number of disabled local apics in ACPI tables MADT
 to determine the number of potentially hot-pluggable cpus. The implementation
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 9b8291f..2537066 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -191,15 +191,6 @@
 
 ---------------------------
 
-What:	i2c_adapter.list
-When:	July 2007
-Why:	Superfluous, this list duplicates the one maintained by the driver
-	core.
-Who:	Jean Delvare <khali@linux-fr.org>,
-	David Brownell <dbrownell@users.sourceforge.net>
-
----------------------------
-
 What:	ACPI procfs interface
 When:	July 2008
 Why:	ACPI sysfs conversion should be finished by January 2008.
@@ -225,14 +216,6 @@
 
 ---------------------------
 
-What:	i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
-When:	September 2007
-Why:	Obsolete. The new i2c-gpio driver replaces all hardware-specific
-	I2C-over-GPIO drivers.
-Who:	Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
 What:	'time' kernel boot parameter
 When:	January 2008
 Why:	replaced by 'printk.time=<value>' so that printk timestamps can be
@@ -266,13 +249,6 @@
 
 ---------------------------
 
-What:	Legacy RTC drivers (under drivers/i2c/chips)
-When:	November 2007
-Why:	Obsolete. We have a RTC subsystem with better drivers.
-Who:	Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
 What:	iptables SAME target
 When:	1.1. 2008
 Files:	net/ipv4/netfilter/ipt_SAME.c, include/linux/netfilter_ipv4/ipt_SAME.h
@@ -323,3 +299,10 @@
 Who:	Stephen Hemminger <shemminger@linux-foundation.org>
 
 ---------------------------
+
+What:	i2c-i810, i2c-prosavage and i2c-savage4
+When:	May 2008
+Why:	These drivers are superseded by i810fb, intelfb and savagefb.
+Who:	Jean Delvare <khali@linux-fr.org>
+
+---------------------------
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index fde4420..3bd9583 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -17,9 +17,8 @@
    Datasheets: Publicly available at the Intel website
 
 Authors: 
-	Frodo Looijaard <frodol@dds.nl>, 
-	Philip Edelbrock <phil@netroedge.com>, 
 	Mark Studebaker <mdsxyz123@yahoo.com>
+	Jean Delvare <khali@linux-fr.org>
 
 
 Module Parameters
@@ -62,7 +61,7 @@
 I2C Block Read Support
 ----------------------
 
-Not supported at the moment.
+I2C block read is supported on the 82801EB (ICH5) and later chips.
 
 
 SMBus 2.0 Support
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 06b4be3..1405fb6 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -10,7 +10,7 @@
   * VIA Technologies, Inc. VT8231, VT8233, VT8233A
     Datasheet: available on request from VIA
 
-  * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
+  * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8237S, VT8251
     Datasheet: available on request and under NDA from VIA
 
   * VIA Technologies, Inc. CX700
@@ -46,6 +46,7 @@
  device 1106:3177   (VT8235)
  device 1106:3227   (VT8237R)
  device 1106:3337   (VT8237A)
+ device 1106:3372   (VT8237S)
  device 1106:3287   (VT8251)
  device 1106:8324   (CX700)
 
diff --git a/Documentation/i2c/chips/pcf8575 b/Documentation/i2c/chips/pcf8575
new file mode 100644
index 0000000..25f5698
--- /dev/null
+++ b/Documentation/i2c/chips/pcf8575
@@ -0,0 +1,72 @@
+About the PCF8575 chip and the pcf8575 kernel driver
+====================================================
+
+The PCF8575 chip is produced by the following manufacturers:
+
+  * Philips NXP
+    http://www.nxp.com/#/pip/cb=[type=product,path=50807/41735/41850,final=PCF8575_3]|pip=[pip=PCF8575_3][0]
+
+  * Texas Instruments
+    http://focus.ti.com/docs/prod/folders/print/pcf8575.html
+
+
+Some vendors sell small PCB's with the PCF8575 mounted on it. You can connect
+such a board to a Linux host via e.g. an USB to I2C interface. Examples of
+PCB boards with a PCF8575:
+
+  * SFE Breakout Board for PCF8575 I2C Expander by RobotShop
+    http://www.robotshop.ca/home/products/robot-parts/electronics/adapters-converters/sfe-pcf8575-i2c-expander-board.html
+
+  * Breakout Board for PCF8575 I2C Expander by Spark Fun Electronics
+    http://www.sparkfun.com/commerce/product_info.php?products_id=8130
+
+
+Description
+-----------
+The PCF8575 chip is a 16-bit I/O expander for the I2C bus. Up to eight of
+these chips can be connected to the same I2C bus. You can find this
+chip on some custom designed hardware, but you won't find it on PC
+motherboards.
+
+The PCF8575 chip consists of a 16-bit quasi-bidirectional port and an I2C-bus
+interface. Each of the sixteen I/O's can be independently used as an input or
+an output. To set up an I/O pin as an input, you have to write a 1 to the
+corresponding output.
+
+For more information please see the datasheet.
+
+
+Detection
+---------
+
+There is no method known to detect whether a chip on a given I2C address is
+a PCF8575 or whether it is any other I2C device. So there are two alternatives
+to let the driver find the installed PCF8575 devices:
+- Load this driver after any other I2C driver for I2C devices with addresses
+  in the range 0x20 .. 0x27.
+- Pass the I2C bus and address of the installed PCF8575 devices explicitly to
+  the driver at load time via the probe=... or force=... parameters.
+
+/sys interface
+--------------
+
+For each address on which a PCF8575 chip was found or forced the following
+files will be created under /sys:
+* /sys/bus/i2c/devices/<bus>-<address>/read
+* /sys/bus/i2c/devices/<bus>-<address>/write
+where bus is the I2C bus number (0, 1, ...) and address is the four-digit
+hexadecimal representation of the 7-bit I2C address of the PCF8575
+(0020 .. 0027).
+
+The read file is read-only. Reading it will trigger an I2C read and will hence
+report the current input state for the pins configured as inputs, and the
+current output value for the pins configured as outputs.
+
+The write file is read-write. Writing a value to it will configure all pins
+as output for which the corresponding bit is zero. Reading the write file will
+return the value last written, or -EAGAIN if no value has yet been written to
+the write file.
+
+On module initialization the configuration of the chip is not changed -- the
+chip is left in the state it was already configured in through either power-up
+or through previous I2C write actions.
diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
index 89e69ad..0d8be1c 100644
--- a/Documentation/i2c/i2c-stub
+++ b/Documentation/i2c/i2c-stub
@@ -25,6 +25,9 @@
 	3. load the target sensors chip driver module
 	4. observe its behavior in the kernel log
 
+There's a script named i2c-stub-from-dump in the i2c-tools package which
+can load register values automatically from a chip dump.
+
 PARAMETERS:
 
 int chip_addr[10]:
@@ -32,9 +35,6 @@
 
 CAVEATS:
 
-There are independent arrays for byte/data and word/data commands.  Depending
-on if/how a target driver mixes them, you'll need to be careful.
-
 If your target driver polls some byte or word waiting for it to change, the
 stub could lock it up.  Use i2cset to unlock it.
 
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 2c17003..bfb0a55 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -267,9 +267,9 @@
 Fortunately, as a module writer, you just have to define the `normal_i2c' 
 parameter. The complete declaration could look like this:
 
-  /* Scan 0x37, and 0x48 to 0x4f */
-  static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
-                                         0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+  /* Scan 0x4c to 0x4f */
+  static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, 0x4f,
+                                               I2C_CLIENT_END };
 
   /* Magic definition of all other variables and things */
   I2C_CLIENT_INSMOD;
diff --git a/Documentation/ide.txt b/Documentation/ide.txt
index 1d50f23..94e2e3b 100644
--- a/Documentation/ide.txt
+++ b/Documentation/ide.txt
@@ -30,7 +30,7 @@
 ***
 ***  The CMD640 is also used on some Vesa Local Bus (VLB) cards, and is *NOT*
 ***  automatically detected by Linux.  For safe, reliable operation with such
-***  interfaces, one *MUST* use the "ide0=cmd640_vlb" kernel option.
+***  interfaces, one *MUST* use the "cmd640.probe_vlb" kernel option.
 ***
 ***  Use of the "serialize" option is no longer necessary.
 
@@ -244,10 +244,6 @@
 
  "hdx=nodma"		: disallow DMA
 
- "hdx=swapdata"		: when the drive is a disk, byte swap all data
-
- "hdx=bswap"		: same as above..........
-
  "hdx=scsi"		: the return of the ide-scsi flag, this is useful for
  			  allowing ide-floppy, ide-tape, and ide-cdrom|writers
  			  to use ide-scsi emulation on a device specific option.
@@ -292,9 +288,6 @@
 to the first ATA interface found on the particular host, and the defaults for
 the base,ctl ports must not be altered.
 
- "ide0=cmd640_vlb"	: *REQUIRED* for VLB cards with the CMD640 chip
-			  (not for PCI -- automatically detected)
-
  "ide=doubler"		: probe/support IDE doublers on Amiga
 
 There may be more options than shown -- use the source, Luke!
@@ -310,6 +303,10 @@
 * "probe" module parameter when ali14xx driver is compiled as module
   ("modprobe ali14xx probe")
 
+Also for legacy CMD640 host driver (cmd640) you need to use "probe_vlb"
+kernel paremeter to enable probing for VLB version of the chipset (PCI ones
+are detected automatically).
+
 ================================================================================
 
 IDE ATAPI streaming tape driver
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 65de5ba..880f882 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -370,7 +370,8 @@
 			configured.  Potentially dangerous and should only be
 			used if you are entirely sure of the consequences.
 
-	chandev=	[HW,NET] Generic channel device initialisation
+	ccw_timeout_log [S390]
+			See Documentation/s390/CommonIO for details.
 
 	checkreqprot	[SELINUX] Set initial checkreqprot flag value.
 			Format: { "0" | "1" }
@@ -382,6 +383,12 @@
 			Value can be changed at runtime via
 				/selinux/checkreqprot.
 
+	cio_ignore=	[S390]
+			See Documentation/s390/CommonIO for details.
+
+	cio_msg=	[S390]
+			See Documentation/s390/CommonIO for details.
+
 	clock=		[BUGS=X86-32, HW] gettimeofday clocksource override.
 			[Deprecated]
 			Forces specified clocksource (if available) to be used
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index cb12ae1..53a6389 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -141,6 +141,7 @@
 - ppc64
 - ia64 (Does not support probes on instruction slot1.)
 - sparc64 (Return probes not yet implemented.)
+- arm
 
 3. Configuring Kprobes
 
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index 86320aa..8fbc0a8 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -4,6 +4,11 @@
 Command line parameters
 -----------------------
 
+* ccw_timeout_log
+
+  Enable logging of debug information in case of ccw device timeouts.
+
+
 * cio_msg = yes | no
   
   Determines whether information on found devices and sensed device 
diff --git a/MAINTAINERS b/MAINTAINERS
index 59db481..2937122 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -758,22 +758,20 @@
 
 BLACKFIN RTC DRIVER
 P:	Mike Frysinger
-M:	michael.frysinger@analog.com
 M:	vapier.adi@gmail.com
 L:	uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
 W:	http://blackfin.uclinux.org
 S:	Supported
 
 BLACKFIN SERIAL DRIVER
-P:	Aubrey Li
-M:	aubrey.li@analog.com
+P:	Sonic Zhang
+M:	sonic.zhang@analog.com
 L:	uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
 W:	http://blackfin.uclinux.org
 S:	Supported
 
 BLACKFIN WATCHDOG DRIVER
 P:	Mike Frysinger
-M:	michael.frysinger@analog.com
 M:	vapier.adi@gmail.com
 L:	uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
 W:	http://blackfin.uclinux.org
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a04f507..e53b0ed 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -180,8 +180,8 @@
 	bool "Atmel AT91"
 	select GENERIC_GPIO
 	help
-	  This enables support for systems based on the Atmel AT91RM9200
-	  and AT91SAM9xxx processors.
+	  This enables support for systems based on the Atmel AT91RM9200,
+	  AT91SAM9 and AT91CAP9 processors.
 
 config ARCH_CLPS7500
 	bool "Cirrus CL-PS7500FE"
@@ -217,6 +217,7 @@
 	bool "EP93xx-based"
 	select ARM_AMBA
 	select ARM_VIC
+	select GENERIC_GPIO
 	help
 	  This enables support for the Cirrus EP93xx series of CPUs.
 
@@ -366,6 +367,7 @@
 	select ARCH_DISCONTIGMEM_ENABLE
 	select ARCH_MTD_XIP
 	select GENERIC_GPIO
+	select GENERIC_TIME
 	help
 	  Support for StrongARM 11x0 based boards.
 
@@ -409,6 +411,17 @@
 	help
 	  Support for TI's OMAP platform (OMAP1 and OMAP2).
 
+config ARCH_MSM7X00A
+	bool "Qualcomm MSM7X00A"
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	help
+	  Support for Qualcomm MSM7X00A based systems.  This runs on the ARM11
+	  apps processor of the MSM7X00A and depends on a shared memory
+	  interface to the ARM9 modem processor which runs the baseband stack
+	  and controls some vital subsystems (clock and power control, etc).
+	  <http://www.cdmatech.com/products/msm7200_chipset_solution.jsp>
+
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
@@ -477,6 +490,8 @@
 
 source "arch/arm/mach-ks8695/Kconfig"
 
+source "arch/arm/mach-msm/Kconfig"
+
 # Definitions to make life easier
 config ARCH_ACORN
 	bool
@@ -657,6 +672,7 @@
 	default 128 if ARCH_L7200
 	default 200 if ARCH_EBSA110 || ARCH_S3C2410
 	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
+	default AT91_TIMER_HZ if ARCH_AT91
 	default 100
 
 config AEABI
@@ -951,7 +967,7 @@
 
 config VFP
 	bool "VFP-format floating point maths"
-	depends on CPU_V6 || CPU_ARM926T
+	depends on CPU_V6 || CPU_ARM926T || CPU_V7
 	help
 	  Say Y to include VFP support code in the kernel. This is needed
 	  if your hardware includes a VFP unit.
@@ -961,6 +977,18 @@
 
 	  Say N if your target does not have VFP hardware.
 
+config VFPv3
+	bool
+	depends on VFP
+	default y if CPU_V7
+
+config NEON
+	bool "Advanced SIMD (NEON) Extension support"
+	depends on VFPv3 && CPU_V7
+	help
+	  Say Y to include support code for NEON, the ARMv7 Advanced SIMD
+	  Extension.
+
 endmenu
 
 menu "Userspace binary formats"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 18101f5..192ee01 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -43,6 +43,12 @@
 	  you are concerned with the code size or don't want to see these
 	  messages.
 
+config DEBUG_STACK_USAGE
+	bool "Enable stack utilization instrumentation"
+	depends on DEBUG_KERNEL
+	help
+	  Enables the display of the minimum amount of free stack which each
+	  task has ever had available in the sysrq-T output.
 
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
diff --git a/arch/arm/Kconfig.instrumentation b/arch/arm/Kconfig.instrumentation
index 63b8c6d..453ad8e 100644
--- a/arch/arm/Kconfig.instrumentation
+++ b/arch/arm/Kconfig.instrumentation
@@ -43,6 +43,16 @@
 config OPROFILE_ARM11_CORE
 	bool
 
+config KPROBES
+	bool "Kprobes"
+	depends on KALLSYMS && MODULES && !UML && !XIP_KERNEL
+	help
+	  Kprobes allows you to trap at almost any kernel address and
+	  execute a callback function.  register_kprobe() establishes
+	  a probepoint and specifies the callback.  Kprobes is useful
+	  for kernel debugging, non-intrusive instrumentation and testing.
+	  If in doubt, say "N".
+
 config MARKERS
 	bool "Activate markers"
 	help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 35e56c9..dd220d1 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -139,6 +139,7 @@
  machine-$(CONFIG_ARCH_KS8695)     := ks8695
   incdir-$(CONFIG_ARCH_MXC)	   := mxc
  machine-$(CONFIG_ARCH_MX3)	   := mx3
+ machine-$(CONFIG_ARCH_MSM7X00A)   := msm
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 5fde99f..de9d9ee 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -44,10 +44,6 @@
 OBJS		+= head-sharpsl.o
 endif
 
-ifeq ($(CONFIG_ARCH_AT91RM9200),y)
-OBJS		+= head-at91rm9200.o
-endif
-
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS		+= big-endian.o
diff --git a/arch/arm/boot/compressed/head-at91rm9200.S b/arch/arm/boot/compressed/head-at91rm9200.S
deleted file mode 100644
index 11782cc..0000000
--- a/arch/arm/boot/compressed/head-at91rm9200.S
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * linux/arch/arm/boot/compressed/head-at91rm9200.S
- *
- *  Copyright (C) 2003 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <asm/mach-types.h>
-
-		.section	".start", "ax"
-
-		@ Atmel AT91RM9200-DK : 262
-		mov	r3,	#(MACH_TYPE_AT91RM9200DK & 0xff)
-		orr	r3, r3, #(MACH_TYPE_AT91RM9200DK & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Cogent CSB337 : 399
-		mov	r3,	#(MACH_TYPE_CSB337 & 0xff)
-		orr	r3, r3, #(MACH_TYPE_CSB337 & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Cogent CSB637 : 648
-		mov	r3,	#(MACH_TYPE_CSB637 & 0xff)
-		orr	r3, r3,	#(MACH_TYPE_CSB637 & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Atmel AT91RM9200-EK : 705
-		mov	r3,	#(MACH_TYPE_AT91RM9200EK & 0xff)
-		orr	r3, r3, #(MACH_TYPE_AT91RM9200EK & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Conitec Carmeva : 769
-		mov	r3,	#(MACH_TYPE_CARMEVA & 0xff)
-		orr	r3, r3, #(MACH_TYPE_CARMEVA & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ KwikByte KB920x : 612
-		mov	r3,	#(MACH_TYPE_KB9200 & 0xff)
-		orr	r3, r3, #(MACH_TYPE_KB9200 & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Embest ATEB9200 : 923
-		mov	r3,	#(MACH_TYPE_ATEB9200 & 0xff)
-		orr	r3, r3,	#(MACH_TYPE_ATEB9200 & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Sperry-Sun KAFA : 662
-		mov	r3,	#(MACH_TYPE_KAFA & 0xff)
-		orr	r3, r3,	#(MACH_TYPE_KAFA & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ picotux 200 : 963
-		mov	r3,	#(MACH_TYPE_PICOTUX2XX & 0xff)
-		orr	r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Ajeco 1ARM : 1075
-		mov	r3,	#(MACH_TYPE_ONEARM & 0xff)
-		orr	r3, r3, #(MACH_TYPE_ONEARM & 0xff00)
-		cmp	r7, r3
-		beq	99f
-
-		@ Unknown board, use the AT91RM9200DK board
-		@ mov	r7, #MACH_TYPE_AT91RM9200
-		mov	r7,	#(MACH_TYPE_AT91RM9200DK & 0xff)
-		orr	r7, r7, #(MACH_TYPE_AT91RM9200DK & 0xff00)
-
-99:
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
index bf1075e..f53bca4 100644
--- a/arch/arm/common/rtctime.c
+++ b/arch/arm/common/rtctime.c
@@ -20,7 +20,6 @@
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
-#include <linux/rtc.h>
 
 #include <asm/rtc.h>
 #include <asm/semaphore.h>
diff --git a/arch/arm/configs/at91cap9adk_defconfig b/arch/arm/configs/at91cap9adk_defconfig
new file mode 100644
index 0000000..e32e736
--- /dev/null
+++ b/arch/arm/configs/at91cap9adk_defconfig
@@ -0,0 +1,1143 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc8
+# Wed Jan 23 22:55:57 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+CONFIG_ARCH_AT91CAP9=y
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91CAP9 Board Type
+#
+CONFIG_MACH_AT91CAP9ADK=y
+
+#
+# AT91 Board Options
+#
+CONFIG_MTD_AT91_DATAFLASH_CARD=y
+# CONFIG_MTD_NAND_AT91_BUSWIDTH_16 is not set
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=100
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_AT91=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ATMEL_SSC=y
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+CONFIG_LOGO_LINUX_VGA16=y
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_AT91=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig
index 970c8c7..4264e27 100644
--- a/arch/arm/configs/collie_defconfig
+++ b/arch/arm/configs/collie_defconfig
@@ -367,7 +367,6 @@
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-CONFIG_MTD_OBSOLETE_CHIPS=y
 CONFIG_MTD_SHARP=y
 # CONFIG_MTD_XIP is not set
 
diff --git a/arch/arm/configs/msm_defconfig b/arch/arm/configs/msm_defconfig
new file mode 100644
index 0000000..ae4c5e6
--- /dev/null
+++ b/arch/arm/configs/msm_defconfig
@@ -0,0 +1,895 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.23
+# Wed Nov  7 01:36:45 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_GPIOS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_PANIC_TIMEOUT=0
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_GOLDFISH is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+CONFIG_ARCH_MSM7X00A=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# MSM7200 Board Type
+#
+CONFIG_MACH_HALIBUT=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+# CONFIG_SERIAL_MSM_NOINIT is not set
+CONFIG_MSM_SMD=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyMSM,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_SUSPEND_UP_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_MSM_NAND=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_GOLDFISH_NAND is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+CONFIG_MSM_RMNET=y
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_GOLDFISH_EVENTS is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_MEP is not set
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
+CONFIG_INPUT_GPIO=y
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DCC_TTY=y
+# CONFIG_GOLDFISH_TTY is not set
+CONFIG_BINDER=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_MSM=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+CONFIG_SENSORS_PCA9633=y
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+CONFIG_SENSORS_AKM8976=y
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_LOW_MEMORY_KILLER=y
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_MSM=y
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# USB Function Support
+#
+CONFIG_USB_FUNCTION=y
+CONFIG_USB_FUNCTION_MSM_HSUSB=y
+# CONFIG_USB_FUNCTION_NULL is not set
+# CONFIG_USB_FUNCTION_ZERO is not set
+# CONFIG_USB_FUNCTION_LOOPBACK is not set
+CONFIG_USB_FUNCTION_ADB=y
+# CONFIG_MMC is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Android
+#
+# CONFIG_ANDROID_GADGET is not set
+# CONFIG_ANDROID_RAM_CONSOLE is not set
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_VIBRATOR=y
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 593b565..faa7619 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -19,6 +19,7 @@
 obj-$(CONFIG_PCI)		+= bios32.o isa.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-decode.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c
index 0a3e9ad..2f080a3 100644
--- a/arch/arm/kernel/dma-isa.c
+++ b/arch/arm/kernel/dma-isa.c
@@ -216,7 +216,7 @@
 
 		request_dma(DMA_ISA_CASCADE, "cascade");
 
-		for (i = 0; i < sizeof(dma_resources) / sizeof(dma_resources[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(dma_resources); i++)
 			request_resource(&ioport_resource, dma_resources + i);
 	}
 }
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 29dec08..a46d5b4 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -11,8 +11,8 @@
  *
  *  Low-level vector interface routines
  *
- *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
- *  it to save wrong values...  Be aware!
+ *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction
+ *  that causes it to save wrong values...  Be aware!
  */
 
 #include <asm/memory.h>
@@ -58,6 +58,12 @@
 
 	.endm
 
+#ifdef CONFIG_KPROBES
+	.section	.kprobes.text,"ax",%progbits
+#else
+	.text
+#endif
+
 /*
  * Invalid mode handlers
  */
@@ -112,8 +118,8 @@
 #define SPFIX(code...)
 #endif
 
-	.macro	svc_entry
-	sub	sp, sp, #S_FRAME_SIZE
+	.macro	svc_entry, stack_hole=0
+	sub	sp, sp, #(S_FRAME_SIZE + \stack_hole)
  SPFIX(	tst	sp, #4		)
  SPFIX(	bicne	sp, sp, #4	)
 	stmib	sp, {r1 - r12}
@@ -121,7 +127,7 @@
 	ldmia	r0, {r1 - r3}
 	add	r5, sp, #S_SP		@ here for interlock avoidance
 	mov	r4, #-1			@  ""  ""      ""       ""
-	add	r0, sp, #S_FRAME_SIZE   @  ""  ""      ""       ""
+	add	r0, sp, #(S_FRAME_SIZE + \stack_hole)
  SPFIX(	addne	r0, r0, #4	)
 	str	r1, [sp]		@ save the "real" r0 copied
 					@ from the exception stack
@@ -242,7 +248,14 @@
 
 	.align	5
 __und_svc:
+#ifdef CONFIG_KPROBES
+	@ If a kprobe is about to simulate a "stmdb sp..." instruction,
+	@ it obviously needs free stack space which then will belong to
+	@ the saved context.
+	svc_entry 64
+#else
 	svc_entry
+#endif
 
 	@
 	@ call emulation code, which returns using r9 if it has emulated
@@ -480,6 +493,13 @@
  * co-processor instructions.  However, we have to watch out
  * for the ARM6/ARM7 SWI bug.
  *
+ * NEON is a special case that has to be handled here. Not all
+ * NEON instructions are co-processor instructions, so we have
+ * to make a special case of checking for them. Plus, there's
+ * five groups of them, so we have a table of mask/opcode pairs
+ * to check against, and if any match then we branch off into the
+ * NEON handler code.
+ *
  * Emulators may wish to make use of the following registers:
  *  r0  = instruction opcode.
  *  r2  = PC+4
@@ -488,6 +508,23 @@
  *  lr  = unrecognised instruction return address
  */
 call_fpe:
+#ifdef CONFIG_NEON
+	adr	r6, .LCneon_opcodes
+2:
+	ldr	r7, [r6], #4			@ mask value
+	cmp	r7, #0				@ end mask?
+	beq	1f
+	and	r8, r0, r7
+	ldr	r7, [r6], #4			@ opcode bits matching in mask
+	cmp	r8, r7				@ NEON instruction?
+	bne	2b
+	get_thread_info r10
+	mov	r7, #1
+	strb	r7, [r10, #TI_USED_CP + 10]	@ mark CP#10 as used
+	strb	r7, [r10, #TI_USED_CP + 11]	@ mark CP#11 as used
+	b	do_vfp				@ let VFP handler handle this
+1:
+#endif
 	tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
 #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
 	and	r8, r0, #0x0f000000		@ mask out op-code bits
@@ -537,6 +574,20 @@
 	mov	pc, lr				@ CP#14 (Debug)
 	mov	pc, lr				@ CP#15 (Control)
 
+#ifdef CONFIG_NEON
+	.align	6
+
+.LCneon_opcodes:
+	.word	0xfe000000			@ mask
+	.word	0xf2000000			@ opcode
+
+	.word	0xff100000			@ mask
+	.word	0xf4000000			@ opcode
+
+	.word	0x00000000			@ mask
+	.word	0x00000000			@ opcode
+#endif
+
 do_fpe:
 	enable_irq
 	ldr	r4, .LCfp
@@ -555,7 +606,7 @@
 	.data
 ENTRY(fp_enter)
 	.word	no_fp
-	.text
+	.previous
 
 no_fp:	mov	pc, lr
 
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 33e6cc2..6c90c50 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -72,7 +72,7 @@
 	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
 	ldr	lr, [sp, #S_PC]!		@ get pc
 	msr	spsr_cxsf, r1			@ save in spsr_svc
-	ldmdb	sp, {r0 - lr}^			@ get calling r1 - lr
+	ldmdb	sp, {r0 - lr}^			@ get calling r0 - lr
 	mov	r0, r0
 	add	sp, sp, #S_FRAME_SIZE - S_PC
 	movs	pc, lr				@ return & move spsr_svc into cpsr
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
new file mode 100644
index 0000000..d51bc8b
--- /dev/null
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -0,0 +1,1529 @@
+/*
+ * arch/arm/kernel/kprobes-decode.c
+ *
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * 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.
+ */
+
+/*
+ * We do not have hardware single-stepping on ARM, This
+ * effort is further complicated by the ARM not having a
+ * "next PC" register.  Instructions that change the PC
+ * can't be safely single-stepped in a MP environment, so
+ * we have a lot of work to do:
+ *
+ * In the prepare phase:
+ *   *) If it is an instruction that does anything
+ *      with the CPU mode, we reject it for a kprobe.
+ *      (This is out of laziness rather than need.  The
+ *      instructions could be simulated.)
+ *
+ *   *) Otherwise, decode the instruction rewriting its
+ *      registers to take fixed, ordered registers and
+ *      setting a handler for it to run the instruction.
+ *
+ * In the execution phase by an instruction's handler:
+ *
+ *   *) If the PC is written to by the instruction, the
+ *      instruction must be fully simulated in software.
+ *      If it is a conditional instruction, the handler
+ *      will use insn[0] to copy its condition code to
+ *	set r0 to 1 and insn[1] to "mov pc, lr" to return.
+ *
+ *   *) Otherwise, a modified form of the instruction is
+ *      directly executed.  Its handler calls the
+ *      instruction in insn[0].  In insn[1] is a
+ *      "mov pc, lr" to return.
+ *
+ *      Before calling, load up the reordered registers
+ *      from the original instruction's registers.  If one
+ *      of the original input registers is the PC, compute
+ *      and adjust the appropriate input register.
+ *
+ *	After call completes, copy the output registers to
+ *      the original instruction's original registers.
+ *
+ * We don't use a real breakpoint instruction since that
+ * would have us in the kernel go from SVC mode to SVC
+ * mode losing the link register.  Instead we use an
+ * undefined instruction.  To simplify processing, the
+ * undefined instruction used for kprobes must be reserved
+ * exclusively for kprobes use.
+ *
+ * TODO: ifdef out some instruction decoding based on architecture.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+
+#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
+
+#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
+
+#define PSR_fs	(PSR_f|PSR_s)
+
+#define KPROBE_RETURN_INSTRUCTION	0xe1a0f00e	/* mov pc, lr */
+#define SET_R0_TRUE_INSTRUCTION		0xe3a00001	/* mov	r0, #1 */
+
+#define	truecc_insn(insn)	(((insn) & 0xf0000000) | \
+				 (SET_R0_TRUE_INSTRUCTION & 0x0fffffff))
+
+typedef long (insn_0arg_fn_t)(void);
+typedef long (insn_1arg_fn_t)(long);
+typedef long (insn_2arg_fn_t)(long, long);
+typedef long (insn_3arg_fn_t)(long, long, long);
+typedef long (insn_4arg_fn_t)(long, long, long, long);
+typedef long long (insn_llret_0arg_fn_t)(void);
+typedef long long (insn_llret_3arg_fn_t)(long, long, long);
+typedef long long (insn_llret_4arg_fn_t)(long, long, long, long);
+
+union reg_pair {
+	long long	dr;
+#ifdef __LITTLE_ENDIAN
+	struct { long	r0, r1; };
+#else
+	struct { long	r1, r0; };
+#endif
+};
+
+/*
+ * For STR and STM instructions, an ARM core may choose to use either
+ * a +8 or a +12 displacement from the current instruction's address.
+ * Whichever value is chosen for a given core, it must be the same for
+ * both instructions and may not change.  This function measures it.
+ */
+
+static int str_pc_offset;
+
+static void __init find_str_pc_offset(void)
+{
+	int addr, scratch, ret;
+
+	__asm__ (
+		"sub	%[ret], pc, #4		\n\t"
+		"str	pc, %[addr]		\n\t"
+		"ldr	%[scr], %[addr]		\n\t"
+		"sub	%[ret], %[scr], %[ret]	\n\t"
+		: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
+
+	str_pc_offset = ret;
+}
+
+/*
+ * The insnslot_?arg_r[w]flags() functions below are to keep the
+ * msr -> *fn -> mrs instruction sequences indivisible so that
+ * the state of the CPSR flags aren't inadvertently modified
+ * just before or just after the call.
+ */
+
+static inline long __kprobes
+insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn)
+{
+	register long ret asm("r0");
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret)
+		: [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	return ret;
+}
+
+static inline long long __kprobes
+insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn)
+{
+	register long ret0 asm("r0");
+	register long ret1 asm("r1");
+	union reg_pair fnr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret0), "=r" (ret1)
+		: [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	fnr.r0 = ret0;
+	fnr.r1 = ret1;
+	return fnr.dr;
+}
+
+static inline long __kprobes
+insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long ret asm("r0");
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret)
+		: "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long ret asm("r0");
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret)
+		: "0" (rr0), "r" (rr1),
+		  [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long ret asm("r0");
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret)
+		: "0" (rr0), "r" (rr1), "r" (rr2),
+		  [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	return ret;
+}
+
+static inline long long __kprobes
+insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr,
+			   insn_llret_3arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long ret0 asm("r0");
+	register long ret1 asm("r1");
+	union reg_pair fnr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret0), "=r" (ret1)
+		: "0" (rr0), "r" (rr1), "r" (rr2),
+		  [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	fnr.r0 = ret0;
+	fnr.r1 = ret1;
+	return fnr.dr;
+}
+
+static inline long __kprobes
+insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr,
+		     insn_4arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long rr3 asm("r3") = r3;
+	register long ret asm("r0");
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[cpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		: "=r" (ret)
+		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
+		  [cpsr] "r" (cpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long ret asm("r0");
+	long oldcpsr = *cpsr;
+	long newcpsr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[oldcpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		"mrs	%[newcpsr], cpsr	\n\t"
+		: "=r" (ret), [newcpsr] "=r" (newcpsr)
+		: "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long ret asm("r0");
+	long oldcpsr = *cpsr;
+	long newcpsr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[oldcpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		"mrs	%[newcpsr], cpsr	\n\t"
+		: "=r" (ret), [newcpsr] "=r" (newcpsr)
+		: "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr,
+		      insn_3arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long ret asm("r0");
+	long oldcpsr = *cpsr;
+	long newcpsr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[oldcpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		"mrs	%[newcpsr], cpsr	\n\t"
+		: "=r" (ret), [newcpsr] "=r" (newcpsr)
+		: "0" (rr0), "r" (rr1), "r" (rr2),
+		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
+	return ret;
+}
+
+static inline long __kprobes
+insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
+		      insn_4arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long rr3 asm("r3") = r3;
+	register long ret asm("r0");
+	long oldcpsr = *cpsr;
+	long newcpsr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[oldcpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		"mrs	%[newcpsr], cpsr	\n\t"
+		: "=r" (ret), [newcpsr] "=r" (newcpsr)
+		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
+		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
+	return ret;
+}
+
+static inline long long __kprobes
+insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr,
+			    insn_llret_4arg_fn_t *fn)
+{
+	register long rr0 asm("r0") = r0;
+	register long rr1 asm("r1") = r1;
+	register long rr2 asm("r2") = r2;
+	register long rr3 asm("r3") = r3;
+	register long ret0 asm("r0");
+	register long ret1 asm("r1");
+	long oldcpsr = *cpsr;
+	long newcpsr;
+	union reg_pair fnr;
+
+	__asm__ __volatile__ (
+		"msr	cpsr_fs, %[oldcpsr]	\n\t"
+		"mov	lr, pc			\n\t"
+		"mov	pc, %[fn]		\n\t"
+		"mrs	%[newcpsr], cpsr	\n\t"
+		: "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr)
+		: "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3),
+		  [oldcpsr] "r" (oldcpsr), [fn] "r" (fn)
+		: "lr", "cc"
+	);
+	*cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs);
+	fnr.r0 = ret0;
+	fnr.r1 = ret1;
+	return fnr.dr;
+}
+
+/*
+ * To avoid the complications of mimicing single-stepping on a
+ * processor without a Next-PC or a single-step mode, and to
+ * avoid having to deal with the side-effects of boosting, we
+ * simulate or emulate (almost) all ARM instructions.
+ *
+ * "Simulation" is where the instruction's behavior is duplicated in
+ * C code.  "Emulation" is where the original instruction is rewritten
+ * and executed, often by altering its registers.
+ *
+ * By having all behavior of the kprobe'd instruction completed before
+ * returning from the kprobe_handler(), all locks (scheduler and
+ * interrupt) can safely be released.  There is no need for secondary
+ * breakpoints, no race with MP or preemptable kernels, nor having to
+ * clean up resources counts at a later time impacting overall system
+ * performance.  By rewriting the instruction, only the minimum registers
+ * need to be loaded and saved back optimizing performance.
+ *
+ * Calling the insnslot_*_rwflags version of a function doesn't hurt
+ * anything even when the CPSR flags aren't updated by the
+ * instruction.  It's just a little slower in return for saving
+ * a little space by not having a duplicate function that doesn't
+ * update the flags.  (The same optimization can be said for
+ * instructions that do or don't perform register writeback)
+ * Also, instructions can either read the flags, only write the
+ * flags, or read and write the flags.  To save combinations
+ * rather than for sheer performance, flag functions just assume
+ * read and write of flags.
+ */
+
+static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	long iaddr = (long)p->addr;
+	int disp  = branch_displacement(insn);
+
+	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
+		return;
+
+	if (insn & (1 << 24))
+		regs->ARM_lr = iaddr + 4;
+
+	regs->ARM_pc = iaddr + 8 + disp;
+}
+
+static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
+{
+	kprobe_opcode_t insn = p->opcode;
+	long iaddr = (long)p->addr;
+	int disp = branch_displacement(insn);
+
+	regs->ARM_lr = iaddr + 4;
+	regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
+	regs->ARM_cpsr |= PSR_T_BIT;
+}
+
+static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rm = insn & 0xf;
+	long rmv = regs->uregs[rm];
+
+	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
+		return;
+
+	if (insn & (1 << 5))
+		regs->ARM_lr = (long)p->addr + 4;
+
+	regs->ARM_pc = rmv & ~0x1;
+	regs->ARM_cpsr &= ~PSR_T_BIT;
+	if (rmv & 0x1)
+		regs->ARM_cpsr |= PSR_T_BIT;
+}
+
+static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rn = (insn >> 16) & 0xf;
+	int lbit = insn & (1 << 20);
+	int wbit = insn & (1 << 21);
+	int ubit = insn & (1 << 23);
+	int pbit = insn & (1 << 24);
+	long *addr = (long *)regs->uregs[rn];
+	int reg_bit_vector;
+	int reg_count;
+
+	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
+		return;
+
+	reg_count = 0;
+	reg_bit_vector = insn & 0xffff;
+	while (reg_bit_vector) {
+		reg_bit_vector &= (reg_bit_vector - 1);
+		++reg_count;
+	}
+
+	if (!ubit)
+		addr -= reg_count;
+	addr += (!pbit ^ !ubit);
+
+	reg_bit_vector = insn & 0xffff;
+	while (reg_bit_vector) {
+		int reg = __ffs(reg_bit_vector);
+		reg_bit_vector &= (reg_bit_vector - 1);
+		if (lbit)
+			regs->uregs[reg] = *addr++;
+		else
+			*addr++ = regs->uregs[reg];
+	}
+
+	if (wbit) {
+		if (!ubit)
+			addr -= reg_count;
+		addr -= (!pbit ^ !ubit);
+		regs->uregs[rn] = (long)addr;
+	}
+}
+
+static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+
+	if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn))
+		return;
+
+	regs->ARM_pc = (long)p->addr + str_pc_offset;
+	simulate_ldm1stm1(p, regs);
+	regs->ARM_pc = (long)p->addr + 4;
+}
+
+static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
+{
+	regs->uregs[12] = regs->uregs[13];
+}
+
+static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rn = (insn >> 16) & 0xf;
+	long rnv = regs->uregs[rn];
+
+	/* Save Rn in case of writeback. */
+	regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm = insn & 0xf;  /* rm may be invalid, don't care. */
+
+	/* Not following the C calling convention here, so need asm(). */
+	__asm__ __volatile__ (
+		"ldr	r0, %[rn]	\n\t"
+		"ldr	r1, %[rm]	\n\t"
+		"msr	cpsr_fs, %[cpsr]\n\t"
+		"mov	lr, pc		\n\t"
+		"mov	pc, %[i_fn]	\n\t"
+		"str	r0, %[rn]	\n\t"	/* in case of writeback */
+		"str	r2, %[rd0]	\n\t"
+		"str	r3, %[rd1]	\n\t"
+		: [rn]  "+m" (regs->uregs[rn]),
+		  [rd0] "=m" (regs->uregs[rd]),
+		  [rd1] "=m" (regs->uregs[rd+1])
+		: [rm]   "m" (regs->uregs[rm]),
+		  [cpsr] "r" (regs->ARM_cpsr),
+		  [i_fn] "r" (i_fn)
+		: "r0", "r1", "r2", "r3", "lr", "cc"
+	);
+}
+
+static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm  = insn & 0xf;
+	long rnv = regs->uregs[rn];
+	long rmv = regs->uregs[rm];  /* rm/rmv may be invalid, don't care. */
+
+	regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd],
+					       regs->uregs[rd+1],
+					       regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	union reg_pair fnr;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm = insn & 0xf;
+	long rdv;
+	long rnv  = regs->uregs[rn];
+	long rmv  = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */
+	long cpsr = regs->ARM_cpsr;
+
+	fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn);
+	regs->uregs[rn] = fnr.r0;  /* Save Rn in case of writeback. */
+	rdv = fnr.r1;
+
+	if (rd == 15) {
+#if __LINUX_ARM_ARCH__ >= 5
+		cpsr &= ~PSR_T_BIT;
+		if (rdv & 0x1)
+			cpsr |= PSR_T_BIT;
+		regs->ARM_cpsr = cpsr;
+		rdv &= ~0x1;
+#else
+		rdv &= ~0x2;
+#endif
+	}
+	regs->uregs[rd] = rdv;
+}
+
+static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	long iaddr = (long)p->addr;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm = insn & 0xf;
+	long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd];
+	long rnv = (rn == 15) ? iaddr +  8 : regs->uregs[rn];
+	long rmv = regs->uregs[rm];  /* rm/rmv may be invalid, don't care. */
+
+	/* Save Rn in case of writeback. */
+	regs->uregs[rn] =
+		insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	union reg_pair fnr;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+
+	fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn);
+	regs->uregs[rn] = fnr.r0;
+	regs->uregs[rd] = fnr.r1;
+}
+
+static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	long rnv = regs->uregs[rn];
+	long rdv = regs->uregs[rd];
+
+	insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rm = insn & 0xf;
+	long rmv = regs->uregs[rm];
+
+	/* Writes Q flag */
+	regs->uregs[rd] = insnslot_1arg_rwflags(rmv, &regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm = insn & 0xf;
+	long rnv = regs->uregs[rn];
+	long rmv = regs->uregs[rm];
+
+	/* Reads GE bits */
+	regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
+
+	insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+
+	regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int ird = (insn >> 12) & 0xf;
+
+	insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rn = (insn >> 16) & 0xf;
+	long rnv = regs->uregs[rn];
+
+	insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rm = insn & 0xf;
+	long rmv = regs->uregs[rm];
+
+	regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	int rm = insn & 0xf;
+	long rnv = regs->uregs[rn];
+	long rmv = regs->uregs[rm];
+
+	regs->uregs[rd] =
+		insnslot_2arg_rwflags(rnv, rmv, &regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 16) & 0xf;
+	int rn = (insn >> 12) & 0xf;
+	int rs = (insn >> 8) & 0xf;
+	int rm = insn & 0xf;
+	long rnv = regs->uregs[rn];
+	long rsv = regs->uregs[rs];
+	long rmv = regs->uregs[rm];
+
+	regs->uregs[rd] =
+		insnslot_3arg_rwflags(rnv, rsv, rmv, &regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 16) & 0xf;
+	int rs = (insn >> 8) & 0xf;
+	int rm = insn & 0xf;
+	long rsv = regs->uregs[rs];
+	long rmv = regs->uregs[rm];
+
+	regs->uregs[rd] =
+		insnslot_2arg_rwflags(rsv, rmv, &regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	union reg_pair fnr;
+	int rdhi = (insn >> 16) & 0xf;
+	int rdlo = (insn >> 12) & 0xf;
+	int rs   = (insn >> 8) & 0xf;
+	int rm   = insn & 0xf;
+	long rsv = regs->uregs[rs];
+	long rmv = regs->uregs[rm];
+
+	fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi],
+					     regs->uregs[rdlo], rsv, rmv,
+					     &regs->ARM_cpsr, i_fn);
+	regs->uregs[rdhi] = fnr.r0;
+	regs->uregs[rdlo] = fnr.r1;
+}
+
+static void __kprobes
+emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
+
+	regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;
+	long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn];
+
+	regs->uregs[rd] = insnslot_1arg_rwflags(rnv, &regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	long ppc = (long)p->addr + 8;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;	/* rn/rnv/rs/rsv may be */
+	int rs = (insn >> 8) & 0xf;	/* invalid, don't care. */
+	int rm = insn & 0xf;
+	long rnv = (rn == 15) ? ppc : regs->uregs[rn];
+	long rmv = (rm == 15) ? ppc : regs->uregs[rm];
+	long rsv = regs->uregs[rs];
+
+	regs->uregs[rd] =
+		insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn);
+}
+
+static void __kprobes
+emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs)
+{
+	insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0];
+	kprobe_opcode_t insn = p->opcode;
+	long ppc = (long)p->addr + 8;
+	int rd = (insn >> 12) & 0xf;
+	int rn = (insn >> 16) & 0xf;	/* rn/rnv/rs/rsv may be */
+	int rs = (insn >> 8) & 0xf;	/* invalid, don't care. */
+	int rm = insn & 0xf;
+	long rnv = (rn == 15) ? ppc : regs->uregs[rn];
+	long rmv = (rm == 15) ? ppc : regs->uregs[rm];
+	long rsv = regs->uregs[rs];
+
+	regs->uregs[rd] =
+		insnslot_3arg_rwflags(rnv, rmv, rsv, &regs->ARM_cpsr, i_fn);
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	int ibit = (insn & (1 << 26)) ? 25 : 22;
+
+	insn &= 0xfff00fff;
+	insn |= 0x00001000;	/* Rn = r0, Rd = r1 */
+	if (insn & (1 << ibit)) {
+		insn &= ~0xf;
+		insn |= 2;	/* Rm = r2 */
+	}
+	asi->insn[0] = insn;
+	asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	insn &= 0xffff0ff0;	/* Rd = r0, Rm = r0 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rd12rm0;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	insn &= 0xffff0fff;	/* Rd = r0 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rd12;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn,
+				struct arch_specific_insn *asi)
+{
+	insn &= 0xfff00ff0;	/* Rd = r0, Rn = r0 */
+	insn |= 0x00000001;	/* Rm = r1 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rd12rn16rm0_rwflags;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn,
+			       struct arch_specific_insn *asi)
+{
+	insn &= 0xfff0f0f0;	/* Rd = r0, Rs = r0 */
+	insn |= 0x00000001;	/* Rm = r1          */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rd16rs8rm0_rwflags;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn,
+				   struct arch_specific_insn *asi)
+{
+	insn &= 0xfff000f0;	/* Rd = r0, Rn = r0 */
+	insn |= 0x00000102;	/* Rs = r1, Rm = r2 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn,
+				       struct arch_specific_insn *asi)
+{
+	insn &= 0xfff000f0;	/* RdHi = r0, RdLo = r1 */
+	insn |= 0x00001203;	/* Rs = r2, Rm = r3 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags;
+	return INSN_GOOD;
+}
+
+/*
+ * For the instruction masking and comparisons in all the "space_*"
+ * functions below, Do _not_ rearrange the order of tests unless
+ * you're very, very sure of what you are doing.  For the sake of
+ * efficiency, the masks for some tests sometimes assume other test
+ * have been done prior to them so the number of patterns to test
+ * for an instruction set can be as broad as possible to reduce the
+ * number of tests needed.
+ */
+
+static enum kprobe_insn __kprobes
+space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */
+	/* RFE           : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */
+	/* SRS           : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */
+	if ((insn & 0xfff30020) == 0xf1020000 ||
+	    (insn & 0xfe500f00) == 0xf8100a00 ||
+	    (insn & 0xfe5f0f00) == 0xf84d0500)
+		return INSN_REJECTED;
+
+	/* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */
+	if ((insn & 0xfd700000) == 0xf4500000) {
+		insn &= 0xfff0ffff;	/* Rn = r0 */
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_rn16;
+		return INSN_GOOD;
+	}
+
+	/* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */
+	if ((insn & 0xfe000000) == 0xfa000000) {
+		asi->insn_handler = simulate_blx1;
+		return INSN_GOOD_NO_SLOT;
+	}
+
+	/* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
+	/* CDP2   : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+	if ((insn & 0xffff00f0) == 0xf1010000 ||
+	    (insn & 0xff000010) == 0xfe000000) {
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_none;
+		return INSN_GOOD;
+	}
+
+	/* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
+	/* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */
+	if ((insn & 0xffe00000) == 0xfc400000) {
+		insn &= 0xfff00fff;	/* Rn = r0 */
+		insn |= 0x00001000;	/* Rd = r1 */
+		asi->insn[0] = insn;
+		asi->insn_handler =
+			(insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
+		return INSN_GOOD;
+	}
+
+	/* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+	/* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+	if ((insn & 0xfe000000) == 0xfc000000) {
+		insn &= 0xfff0ffff;      /* Rn = r0 */
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_ldcstc;
+		return INSN_GOOD;
+	}
+
+	/* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+	/* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
+	insn &= 0xffff0fff;	/* Rd = r0 */
+	asi->insn[0]      = insn;
+	asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */
+	if ((insn & 0x0f900010) == 0x01000000) {
+
+		/* BXJ  : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
+		/* MSR  : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
+		if ((insn & 0x0ff000f0) == 0x01200020 ||
+		    (insn & 0x0fb000f0) == 0x01200000)
+			return INSN_REJECTED;
+
+		/* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */
+		if ((insn & 0x0fb00010) == 0x01000000)
+			return prep_emulate_rd12(insn, asi);
+
+		/* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
+		if ((insn & 0x0ff00090) == 0x01400080)
+			return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
+
+		/* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
+		/* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
+		if ((insn & 0x0ff000b0) == 0x012000a0 ||
+		    (insn & 0x0ff00090) == 0x01600080)
+			return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+
+		/* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */
+		/* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */
+		return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+
+	}
+
+	/* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */
+	else if ((insn & 0x0f900090) == 0x01000010) {
+
+		/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
+		if ((insn & 0xfff000f0) == 0xe1200070)
+			return INSN_REJECTED;
+
+		/* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
+		/* BX     : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
+		if ((insn & 0x0ff000d0) == 0x01200010) {
+			asi->insn[0] = truecc_insn(insn);
+			asi->insn_handler = simulate_blx2bx;
+			return INSN_GOOD;
+		}
+
+		/* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
+		if ((insn & 0x0ff000f0) == 0x01600010)
+			return prep_emulate_rd12rm0(insn, asi);
+
+		/* QADD    : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */
+		/* QSUB    : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */
+		/* QDADD   : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */
+		/* QDSUB   : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */
+		return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+	}
+
+	/* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */
+	else if ((insn & 0x0f000090) == 0x00000090) {
+
+		/* MUL    : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx :   */
+		/* MULS   : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */
+		/* MLA    : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx :   */
+		/* MLAS   : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */
+		/* UMAAL  : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx :   */
+		/* UMULL  : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx :   */
+		/* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */
+		/* UMLAL  : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx :   */
+		/* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */
+		/* SMULL  : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx :   */
+		/* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */
+		/* SMLAL  : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx :   */
+		/* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */
+		if ((insn & 0x0fe000f0) == 0x00000090) {
+		       return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+		} else if  ((insn & 0x0fe000f0) == 0x00200090) {
+		       return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+		} else {
+		       return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
+		}
+	}
+
+	/* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */
+	else if ((insn & 0x0e000090) == 0x00000090) {
+
+		/* SWP   : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */
+		/* SWPB  : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */
+		/* LDRD  : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */
+		/* STRD  : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */
+		/* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */
+		/* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */
+		/* LDRH  : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */
+		/* STRH  : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */
+		/* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */
+		/* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */
+		if ((insn & 0x0fb000f0) == 0x01000090) {
+			/* SWP/SWPB */
+			return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+		} else if ((insn & 0x0e1000d0) == 0x00000d0) {
+			/* STRD/LDRD */
+			insn &= 0xfff00fff;
+			insn |= 0x00002000;	/* Rn = r0, Rd = r2 */
+			if (insn & (1 << 22)) {
+				/* I bit */
+				insn &= ~0xf;
+				insn |= 1;	/* Rm = r1 */
+			}
+			asi->insn[0] = insn;
+			asi->insn_handler =
+				(insn & (1 << 5)) ? emulate_strd : emulate_ldrd;
+			return INSN_GOOD;
+		}
+
+		return prep_emulate_ldr_str(insn, asi);
+	}
+
+	/* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */
+
+	/*
+	 * ALU op with S bit and Rd == 15 :
+	 * 	cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx
+	 */
+	if ((insn & 0x0e10f000) == 0x0010f000)
+		return INSN_REJECTED;
+
+	/*
+	 * "mov ip, sp" is the most common kprobe'd instruction by far.
+	 * Check and optimize for it explicitly.
+	 */
+	if (insn == 0xe1a0c00d) {
+		asi->insn_handler = simulate_mov_ipsp;
+		return INSN_GOOD_NO_SLOT;
+	}
+
+	/*
+	 * Data processing: Immediate-shift / Register-shift
+	 * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx
+	 * CPY    : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx
+	 * MOV    : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx
+	 * *S (bit 20) updates condition codes
+	 * ADC/SBC/RSC reads the C flag
+	 */
+	insn &= 0xfff00ff0;	/* Rn = r0, Rd = r0 */
+	insn |= 0x00000001;	/* Rm = r1 */
+	if (insn & 0x010) {
+		insn &= 0xfffff0ff;     /* register shift */
+		insn |= 0x00000200;     /* Rs = r2 */
+	}
+	asi->insn[0] = insn;
+	asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
+				emulate_alu_rwflags : emulate_alu_rflags;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/*
+	 * MSR   : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx
+	 * Undef : cccc 0011 0x00 xxxx xxxx xxxx xxxx xxxx
+	 * ALU op with S bit and Rd == 15 :
+	 *	   cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx
+	 */
+	if ((insn & 0x0f900000) == 0x03200000 ||	/* MSR & Undef */
+	    (insn & 0x0e10f000) == 0x0210f000)		/* ALU s-bit, R15  */
+		return INSN_REJECTED;
+
+	/*
+	 * Data processing: 32-bit Immediate
+	 * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
+	 * MOV    : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx
+	 * *S (bit 20) updates condition codes
+	 * ADC/SBC/RSC reads the C flag
+	 */
+	insn &= 0xfff00ff0;	/* Rn = r0, Rd = r0 */
+	asi->insn[0] = insn;
+	asi->insn_handler = (insn & (1 << 20)) ?  /* S-bit */
+			emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */
+	if ((insn & 0x0ff000f0) == 0x068000b0) {
+		insn &= 0xfff00ff0;	/* Rd = r0, Rn = r0 */
+		insn |= 0x00000001;	/* Rm = r1 */
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_sel;
+		return INSN_GOOD;
+	}
+
+	/* SSAT   : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */
+	/* USAT   : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */
+	/* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */
+	/* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */
+	if ((insn & 0x0fa00030) == 0x06a00010 ||
+	    (insn & 0x0fb000f0) == 0x06a00030) {
+		insn &= 0xffff0ff0;	/* Rd = r0, Rm = r0 */
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_sat;
+		return INSN_GOOD;
+	}
+
+	/* REV    : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
+	/* REV16  : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
+	/* REVSH  : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
+	if ((insn & 0x0ff00070) == 0x06b00030 ||
+	    (insn & 0x0ff000f0) == 0x06f000b0)
+		return prep_emulate_rd12rm0(insn, asi);
+
+	/* SADD16    : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */
+	/* SADDSUBX  : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */
+	/* SSUBADDX  : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */
+	/* SSUB16    : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */
+	/* SADD8     : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */
+	/* SSUB8     : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */
+	/* QADD16    : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx :   */
+	/* QADDSUBX  : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx :   */
+	/* QSUBADDX  : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx :   */
+	/* QSUB16    : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx :   */
+	/* QADD8     : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx :   */
+	/* QSUB8     : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx :   */
+	/* SHADD16   : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx :   */
+	/* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx :   */
+	/* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx :   */
+	/* SHSUB16   : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx :   */
+	/* SHADD8    : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx :   */
+	/* SHSUB8    : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx :   */
+	/* UADD16    : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */
+	/* UADDSUBX  : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */
+	/* USUBADDX  : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */
+	/* USUB16    : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */
+	/* UADD8     : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */
+	/* USUB8     : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */
+	/* UQADD16   : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx :   */
+	/* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx :   */
+	/* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx :   */
+	/* UQSUB16   : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx :   */
+	/* UQADD8    : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx :   */
+	/* UQSUB8    : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx :   */
+	/* UHADD16   : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx :   */
+	/* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx :   */
+	/* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx :   */
+	/* UHSUB16   : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx :   */
+	/* UHADD8    : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx :   */
+	/* UHSUB8    : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx :   */
+	/* PKHBT     : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx :   */
+	/* PKHTB     : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx :   */
+	/* SXTAB16   : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx :   */
+	/* SXTB      : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
+	/* SXTAB     : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx :   */
+	/* SXTAH     : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx :   */
+	/* UXTAB16   : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx :   */
+	/* UXTAB     : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx :   */
+	/* UXTAH     : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx :   */
+	return prep_emulate_rd12rn16rm0_wflags(insn, asi);
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
+	if ((insn & 0x0ff000f0) == 0x03f000f0)
+		return INSN_REJECTED;
+
+	/* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
+	/* USAD8  : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
+	if ((insn & 0x0ff000f0) == 0x07800010)
+		 return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+
+	/* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
+	/* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
+	if ((insn & 0x0ff00090) == 0x07400010)
+		return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi);
+
+	/* SMLAD  : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */
+	/* SMLSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */
+	/* SMMLA  : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx :  */
+	/* SMMLS  : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx :  */
+	if ((insn & 0x0ff00090) == 0x07000010 ||
+	    (insn & 0x0ff000d0) == 0x07500010 ||
+	    (insn & 0x0ff000d0) == 0x075000d0)
+		return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi);
+
+	/* SMUSD  : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :  */
+	/* SMUAD  : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */
+	/* SMMUL  : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx :  */
+	return prep_emulate_rd16rs8rm0_wflags(insn, asi);
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* LDR   : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */
+	/* LDRB  : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */
+	/* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
+	/* LDRT  : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
+	/* STR   : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */
+	/* STRB  : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */
+	/* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
+	/* STRT  : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
+	return prep_emulate_ldr_str(insn, asi);
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */
+	/* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
+	if ((insn & 0x0e708000) == 0x85000000 ||
+	    (insn & 0x0e508000) == 0x85010000)
+		return INSN_REJECTED;
+
+	/* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
+	/* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
+	asi->insn[0] = truecc_insn(insn);
+	asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */
+				simulate_stm1_pc : simulate_ldm1stm1;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* B  : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
+	/* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
+	asi->insn[0] = truecc_insn(insn);
+	asi->insn_handler = simulate_bbl;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
+	/* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */
+	insn &= 0xfff00fff;
+	insn |= 0x00001000;	/* Rn = r0, Rd = r1 */
+	asi->insn[0] = insn;
+	asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
+	/* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
+	insn &= 0xfff0ffff;	/* Rn = r0 */
+	asi->insn[0] = insn;
+	asi->insn_handler = emulate_ldcstc;
+	return INSN_GOOD;
+}
+
+static enum kprobe_insn __kprobes
+space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	/* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
+	/* SWI  : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
+	if ((insn & 0xfff000f0) == 0xe1200070 ||
+	    (insn & 0x0f000000) == 0x0f000000)
+		return INSN_REJECTED;
+
+	/* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
+	if ((insn & 0x0f000010) == 0x0e000000) {
+		asi->insn[0] = insn;
+		asi->insn_handler = emulate_none;
+		return INSN_GOOD;
+	}
+
+	/* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
+	/* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
+	insn &= 0xffff0fff;	/* Rd = r0 */
+	asi->insn[0] = insn;
+	asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12;
+	return INSN_GOOD;
+}
+
+/* Return:
+ *   INSN_REJECTED     If instruction is one not allowed to kprobe,
+ *   INSN_GOOD         If instruction is supported and uses instruction slot,
+ *   INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
+ *
+ * For instructions we don't want to kprobe (INSN_REJECTED return result):
+ *   These are generally ones that modify the processor state making
+ *   them "hard" to simulate such as switches processor modes or
+ *   make accesses in alternate modes.  Any of these could be simulated
+ *   if the work was put into it, but low return considering they
+ *   should also be very rare.
+ */
+enum kprobe_insn __kprobes
+arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+{
+	asi->insn[1] = KPROBE_RETURN_INSTRUCTION;
+
+	if ((insn & 0xf0000000) == 0xf0000000) {
+
+		return space_1111(insn, asi);
+
+	} else if ((insn & 0x0e000000) == 0x00000000) {
+
+		return space_cccc_000x(insn, asi);
+
+	} else if ((insn & 0x0e000000) == 0x02000000) {
+
+		return space_cccc_001x(insn, asi);
+
+	} else if ((insn & 0x0f000010) == 0x06000010) {
+
+		return space_cccc_0110__1(insn, asi);
+
+	} else if ((insn & 0x0f000010) == 0x07000010) {
+
+		return space_cccc_0111__1(insn, asi);
+
+	} else if ((insn & 0x0c000000) == 0x04000000) {
+
+		return space_cccc_01xx(insn, asi);
+
+	} else if ((insn & 0x0e000000) == 0x08000000) {
+
+		return space_cccc_100x(insn, asi);
+
+	} else if ((insn & 0x0e000000) == 0x0a000000) {
+
+		return space_cccc_101x(insn, asi);
+
+	} else if ((insn & 0x0fe00000) == 0x0c400000) {
+
+		return space_cccc_1100_010x(insn, asi);
+
+	} else if ((insn & 0x0e000000) == 0x0c400000) {
+
+		return space_cccc_110x(insn, asi);
+
+	}
+
+	return space_cccc_111x(insn, asi);
+}
+
+void __init arm_kprobe_decode_init(void)
+{
+	find_str_pc_offset();
+}
+
+
+/*
+ * All ARM instructions listed below.
+ *
+ * Instructions and their general purpose registers are given.
+ * If a particular register may not use R15, it is prefixed with a "!".
+ * If marked with a "*" means the value returned by reading R15
+ * is implementation defined.
+ *
+ * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ
+ *     TST: Rd, Rn, Rm, !Rs
+ * BX: Rm
+ * BLX(2): !Rm
+ * BX: Rm (R15 legal, but discouraged)
+ * BXJ: !Rm,
+ * CLZ: !Rd, !Rm
+ * CPY: Rd, Rm
+ * LDC/2,STC/2 immediate offset & unindex: Rn
+ * LDC/2,STC/2 immediate pre/post-indexed: !Rn
+ * LDM(1/3): !Rn, register_list
+ * LDM(2): !Rn, !register_list
+ * LDR,STR,PLD immediate offset: Rd, Rn
+ * LDR,STR,PLD register offset: Rd, Rn, !Rm
+ * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm
+ * LDR,STR immediate pre/post-indexed: Rd, !Rn
+ * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm
+ * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm
+ * LDRB,STRB immediate offset: !Rd, Rn
+ * LDRB,STRB register offset: !Rd, Rn, !Rm
+ * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm
+ * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn
+ * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm
+ * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm
+ * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn
+ * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm
+ * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm
+ * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn
+ * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm
+ * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn
+ * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm
+ * LDREX: !Rd, !Rn
+ * MCR/2: !Rd
+ * MCRR/2,MRRC/2: !Rd, !Rn
+ * MLA: !Rd, !Rn, !Rm, !Rs
+ * MOV: Rd
+ * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register)
+ * MRS,MSR: !Rd
+ * MUL: !Rd, !Rm, !Rs
+ * PKH{BT,TB}: !Rd, !Rn, !Rm
+ * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn
+ * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn
+ * REV/16/SH: !Rd, !Rm
+ * RFE: !Rn
+ * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm
+ * SEL: !Rd, !Rn, !Rm
+ * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs
+ * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs
+ * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs
+ * SSAT/16: !Rd, !Rm
+ * STM(1/2): !Rn, register_list* (R15 in reg list not recommended)
+ * STRT immediate pre/post-indexed: Rd*, !Rn
+ * STRT register pre/post-indexed: Rd*, !Rn, !Rm
+ * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm
+ * STREX: !Rd, !Rn, !Rm
+ * SWP/B: !Rd, !Rn, !Rm
+ * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm
+ * {S,U}XT{B,B16,H}: !Rd, !Rm
+ * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs
+ * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs
+ *
+ * May transfer control by writing R15 (possible mode changes or alternate
+ * mode accesses marked by "*"):
+ * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY,
+ * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI*
+ *
+ * Instructions that do not take general registers, nor transfer control:
+ * CDP/2, SETEND, SRS*
+ */
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
new file mode 100644
index 0000000..a22a98c
--- /dev/null
+++ b/arch/arm/kernel/kprobes.c
@@ -0,0 +1,447 @@
+/*
+ * arch/arm/kernel/kprobes.c
+ *
+ * Kprobes on ARM
+ *
+ * Abhishek Sagar <sagar.abhishek@gmail.com>
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * Nicolas Pitre <nico@marvell.com>
+ * Copyright (C) 2007 Marvell 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 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
+
+#define MIN_STACK_SIZE(addr) 				\
+	min((unsigned long)MAX_STACK_SIZE,		\
+	    (unsigned long)current_thread_info() + THREAD_START_SP - (addr))
+
+#define flush_insns(addr, cnt) 				\
+	flush_icache_range((unsigned long)(addr),	\
+			   (unsigned long)(addr) +	\
+			   sizeof(kprobe_opcode_t) * (cnt))
+
+/* Used as a marker in ARM_pc to note when we're in a jprobe. */
+#define JPROBE_MAGIC_ADDR		0xffffffff
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+	kprobe_opcode_t insn;
+	kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
+	unsigned long addr = (unsigned long)p->addr;
+	int is;
+
+	if (addr & 0x3 || in_exception_text(addr))
+		return -EINVAL;
+
+	insn = *p->addr;
+	p->opcode = insn;
+	p->ainsn.insn = tmp_insn;
+
+	switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
+	case INSN_REJECTED:	/* not supported */
+		return -EINVAL;
+
+	case INSN_GOOD:		/* instruction uses slot */
+		p->ainsn.insn = get_insn_slot();
+		if (!p->ainsn.insn)
+			return -ENOMEM;
+		for (is = 0; is < MAX_INSN_SIZE; ++is)
+			p->ainsn.insn[is] = tmp_insn[is];
+		flush_insns(&p->ainsn.insn, MAX_INSN_SIZE);
+		break;
+
+	case INSN_GOOD_NO_SLOT:	/* instruction doesn't need insn slot */
+		p->ainsn.insn = NULL;
+		break;
+	}
+
+	return 0;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+	*p->addr = KPROBE_BREAKPOINT_INSTRUCTION;
+	flush_insns(p->addr, 1);
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+	*p->addr = p->opcode;
+	flush_insns(p->addr, 1);
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+	if (p->ainsn.insn) {
+		mutex_lock(&kprobe_mutex);
+		free_insn_slot(p->ainsn.insn, 0);
+		mutex_unlock(&kprobe_mutex);
+		p->ainsn.insn = NULL;
+	}
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	kcb->prev_kprobe.kp = kprobe_running();
+	kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+	__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+	kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p)
+{
+	__get_cpu_var(current_kprobe) = p;
+}
+
+static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
+				 struct kprobe_ctlblk *kcb)
+{
+	regs->ARM_pc += 4;
+	p->ainsn.insn_handler(p, regs);
+}
+
+/*
+ * Called with IRQs disabled. IRQs must remain disabled from that point
+ * all the way until processing this kprobe is complete.  The current
+ * kprobes implementation cannot process more than one nested level of
+ * kprobe, and that level is reserved for user kprobe handlers, so we can't
+ * risk encountering a new kprobe in an interrupt handler.
+ */
+void __kprobes kprobe_handler(struct pt_regs *regs)
+{
+	struct kprobe *p, *cur;
+	struct kprobe_ctlblk *kcb;
+	kprobe_opcode_t	*addr = (kprobe_opcode_t *)regs->ARM_pc;
+
+	kcb = get_kprobe_ctlblk();
+	cur = kprobe_running();
+	p = get_kprobe(addr);
+
+	if (p) {
+		if (cur) {
+			/* Kprobe is pending, so we're recursing. */
+			switch (kcb->kprobe_status) {
+			case KPROBE_HIT_ACTIVE:
+			case KPROBE_HIT_SSDONE:
+				/* A pre- or post-handler probe got us here. */
+				kprobes_inc_nmissed_count(p);
+				save_previous_kprobe(kcb);
+				set_current_kprobe(p);
+				kcb->kprobe_status = KPROBE_REENTER;
+				singlestep(p, regs, kcb);
+				restore_previous_kprobe(kcb);
+				break;
+			default:
+				/* impossible cases */
+				BUG();
+			}
+		} else {
+			set_current_kprobe(p);
+			kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+			/*
+			 * If we have no pre-handler or it returned 0, we
+			 * continue with normal processing.  If we have a
+			 * pre-handler and it returned non-zero, it prepped
+			 * for calling the break_handler below on re-entry,
+			 * so get out doing nothing more here.
+			 */
+			if (!p->pre_handler || !p->pre_handler(p, regs)) {
+				kcb->kprobe_status = KPROBE_HIT_SS;
+				singlestep(p, regs, kcb);
+				if (p->post_handler) {
+					kcb->kprobe_status = KPROBE_HIT_SSDONE;
+					p->post_handler(p, regs, 0);
+				}
+				reset_current_kprobe();
+			}
+		}
+	} else if (cur) {
+		/* We probably hit a jprobe.  Call its break handler. */
+		if (cur->break_handler && cur->break_handler(cur, regs)) {
+			kcb->kprobe_status = KPROBE_HIT_SS;
+			singlestep(cur, regs, kcb);
+			if (cur->post_handler) {
+				kcb->kprobe_status = KPROBE_HIT_SSDONE;
+				cur->post_handler(cur, regs, 0);
+			}
+		}
+		reset_current_kprobe();
+	} else {
+		/*
+		 * The probe was removed and a race is in progress.
+		 * There is nothing we can do about it.  Let's restart
+		 * the instruction.  By the time we can restart, the
+		 * real instruction will be there.
+		 */
+	}
+}
+
+int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
+{
+	kprobe_handler(regs);
+	return 0;
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
+{
+	struct kprobe *cur = kprobe_running();
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	switch (kcb->kprobe_status) {
+	case KPROBE_HIT_SS:
+	case KPROBE_REENTER:
+		/*
+		 * We are here because the instruction being single
+		 * stepped caused a page fault. We reset the current
+		 * kprobe and the PC to point back to the probe address
+		 * and allow the page fault handler to continue as a
+		 * normal page fault.
+		 */
+		regs->ARM_pc = (long)cur->addr;
+		if (kcb->kprobe_status == KPROBE_REENTER) {
+			restore_previous_kprobe(kcb);
+		} else {
+			reset_current_kprobe();
+		}
+		break;
+
+	case KPROBE_HIT_ACTIVE:
+	case KPROBE_HIT_SSDONE:
+		/*
+		 * We increment the nmissed count for accounting,
+		 * we can also use npre/npostfault count for accounting
+		 * these specific fault cases.
+		 */
+		kprobes_inc_nmissed_count(cur);
+
+		/*
+		 * We come here because instructions in the pre/post
+		 * handler caused the page_fault, this could happen
+		 * if handler tries to access user space by
+		 * copy_from_user(), get_user() etc. Let the
+		 * user-specified handler try to fix it.
+		 */
+		if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
+			return 1;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+				       unsigned long val, void *data)
+{
+	/*
+	 * notify_die() is currently never called on ARM,
+	 * so this callback is currently empty.
+	 */
+	return NOTIFY_DONE;
+}
+
+/*
+ * When a retprobed function returns, trampoline_handler() is called,
+ * calling the kretprobe's handler. We construct a struct pt_regs to
+ * give a view of registers r0-r11 to the user return-handler.  This is
+ * not a complete pt_regs structure, but that should be plenty sufficient
+ * for kretprobe handlers which should normally be interested in r0 only
+ * anyway.
+ */
+static void __attribute__((naked)) __kprobes kretprobe_trampoline(void)
+{
+	__asm__ __volatile__ (
+		"stmdb	sp!, {r0 - r11}		\n\t"
+		"mov	r0, sp			\n\t"
+		"bl	trampoline_handler	\n\t"
+		"mov	lr, r0			\n\t"
+		"ldmia	sp!, {r0 - r11}		\n\t"
+		"mov	pc, lr			\n\t"
+		: : : "memory");
+}
+
+/* Called from kretprobe_trampoline */
+static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
+{
+	struct kretprobe_instance *ri = NULL;
+	struct hlist_head *head, empty_rp;
+	struct hlist_node *node, *tmp;
+	unsigned long flags, orig_ret_address = 0;
+	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+
+	INIT_HLIST_HEAD(&empty_rp);
+	spin_lock_irqsave(&kretprobe_lock, flags);
+	head = kretprobe_inst_table_head(current);
+
+	/*
+	 * It is possible to have multiple instances associated with a given
+	 * task either because multiple functions in the call path have
+	 * a return probe installed on them, and/or more than one return
+	 * probe was registered for a target function.
+	 *
+	 * We can handle this because:
+	 *     - instances are always inserted at the head of the list
+	 *     - when multiple return probes are registered for the same
+	 *       function, the first instance's ret_addr will point to the
+	 *       real return address, and all the rest will point to
+	 *       kretprobe_trampoline
+	 */
+	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
+
+		if (ri->rp && ri->rp->handler) {
+			__get_cpu_var(current_kprobe) = &ri->rp->kp;
+			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
+			ri->rp->handler(ri, regs);
+			__get_cpu_var(current_kprobe) = NULL;
+		}
+
+		orig_ret_address = (unsigned long)ri->ret_addr;
+		recycle_rp_inst(ri, &empty_rp);
+
+		if (orig_ret_address != trampoline_address)
+			/*
+			 * This is the real return address. Any other
+			 * instances associated with this task are for
+			 * other calls deeper on the call stack
+			 */
+			break;
+	}
+
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+	spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+		hlist_del(&ri->hlist);
+		kfree(ri);
+	}
+
+	return (void *)orig_ret_address;
+}
+
+/* Called with kretprobe_lock held. */
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+				      struct pt_regs *regs)
+{
+	ri->ret_addr = (kprobe_opcode_t *)regs->ARM_lr;
+
+	/* Replace the return addr with trampoline addr. */
+	regs->ARM_lr = (unsigned long)&kretprobe_trampoline;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long sp_addr = regs->ARM_sp;
+
+	kcb->jprobe_saved_regs = *regs;
+	memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
+	regs->ARM_pc = (long)jp->entry;
+	regs->ARM_cpsr |= PSR_I_BIT;
+	preempt_disable();
+	return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+	__asm__ __volatile__ (
+		/*
+		 * Setup an empty pt_regs. Fill SP and PC fields as
+		 * they're needed by longjmp_break_handler.
+		 */
+		"sub    sp, %0, %1		\n\t"
+		"ldr    r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
+		"str    %0, [sp, %2]		\n\t"
+		"str    r0, [sp, %3]		\n\t"
+		"mov    r0, sp			\n\t"
+		"bl     kprobe_handler		\n\t"
+
+		/*
+		 * Return to the context saved by setjmp_pre_handler
+		 * and restored by longjmp_break_handler.
+		 */
+		"ldr	r0, [sp, %4]		\n\t"
+		"msr	cpsr_cxsf, r0		\n\t"
+		"ldmia	sp, {r0 - pc}		\n\t"
+		:
+		: "r" (kcb->jprobe_saved_regs.ARM_sp),
+		  "I" (sizeof(struct pt_regs)),
+		  "J" (offsetof(struct pt_regs, ARM_sp)),
+		  "J" (offsetof(struct pt_regs, ARM_pc)),
+		  "J" (offsetof(struct pt_regs, ARM_cpsr))
+		: "memory", "cc");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+	long stack_addr = kcb->jprobe_saved_regs.ARM_sp;
+	long orig_sp = regs->ARM_sp;
+	struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+	if (regs->ARM_pc == JPROBE_MAGIC_ADDR) {
+		if (orig_sp != stack_addr) {
+			struct pt_regs *saved_regs =
+				(struct pt_regs *)kcb->jprobe_saved_regs.ARM_sp;
+			printk("current sp %lx does not match saved sp %lx\n",
+			       orig_sp, stack_addr);
+			printk("Saved registers for jprobe %p\n", jp);
+			show_regs(saved_regs);
+			printk("Current registers\n");
+			show_regs(regs);
+			BUG();
+		}
+		*regs = kcb->jprobe_saved_regs;
+		memcpy((void *)stack_addr, kcb->jprobes_stack,
+		       MIN_STACK_SIZE(stack_addr));
+		preempt_enable_no_resched();
+		return 1;
+	}
+	return 0;
+}
+
+static struct undef_hook kprobes_break_hook = {
+	.instr_mask	= 0xffffffff,
+	.instr_val	= KPROBE_BREAKPOINT_INSTRUCTION,
+	.cpsr_mask	= MODE_MASK,
+	.cpsr_val	= SVC_MODE,
+	.fn		= kprobe_trap_handler,
+};
+
+int __init arch_init_kprobes()
+{
+	arm_kprobe_decode_init();
+	register_undef_hook(&kprobes_break_hook);
+	return 0;
+}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index e59b5b8..b5867ec 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -325,7 +325,9 @@
 	profile_tick(CPU_PROFILING);
 	do_leds();
 	do_set_rtc();
+	write_seqlock(&xtime_lock);
 	do_timer(1);
+	write_sequnlock(&xtime_lock);
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
 #endif
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index c34db4e..5595fdd 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -19,6 +19,7 @@
 #include <linux/kallsyms.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/kprobes.h>
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
@@ -46,15 +47,6 @@
 
 static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
 
-static inline int in_exception_text(unsigned long ptr)
-{
-	extern char __exception_text_start[];
-	extern char __exception_text_end[];
-
-	return ptr >= (unsigned long)&__exception_text_start &&
-	       ptr < (unsigned long)&__exception_text_end;
-}
-
 void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
 {
 #ifdef CONFIG_KALLSYMS
@@ -322,6 +314,17 @@
 		get_user(instr, (u32 __user *)pc);
 	}
 
+#ifdef CONFIG_KPROBES
+	/*
+	 * It is possible to have recursive kprobes, so we can't call
+	 * the kprobe trap handler with the undef_lock held.
+	 */
+	if (instr == KPROBE_BREAKPOINT_INSTRUCTION && !user_mode(regs)) {
+		kprobe_trap_handler(regs, instr);
+		return;
+	}
+#endif
+
 	spin_lock_irqsave(&undef_lock, flags);
 	list_for_each_entry(hook, &undef_hook, node) {
 		if ((instr & hook->instr_mask) == hook->instr_val &&
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 5ff5406..30f732c 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -94,6 +94,7 @@
 			TEXT_TEXT
 			SCHED_TEXT
 			LOCK_TEXT
+			KPROBES_TEXT
 #ifdef CONFIG_MMU
 			*(.fixup)
 #endif
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index 0446ef2..b016be2 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -130,13 +130,9 @@
 aaec2000_timer_interrupt(int irq, void *dev_id)
 {
 	/* TODO: Check timer accuracy */
-	write_seqlock(&xtime_lock);
-
 	timer_tick();
 	TIMER1_CLEAR = 1;
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 05a9f8a..5b0422c 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -22,6 +22,9 @@
 config ARCH_AT91SAM9RL
 	bool "AT91SAM9RL"
 
+config ARCH_AT91CAP9
+	bool "AT91CAP9"
+
 config ARCH_AT91X40
 	bool "AT91x40"
 
@@ -178,6 +181,21 @@
 
 # ----------------------------------------------------------
 
+if ARCH_AT91CAP9
+
+comment "AT91CAP9 Board Type"
+
+config MACH_AT91CAP9ADK
+	bool "Atmel AT91CAP9A-DK Evaluation Kit"
+	depends on ARCH_AT91CAP9
+	help
+	  Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
+	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
+
+endif
+
+# ----------------------------------------------------------
+
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
@@ -198,13 +216,13 @@
 
 config MTD_AT91_DATAFLASH_CARD
 	bool "Enable DataFlash Card support"
-	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK)
+	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91CAP9ADK)
 	help
 	  Enable support for the DataFlash card.
 
 config MTD_NAND_AT91_BUSWIDTH_16
 	bool "Enable 16-bit data bus interface to NAND flash"
-	depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK)
+	depends on (MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91CAP9ADK)
 	help
 	  On AT91SAM926x boards both types of NAND flash can be present
 	  (8 and 16 bit data bus width).
@@ -219,6 +237,22 @@
 	  Select this if you need to program one or more of the PCK0..PCK3
 	  programmable clock outputs.
 
+config AT91_TIMER_HZ
+       int "Kernel HZ (jiffies per second)"
+       range 32 1024
+       depends on ARCH_AT91
+       default "128" if ARCH_AT91RM9200
+       default "100"
+       help
+	  On AT91rm9200 chips where you're using a system clock derived
+	  from the 32768 Hz hardware clock, this tick rate should divide
+	  it exactly: use a power-of-two value, such as 128 or 256, to
+	  reduce timing errors caused by rounding.
+
+	  On AT91sam926x chips, or otherwise when using a higher precision
+	  system clock (of at least several MHz), rounding is less of a
+	  problem so it can be safer to use a decimal values like 100.
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index a21f08c..bf5f293 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -8,7 +8,6 @@
 obj-		:=
 
 obj-$(CONFIG_AT91_PMC_UNIT)	+= clock.o
-obj-$(CONFIG_PM)		+= pm.o
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
@@ -16,6 +15,7 @@
 obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o
+obj-$(CONFIG_ARCH_AT91CAP9)	+= at91cap9.o at91sam926x_time.o at91cap9_devices.o
 obj-$(CONFIG_ARCH_AT91X40)	+= at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -29,7 +29,6 @@
 obj-$(CONFIG_MACH_ATEB9200)	+= board-eb9200.o
 obj-$(CONFIG_MACH_KAFA)		+= board-kafa.o
 obj-$(CONFIG_MACH_PICOTUX2XX)	+= board-picotux200.o
-obj-$(CONFIG_MACH_AT91EB01)	+= board-eb01.o
 
 # AT91SAM9260 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
@@ -43,19 +42,17 @@
 # AT91SAM9RL board-specific support
 obj-$(CONFIG_MACH_AT91SAM9RLEK)	+= board-sam9rlek.o
 
-# LEDs support
-led-$(CONFIG_ARCH_AT91RM9200DK)	+= leds.o
-led-$(CONFIG_MACH_AT91RM9200EK)	+= leds.o
-led-$(CONFIG_MACH_AT91SAM9261EK)+= leds.o
-led-$(CONFIG_MACH_CSB337)	+= leds.o
-led-$(CONFIG_MACH_CSB637)	+= leds.o
-led-$(CONFIG_MACH_KB9200)	+= leds.o
-led-$(CONFIG_MACH_KAFA)		+= leds.o
-obj-$(CONFIG_LEDS) += $(led-y)
+# AT91CAP9 board-specific support
+obj-$(CONFIG_MACH_AT91CAP9ADK)	+= board-cap9adk.o
 
-# VGA support
-#obj-$(CONFIG_FB_S1D13XXX)	+= ics1523.o
+# AT91X40 board-specific support
+obj-$(CONFIG_MACH_AT91EB01)	+= board-eb01.o
 
+# Drivers
+obj-y				+= leds.o
+
+# Power Management
+obj-$(CONFIG_PM)		+= pm.o
 
 ifeq ($(CONFIG_PM_DEBUG),y)
 CFLAGS_pm.o += -DDEBUG
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index e667dcc..071a250 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -3,7 +3,12 @@
 #   PARAMS_PHYS must be within 4MB of ZRELADDR
 #   INITRD_PHYS must be in RAM
 
+ifeq ($(CONFIG_ARCH_AT91CAP9),y)
+   zreladdr-y	:= 0x70008000
+params_phys-y	:= 0x70000100
+initrd_phys-y	:= 0x70410000
+else
    zreladdr-y	:= 0x20008000
 params_phys-y	:= 0x20000100
 initrd_phys-y	:= 0x20410000
-
+endif
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
new file mode 100644
index 0000000..48d27d8
--- /dev/null
+++ b/arch/arm/mach-at91/at91cap9.c
@@ -0,0 +1,365 @@
+/*
+ * arch/arm/mach-at91/at91cap9.c
+ *
+ *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
+ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
+ *  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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/at91cap9.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
+
+#include "generic.h"
+#include "clock.h"
+
+static struct map_desc at91cap9_io_desc[] __initdata = {
+	{
+		.virtual	= AT91_VA_BASE_SYS,
+		.pfn		= __phys_to_pfn(AT91_BASE_SYS),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= AT91_IO_VIRT_BASE - AT91CAP9_SRAM_SIZE,
+		.pfn		= __phys_to_pfn(AT91CAP9_SRAM_BASE),
+		.length		= AT91CAP9_SRAM_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioABCD_clk = {
+	.name		= "pioABCD_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_PIOABCD,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mpb0_clk = {
+	.name		= "mpb0_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MPB0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mpb1_clk = {
+	.name		= "mpb1_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MPB1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mpb2_clk = {
+	.name		= "mpb2_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MPB2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mpb3_clk = {
+	.name		= "mpb3_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MPB3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mpb4_clk = {
+	.name		= "mpb4_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MPB4,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_US0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_US1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_US2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+	.name		= "mci0_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MCI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+	.name		= "mci1_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_MCI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk can_clk = {
+	.name		= "can_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_CAN,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+	.name		= "twi_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_TWI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc0_clk = {
+	.name		= "ssc0_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_SSC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+	.name		= "ac97_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_AC97C,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+	.name		= "tcb_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_TCB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwmc_clk = {
+	.name		= "pwmc_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_PWMC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+	.name		= "macb_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_EMAC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk aestdes_clk = {
+	.name		= "aestdes_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_AESTDES,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+	.name		= "adc_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_ADC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk isi_clk = {
+	.name		= "isi_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_ISI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+	.name		= "lcdc_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_LCDC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma_clk = {
+	.name		= "dma_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_DMA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+	.name		= "udphs_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_UDPHS,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+	.name		= "ohci_clk",
+	.pmc_mask	= 1 << AT91CAP9_ID_UHP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+	&pioABCD_clk,
+	&mpb0_clk,
+	&mpb1_clk,
+	&mpb2_clk,
+	&mpb3_clk,
+	&mpb4_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&mmc0_clk,
+	&mmc1_clk,
+	&can_clk,
+	&twi_clk,
+	&spi0_clk,
+	&spi1_clk,
+	&ssc0_clk,
+	&ssc1_clk,
+	&ac97_clk,
+	&tcb_clk,
+	&pwmc_clk,
+	&macb_clk,
+	&aestdes_clk,
+	&adc_clk,
+	&isi_clk,
+	&lcdc_clk,
+	&dma_clk,
+	&udphs_clk,
+	&ohci_clk,
+	// irq0 .. irq1
+};
+
+/*
+ * The four programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+	.name		= "pck0",
+	.pmc_mask	= AT91_PMC_PCK0,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 0,
+};
+static struct clk pck1 = {
+	.name		= "pck1",
+	.pmc_mask	= AT91_PMC_PCK1,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 1,
+};
+static struct clk pck2 = {
+	.name		= "pck2",
+	.pmc_mask	= AT91_PMC_PCK2,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 2,
+};
+static struct clk pck3 = {
+	.name		= "pck3",
+	.pmc_mask	= AT91_PMC_PCK3,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 3,
+};
+
+static void __init at91cap9_register_clocks(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+		clk_register(periph_clocks[i]);
+
+	clk_register(&pck0);
+	clk_register(&pck1);
+	clk_register(&pck2);
+	clk_register(&pck3);
+}
+
+/* --------------------------------------------------------------------
+ *  GPIO
+ * -------------------------------------------------------------------- */
+
+static struct at91_gpio_bank at91cap9_gpio[] = {
+	{
+		.id		= AT91CAP9_ID_PIOABCD,
+		.offset		= AT91_PIOA,
+		.clock		= &pioABCD_clk,
+	}, {
+		.id		= AT91CAP9_ID_PIOABCD,
+		.offset		= AT91_PIOB,
+		.clock		= &pioABCD_clk,
+	}, {
+		.id		= AT91CAP9_ID_PIOABCD,
+		.offset		= AT91_PIOC,
+		.clock		= &pioABCD_clk,
+	}, {
+		.id		= AT91CAP9_ID_PIOABCD,
+		.offset		= AT91_PIOD,
+		.clock		= &pioABCD_clk,
+	}
+};
+
+static void at91cap9_reset(void)
+{
+	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+}
+
+/* --------------------------------------------------------------------
+ *  AT91CAP9 processor initialization
+ * -------------------------------------------------------------------- */
+
+void __init at91cap9_initialize(unsigned long main_clock)
+{
+	/* Map peripherals */
+	iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
+
+	at91_arch_reset = at91cap9_reset;
+	at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
+
+	/* Init clock subsystem */
+	at91_clock_init(main_clock);
+
+	/* Register the processor-specific clocks */
+	at91cap9_register_clocks();
+
+	/* Register GPIO subsystem */
+	at91_gpio_init(at91cap9_gpio, 4);
+}
+
+/* --------------------------------------------------------------------
+ *  Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
+	7,	/* Advanced Interrupt Controller (FIQ) */
+	7,	/* System Peripherals */
+	1,	/* Parallel IO Controller A, B, C and D */
+	0,	/* MP Block Peripheral 0 */
+	0,	/* MP Block Peripheral 1 */
+	0,	/* MP Block Peripheral 2 */
+	0,	/* MP Block Peripheral 3 */
+	0,	/* MP Block Peripheral 4 */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
+	0,	/* Multimedia Card Interface 0 */
+	0,	/* Multimedia Card Interface 1 */
+	3,	/* CAN */
+	6,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface 0 */
+	5,	/* Serial Peripheral Interface 1 */
+	4,	/* Serial Synchronous Controller 0 */
+	4,	/* Serial Synchronous Controller 1 */
+	5,	/* AC97 Controller */
+	0,	/* Timer Counter 0, 1 and 2 */
+	0,	/* Pulse Width Modulation Controller */
+	3,	/* Ethernet */
+	0,	/* Advanced Encryption Standard, Triple DES*/
+	0,	/* Analog-to-Digital Converter */
+	0,	/* Image Sensor Interface */
+	3,	/* LCD Controller */
+	0,	/* DMA Controller */
+	2,	/* USB Device Port */
+	2,	/* USB Host port */
+	0,	/* Advanced Interrupt Controller (IRQ0) */
+	0,	/* Advanced Interrupt Controller (IRQ1) */
+};
+
+void __init at91cap9_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+{
+	if (!priority)
+		priority = at91cap9_default_irq_priority;
+
+	/* Initialize the AIC interrupt controller */
+	at91_aic_init(priority);
+
+	/* Enable GPIO interrupts */
+	at91_gpio_irq_setup();
+}
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
new file mode 100644
index 0000000..c50fad9
--- /dev/null
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -0,0 +1,1066 @@
+/*
+ * arch/arm/mach-at91/at91cap9_devices.c
+ *
+ *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
+ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
+ *  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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91cap9.h>
+#include <asm/arch/at91sam926x_mc.h>
+#include <asm/arch/at91cap9_matrix.h>
+
+#include "generic.h"
+
+
+/* --------------------------------------------------------------------
+ *  USB Host
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_data;
+
+static struct resource usbh_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_UHP_BASE,
+		.end	= AT91CAP9_UHP_BASE + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_UHP,
+		.end	= AT91CAP9_ID_UHP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_usbh_device = {
+	.name		= "at91_ohci",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &ohci_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &usbh_data,
+	},
+	.resource	= usbh_resources,
+	.num_resources	= ARRAY_SIZE(usbh_resources),
+};
+
+void __init at91_add_device_usbh(struct at91_usbh_data *data)
+{
+	int i;
+
+	if (!data)
+		return;
+
+	/* Enable VBus control for UHP ports */
+	for (i = 0; i < data->ports; i++) {
+		if (data->vbus_pin[i])
+			at91_set_gpio_output(data->vbus_pin[i], 0);
+	}
+
+	usbh_data = *data;
+	platform_device_register(&at91_usbh_device);
+}
+#else
+void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+static u64 eth_dmamask = DMA_BIT_MASK(32);
+static struct at91_eth_data eth_data;
+
+static struct resource eth_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_EMAC,
+		.end	= AT91CAP9_BASE_EMAC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_EMAC,
+		.end	= AT91CAP9_ID_EMAC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_eth_device = {
+	.name		= "macb",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &eth_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &eth_data,
+	},
+	.resource	= eth_resources,
+	.num_resources	= ARRAY_SIZE(eth_resources),
+};
+
+void __init at91_add_device_eth(struct at91_eth_data *data)
+{
+	if (!data)
+		return;
+
+	if (data->phy_irq_pin) {
+		at91_set_gpio_input(data->phy_irq_pin, 0);
+		at91_set_deglitch(data->phy_irq_pin, 1);
+	}
+
+	/* Pins used for MII and RMII */
+	at91_set_A_periph(AT91_PIN_PB21, 0);	/* ETXCK_EREFCK */
+	at91_set_A_periph(AT91_PIN_PB22, 0);	/* ERXDV */
+	at91_set_A_periph(AT91_PIN_PB25, 0);	/* ERX0 */
+	at91_set_A_periph(AT91_PIN_PB26, 0);	/* ERX1 */
+	at91_set_A_periph(AT91_PIN_PB27, 0);	/* ERXER */
+	at91_set_A_periph(AT91_PIN_PB28, 0);	/* ETXEN */
+	at91_set_A_periph(AT91_PIN_PB23, 0);	/* ETX0 */
+	at91_set_A_periph(AT91_PIN_PB24, 0);	/* ETX1 */
+	at91_set_A_periph(AT91_PIN_PB30, 0);	/* EMDIO */
+	at91_set_A_periph(AT91_PIN_PB29, 0);	/* EMDC */
+
+	if (!data->is_rmii) {
+		at91_set_B_periph(AT91_PIN_PC25, 0);	/* ECRS */
+		at91_set_B_periph(AT91_PIN_PC26, 0);	/* ECOL */
+		at91_set_B_periph(AT91_PIN_PC22, 0);	/* ERX2 */
+		at91_set_B_periph(AT91_PIN_PC23, 0);	/* ERX3 */
+		at91_set_B_periph(AT91_PIN_PC27, 0);	/* ERXCK */
+		at91_set_B_periph(AT91_PIN_PC20, 0);	/* ETX2 */
+		at91_set_B_periph(AT91_PIN_PC21, 0);	/* ETX3 */
+		at91_set_B_periph(AT91_PIN_PC24, 0);	/* ETXER */
+	}
+
+	eth_data = *data;
+	platform_device_register(&at91cap9_eth_device);
+}
+#else
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct at91_mmc_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_MCI0,
+		.end	= AT91CAP9_BASE_MCI0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_MCI0,
+		.end	= AT91CAP9_ID_MCI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_mmc0_device = {
+	.name		= "at91_mci",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &mmc0_data,
+	},
+	.resource	= mmc0_resources,
+	.num_resources	= ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_MCI1,
+		.end	= AT91CAP9_BASE_MCI1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_MCI1,
+		.end	= AT91CAP9_ID_MCI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_mmc1_device = {
+	.name		= "at91_mci",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &mmc1_data,
+	},
+	.resource	= mmc1_resources,
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+};
+
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+{
+	if (!data)
+		return;
+
+	/* input/irq */
+	if (data->det_pin) {
+		at91_set_gpio_input(data->det_pin, 1);
+		at91_set_deglitch(data->det_pin, 1);
+	}
+	if (data->wp_pin)
+		at91_set_gpio_input(data->wp_pin, 1);
+	if (data->vcc_pin)
+		at91_set_gpio_output(data->vcc_pin, 0);
+
+	if (mmc_id == 0) {		/* MCI0 */
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA2, 0);
+
+		/* CMD */
+		at91_set_A_periph(AT91_PIN_PA1, 1);
+
+		/* DAT0, maybe DAT1..DAT3 */
+		at91_set_A_periph(AT91_PIN_PA0, 1);
+		if (data->wire4) {
+			at91_set_A_periph(AT91_PIN_PA3, 1);
+			at91_set_A_periph(AT91_PIN_PA4, 1);
+			at91_set_A_periph(AT91_PIN_PA5, 1);
+		}
+
+		mmc0_data = *data;
+		at91_clock_associate("mci0_clk", &at91cap9_mmc1_device.dev, "mci_clk");
+		platform_device_register(&at91cap9_mmc0_device);
+	} else {			/* MCI1 */
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA16, 0);
+
+		/* CMD */
+		at91_set_A_periph(AT91_PIN_PA17, 1);
+
+		/* DAT0, maybe DAT1..DAT3 */
+		at91_set_A_periph(AT91_PIN_PA18, 1);
+		if (data->wire4) {
+			at91_set_A_periph(AT91_PIN_PA19, 1);
+			at91_set_A_periph(AT91_PIN_PA20, 1);
+			at91_set_A_periph(AT91_PIN_PA21, 1);
+		}
+
+		mmc1_data = *data;
+		at91_clock_associate("mci1_clk", &at91cap9_mmc1_device.dev, "mci_clk");
+		platform_device_register(&at91cap9_mmc1_device);
+	}
+}
+#else
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+static struct at91_nand_data nand_data;
+
+#define NAND_BASE	AT91_CHIPSELECT_3
+
+static struct resource nand_resources[] = {
+	{
+		.start	= NAND_BASE,
+		.end	= NAND_BASE + SZ_256M - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device at91cap9_nand_device = {
+	.name		= "at91_nand",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= &nand_data,
+	},
+	.resource	= nand_resources,
+	.num_resources	= ARRAY_SIZE(nand_resources),
+};
+
+void __init at91_add_device_nand(struct at91_nand_data *data)
+{
+	unsigned long csa, mode;
+
+	if (!data)
+		return;
+
+	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
+
+	/* set the bus interface characteristics */
+	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(1)
+			| AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(1));
+
+	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(6)
+			| AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(6));
+
+	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(8) | AT91_SMC_NRDCYCLE_(8));
+
+	if (data->bus_width_16)
+		mode = AT91_SMC_DBW_16;
+	else
+		mode = AT91_SMC_DBW_8;
+	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(1));
+
+	/* enable pin */
+	if (data->enable_pin)
+		at91_set_gpio_output(data->enable_pin, 1);
+
+	/* ready/busy pin */
+	if (data->rdy_pin)
+		at91_set_gpio_input(data->rdy_pin, 1);
+
+	/* card detect pin */
+	if (data->det_pin)
+		at91_set_gpio_input(data->det_pin, 1);
+
+	nand_data = *data;
+	platform_device_register(&at91cap9_nand_device);
+}
+#else
+void __init at91_add_device_nand(struct at91_nand_data *data) {}
+#endif
+
+/* --------------------------------------------------------------------
+ *  TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+/*
+ * Prefer the GPIO code since the TWI controller isn't robust
+ * (gets overruns and underruns under load) and can only issue
+ * repeated STARTs in one scenario (the driver doesn't yet handle them).
+ */
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+
+static struct i2c_gpio_platform_data pdata = {
+	.sda_pin		= AT91_PIN_PB4,
+	.sda_is_open_drain	= 1,
+	.scl_pin		= AT91_PIN_PB5,
+	.scl_is_open_drain	= 1,
+	.udelay			= 2,		/* ~100 kHz */
+};
+
+static struct platform_device at91cap9_twi_device = {
+	.name			= "i2c-gpio",
+	.id			= -1,
+	.dev.platform_data	= &pdata,
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+	at91_set_GPIO_periph(AT91_PIN_PB4, 1);		/* TWD (SDA) */
+	at91_set_multi_drive(AT91_PIN_PB4, 1);
+
+	at91_set_GPIO_periph(AT91_PIN_PB5, 1);		/* TWCK (SCL) */
+	at91_set_multi_drive(AT91_PIN_PB5, 1);
+
+	i2c_register_board_info(0, devices, nr_devices);
+	platform_device_register(&at91cap9_twi_device);
+}
+
+#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+
+static struct resource twi_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_TWI,
+		.end	= AT91CAP9_BASE_TWI + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_TWI,
+		.end	= AT91CAP9_ID_TWI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_twi_device = {
+	.name		= "at91_i2c",
+	.id		= -1,
+	.resource	= twi_resources,
+	.num_resources	= ARRAY_SIZE(twi_resources),
+};
+
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+{
+	/* pins used for TWI interface */
+	at91_set_B_periph(AT91_PIN_PB4, 0);		/* TWD */
+	at91_set_multi_drive(AT91_PIN_PB4, 1);
+
+	at91_set_B_periph(AT91_PIN_PB5, 0);		/* TWCK */
+	at91_set_multi_drive(AT91_PIN_PB5, 1);
+
+	i2c_register_board_info(0, devices, nr_devices);
+	platform_device_register(&at91cap9_twi_device);
+}
+#else
+void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
+#endif
+
+/* --------------------------------------------------------------------
+ *  SPI
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+static struct resource spi0_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_SPI0,
+		.end	= AT91CAP9_BASE_SPI0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_SPI0,
+		.end	= AT91CAP9_ID_SPI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_spi0_device = {
+	.name		= "atmel_spi",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &spi_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= spi0_resources,
+	.num_resources	= ARRAY_SIZE(spi0_resources),
+};
+
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PD0, AT91_PIN_PD1 };
+
+static struct resource spi1_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_SPI1,
+		.end	= AT91CAP9_BASE_SPI1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_SPI1,
+		.end	= AT91CAP9_ID_SPI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_spi1_device = {
+	.name		= "atmel_spi",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &spi_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= spi1_resources,
+	.num_resources	= ARRAY_SIZE(spi1_resources),
+};
+
+static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
+
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+{
+	int i;
+	unsigned long cs_pin;
+	short enable_spi0 = 0;
+	short enable_spi1 = 0;
+
+	/* Choose SPI chip-selects */
+	for (i = 0; i < nr_devices; i++) {
+		if (devices[i].controller_data)
+			cs_pin = (unsigned long) devices[i].controller_data;
+		else if (devices[i].bus_num == 0)
+			cs_pin = spi0_standard_cs[devices[i].chip_select];
+		else
+			cs_pin = spi1_standard_cs[devices[i].chip_select];
+
+		if (devices[i].bus_num == 0)
+			enable_spi0 = 1;
+		else
+			enable_spi1 = 1;
+
+		/* enable chip-select pin */
+		at91_set_gpio_output(cs_pin, 1);
+
+		/* pass chip-select pin to driver */
+		devices[i].controller_data = (void *) cs_pin;
+	}
+
+	spi_register_board_info(devices, nr_devices);
+
+	/* Configure SPI bus(es) */
+	if (enable_spi0) {
+		at91_set_B_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
+		at91_set_B_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
+		at91_set_B_periph(AT91_PIN_PA2, 0);	/* SPI0_SPCK */
+
+		at91_clock_associate("spi0_clk", &at91cap9_spi0_device.dev, "spi_clk");
+		platform_device_register(&at91cap9_spi0_device);
+	}
+	if (enable_spi1) {
+		at91_set_A_periph(AT91_PIN_PB12, 0);	/* SPI1_MISO */
+		at91_set_A_periph(AT91_PIN_PB13, 0);	/* SPI1_MOSI */
+		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_SPCK */
+
+		at91_clock_associate("spi1_clk", &at91cap9_spi1_device.dev, "spi_clk");
+		platform_device_register(&at91cap9_spi1_device);
+	}
+}
+#else
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  RTT
+ * -------------------------------------------------------------------- */
+
+static struct platform_device at91cap9_rtt_device = {
+	.name		= "at91_rtt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_rtt(void)
+{
+	platform_device_register(&at91cap9_rtt_device);
+}
+
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91cap9_wdt_device = {
+	.name		= "at91_wdt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+	platform_device_register(&at91cap9_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  AC97
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
+static u64 ac97_dmamask = DMA_BIT_MASK(32);
+static struct atmel_ac97_data ac97_data;
+
+static struct resource ac97_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_AC97C,
+		.end	= AT91CAP9_BASE_AC97C + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_AC97C,
+		.end	= AT91CAP9_ID_AC97C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_ac97_device = {
+	.name		= "ac97c",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &ac97_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &ac97_data,
+	},
+	.resource	= ac97_resources,
+	.num_resources	= ARRAY_SIZE(ac97_resources),
+};
+
+void __init at91_add_device_ac97(struct atmel_ac97_data *data)
+{
+	if (!data)
+		return;
+
+	at91_set_A_periph(AT91_PIN_PA6, 0);	/* AC97FS */
+	at91_set_A_periph(AT91_PIN_PA7, 0);	/* AC97CK */
+	at91_set_A_periph(AT91_PIN_PA8, 0);	/* AC97TX */
+	at91_set_A_periph(AT91_PIN_PA9, 0);	/* AC97RX */
+
+	/* reset */
+	if (data->reset_pin)
+		at91_set_gpio_output(data->reset_pin, 0);
+
+	ac97_data = *data;
+	platform_device_register(&at91cap9_ac97_device);
+}
+#else
+void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_LCDC_BASE,
+		.end	= AT91CAP9_LCDC_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_LCDC,
+		.end	= AT91CAP9_ID_LCDC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_lcdc_device = {
+	.name		= "atmel_lcdfb",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &lcdc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &lcdc_data,
+	},
+	.resource	= lcdc_resources,
+	.num_resources	= ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	if (!data)
+		return;
+
+	at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
+	at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
+	at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
+	at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
+	at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
+	at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
+	at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
+	at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
+	at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
+	at91_set_A_periph(AT91_PIN_PC17, 0);	/* LCDD13 */
+	at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
+	at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
+	at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
+	at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
+	at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
+	at91_set_A_periph(AT91_PIN_PC25, 0);	/* LCDD21 */
+	at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
+	at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
+
+	lcdc_data = *data;
+	platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_SSC0,
+		.end	= AT91CAP9_BASE_SSC0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_SSC0,
+		.end	= AT91CAP9_ID_SSC0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_ssc0_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc0_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc0_resources,
+	.num_resources	= ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB0, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB1, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB2, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB3, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB4, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB5, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_SSC1,
+		.end	= AT91CAP9_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_SSC1,
+		.end	= AT91CAP9_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91cap9_ssc1_device = {
+	.name	= "ssc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ssc1_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc1_resources,
+	.num_resources	= ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB6, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB7, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB8, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB9, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB10, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB11, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91CAP9_ID_SSC0:
+		pdev = &at91cap9_ssc0_device;
+		configure_ssc0_pins(pins);
+		at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
+		break;
+	case AT91CAP9_ID_SSC1:
+		pdev = &at91cap9_ssc1_device;
+		configure_ssc1_pins(pins);
+		at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  UART
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SERIAL_ATMEL)
+static struct resource dbgu_resources[] = {
+	[0] = {
+		.start	= AT91_VA_BASE_SYS + AT91_DBGU,
+		.end	= AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91_ID_SYS,
+		.end	= AT91_ID_SYS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data dbgu_data = {
+	.use_dma_tx	= 0,
+	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
+	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+};
+
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91cap9_dbgu_device = {
+	.name		= "atmel_usart",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
+	},
+	.resource	= dbgu_resources,
+	.num_resources	= ARRAY_SIZE(dbgu_resources),
+};
+
+static inline void configure_dbgu_pins(void)
+{
+	at91_set_A_periph(AT91_PIN_PC30, 0);		/* DRXD */
+	at91_set_A_periph(AT91_PIN_PC31, 1);		/* DTXD */
+}
+
+static struct resource uart0_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_US0,
+		.end	= AT91CAP9_BASE_US0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_US0,
+		.end	= AT91CAP9_ID_US0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart0_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91cap9_uart0_device = {
+	.name		= "atmel_usart",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
+	},
+	.resource	= uart0_resources,
+	.num_resources	= ARRAY_SIZE(uart0_resources),
+};
+
+static inline void configure_usart0_pins(unsigned pins)
+{
+	at91_set_A_periph(AT91_PIN_PA22, 1);		/* TXD0 */
+	at91_set_A_periph(AT91_PIN_PA23, 0);		/* RXD0 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PA24, 0);	/* RTS0 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA25, 0);	/* CTS0 */
+}
+
+static struct resource uart1_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_US1,
+		.end	= AT91CAP9_BASE_US1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_US1,
+		.end	= AT91CAP9_ID_US1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart1_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91cap9_uart1_device = {
+	.name		= "atmel_usart",
+	.id		= 2,
+	.dev		= {
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
+	},
+	.resource	= uart1_resources,
+	.num_resources	= ARRAY_SIZE(uart1_resources),
+};
+
+static inline void configure_usart1_pins(unsigned pins)
+{
+	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
+	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PD7, 0);	/* RTS1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PD8, 0);	/* CTS1 */
+}
+
+static struct resource uart2_resources[] = {
+	[0] = {
+		.start	= AT91CAP9_BASE_US2,
+		.end	= AT91CAP9_BASE_US2 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91CAP9_ID_US2,
+		.end	= AT91CAP9_ID_US2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart2_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
+static struct platform_device at91cap9_uart2_device = {
+	.name		= "atmel_usart",
+	.id		= 3,
+	.dev		= {
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
+	},
+	.resource	= uart2_resources,
+	.num_resources	= ARRAY_SIZE(uart2_resources),
+};
+
+static inline void configure_usart2_pins(unsigned pins)
+{
+	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
+	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PD5, 0);	/* RTS2 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PD6, 0);	/* CTS2 */
+}
+
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+struct platform_device *atmel_default_console_device;	/* the serial console device */
+
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91cap9_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91CAP9_ID_US0:
+			pdev = &at91cap9_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91CAP9_ID_US1:
+			pdev = &at91cap9_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91CAP9_ID_US2:
+			pdev = &at91cap9_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
+void __init at91_add_device_serial(void)
+{
+	int i;
+
+	for (i = 0; i < ATMEL_MAX_UART; i++) {
+		if (at91_uarts[i])
+			platform_device_register(at91_uarts[i]);
+	}
+}
+#else
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
+void __init at91_add_device_serial(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init at91_add_standard_devices(void)
+{
+	at91_add_device_rtt();
+	at91_add_device_watchdog();
+	return 0;
+}
+
+arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 2cad2bf..d688c1d 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -301,28 +301,28 @@
 static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
 	7,	/* Advanced Interrupt Controller (FIQ) */
 	7,	/* System Peripherals */
-	0,	/* Parallel IO Controller A */
-	0,	/* Parallel IO Controller B */
-	0,	/* Parallel IO Controller C */
-	0,	/* Parallel IO Controller D */
-	6,	/* USART 0 */
-	6,	/* USART 1 */
-	6,	/* USART 2 */
-	6,	/* USART 3 */
+	1,	/* Parallel IO Controller A */
+	1,	/* Parallel IO Controller B */
+	1,	/* Parallel IO Controller C */
+	1,	/* Parallel IO Controller D */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
+	5,	/* USART 3 */
 	0,	/* Multimedia Card Interface */
-	4,	/* USB Device Port */
-	0,	/* Two-Wire Interface */
-	6,	/* Serial Peripheral Interface */
-	5,	/* Serial Synchronous Controller 0 */
-	5,	/* Serial Synchronous Controller 1 */
-	5,	/* Serial Synchronous Controller 2 */
+	2,	/* USB Device Port */
+	6,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface */
+	4,	/* Serial Synchronous Controller 0 */
+	4,	/* Serial Synchronous Controller 1 */
+	4,	/* Serial Synchronous Controller 2 */
 	0,	/* Timer Counter 0 */
 	0,	/* Timer Counter 1 */
 	0,	/* Timer Counter 2 */
 	0,	/* Timer Counter 3 */
 	0,	/* Timer Counter 4 */
 	0,	/* Timer Counter 5 */
-	3,	/* USB Host port */
+	2,	/* USB Host port */
 	3,	/* Ethernet MAC */
 	0,	/* Advanced Interrupt Controller (IRQ0) */
 	0,	/* Advanced Interrupt Controller (IRQ1) */
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 9296833..ef6aeb8 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -13,6 +13,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -29,7 +30,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = 0xffffffffUL;
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
 static struct at91_usbh_data usbh_data;
 
 static struct resource usbh_resources[] = {
@@ -50,7 +51,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &ohci_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &usbh_data,
 	},
 	.resource	= usbh_resources,
@@ -125,7 +126,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_ARM_AT91_ETHER) || defined(CONFIG_ARM_AT91_ETHER_MODULE)
-static u64 eth_dmamask = 0xffffffffUL;
+static u64 eth_dmamask = DMA_BIT_MASK(32);
 static struct at91_eth_data eth_data;
 
 static struct resource eth_resources[] = {
@@ -146,7 +147,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &eth_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &eth_data,
 	},
 	.resource	= eth_resources,
@@ -285,7 +286,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = 0xffffffffUL;
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct at91_mmc_data mmc_data;
 
 static struct resource mmc_resources[] = {
@@ -306,7 +307,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc_data,
 	},
 	.resource	= mmc_resources,
@@ -375,7 +376,7 @@
 static struct resource nand_resources[] = {
 	{
 		.start	= NAND_BASE,
-		.end	= NAND_BASE + SZ_8M - 1,
+		.end	= NAND_BASE + SZ_256M - 1,
 		.flags	= IORESOURCE_MEM,
 	}
 };
@@ -513,7 +514,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = 0xffffffffUL;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
 
 static struct resource spi_resources[] = {
 	[0] = {
@@ -533,7 +534,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi_resources,
 	.num_resources	= ARRAY_SIZE(spi_resources),
@@ -557,8 +558,11 @@
 		else
 			cs_pin = spi_standard_cs[devices[i].chip_select];
 
-		/* enable chip-select pin */
-		at91_set_gpio_output(cs_pin, 1);
+		if (devices[i].chip_select == 0)	/* for CS0 errata */
+			at91_set_A_periph(cs_pin, 0);
+		else
+			at91_set_gpio_output(cs_pin, 1);
+
 
 		/* pass chip-select pin to driver */
 		devices[i].controller_data = (void *) cs_pin;
@@ -613,24 +617,175 @@
 
 
 /* --------------------------------------------------------------------
- *  LEDs
+ *  SSC -- Synchronous Serial Controller
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_LEDS)
-u8 at91_leds_cpu;
-u8 at91_leds_timer;
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
 
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+static struct resource ssc0_resources[] = {
+	[0] = {
+		.start	= AT91RM9200_BASE_SSC0,
+		.end	= AT91RM9200_BASE_SSC0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91RM9200_ID_SSC0,
+		.end	= AT91RM9200_ID_SSC0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91rm9200_ssc0_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc0_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc0_resources,
+	.num_resources	= ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
 {
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
-
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB0, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB1, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB2, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB3, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB4, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB5, 1);
 }
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+	[0] = {
+		.start	= AT91RM9200_BASE_SSC1,
+		.end	= AT91RM9200_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91RM9200_ID_SSC1,
+		.end	= AT91RM9200_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91rm9200_ssc1_device = {
+	.name	= "ssc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ssc1_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc1_resources,
+	.num_resources	= ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB6, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB7, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB8, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB9, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB10, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB11, 1);
+}
+
+static u64 ssc2_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc2_resources[] = {
+	[0] = {
+		.start	= AT91RM9200_BASE_SSC2,
+		.end	= AT91RM9200_BASE_SSC2 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91RM9200_ID_SSC2,
+		.end	= AT91RM9200_ID_SSC2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91rm9200_ssc2_device = {
+	.name	= "ssc",
+	.id	= 2,
+	.dev	= {
+		.dma_mask		= &ssc2_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc2_resources,
+	.num_resources	= ARRAY_SIZE(ssc2_resources),
+};
+
+static inline void configure_ssc2_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB12, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB13, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB14, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB15, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB16, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB17, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91RM9200_ID_SSC0:
+		pdev = &at91rm9200_ssc0_device;
+		configure_ssc0_pins(pins);
+		at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
+		break;
+	case AT91RM9200_ID_SSC1:
+		pdev = &at91rm9200_ssc1_device;
+		configure_ssc1_pins(pins);
+		at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
+		break;
+	case AT91RM9200_ID_SSC2:
+		pdev = &at91rm9200_ssc2_device;
+		configure_ssc2_pins(pins);
+		at91_clock_associate("ssc2_clk", &pdev->dev, "ssc");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
 #else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #endif
 
 
@@ -658,12 +813,15 @@
 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91rm9200_dbgu_device = {
 	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
-				.platform_data	= &dbgu_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
 	},
 	.resource	= dbgu_resources,
 	.num_resources	= ARRAY_SIZE(dbgu_resources),
@@ -693,28 +851,35 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91rm9200_uart0_device = {
 	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
-				.platform_data	= &uart0_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
 	},
 	.resource	= uart0_resources,
 	.num_resources	= ARRAY_SIZE(uart0_resources),
 };
 
-static inline void configure_usart0_pins(void)
+static inline void configure_usart0_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA17, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PA18, 0);		/* RXD0 */
-	at91_set_A_periph(AT91_PIN_PA20, 0);		/* CTS0 */
 
-	/*
-	 * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21.
-	 *  We need to drive the pin manually.  Default is off (RTS is active low).
-	 */
-	at91_set_gpio_output(AT91_PIN_PA21, 1);
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA20, 0);	/* CTS0 */
+
+	if (pins & ATMEL_UART_RTS) {
+		/*
+		 * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21.
+		 *  We need to drive the pin manually.  Default is off (RTS is active low).
+		 */
+		at91_set_gpio_output(AT91_PIN_PA21, 1);
+	}
 }
 
 static struct resource uart1_resources[] = {
@@ -735,27 +900,37 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91rm9200_uart1_device = {
 	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
-				.platform_data	= &uart1_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
 	},
 	.resource	= uart1_resources,
 	.num_resources	= ARRAY_SIZE(uart1_resources),
 };
 
-static inline void configure_usart1_pins(void)
+static inline void configure_usart1_pins(unsigned pins)
 {
-	at91_set_A_periph(AT91_PIN_PB18, 0);		/* RI1 */
-	at91_set_A_periph(AT91_PIN_PB19, 0);		/* DTR1 */
 	at91_set_A_periph(AT91_PIN_PB20, 1);		/* TXD1 */
 	at91_set_A_periph(AT91_PIN_PB21, 0);		/* RXD1 */
-	at91_set_A_periph(AT91_PIN_PB23, 0);		/* DCD1 */
-	at91_set_A_periph(AT91_PIN_PB24, 0);		/* CTS1 */
-	at91_set_A_periph(AT91_PIN_PB25, 0);		/* DSR1 */
-	at91_set_A_periph(AT91_PIN_PB26, 0);		/* RTS1 */
+
+	if (pins & ATMEL_UART_RI)
+		at91_set_A_periph(AT91_PIN_PB18, 0);	/* RI1 */
+	if (pins & ATMEL_UART_DTR)
+		at91_set_A_periph(AT91_PIN_PB19, 0);	/* DTR1 */
+	if (pins & ATMEL_UART_DCD)
+		at91_set_A_periph(AT91_PIN_PB23, 0);	/* DCD1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PB24, 0);	/* CTS1 */
+	if (pins & ATMEL_UART_DSR)
+		at91_set_A_periph(AT91_PIN_PB25, 0);	/* DSR1 */
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PB26, 0);	/* RTS1 */
 }
 
 static struct resource uart2_resources[] = {
@@ -776,21 +951,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91rm9200_uart2_device = {
 	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
-				.platform_data	= &uart2_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
 	},
 	.resource	= uart2_resources,
 	.num_resources	= ARRAY_SIZE(uart2_resources),
 };
 
-static inline void configure_usart2_pins(void)
+static inline void configure_usart2_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA22, 0);		/* RXD2 */
 	at91_set_A_periph(AT91_PIN_PA23, 1);		/* TXD2 */
+
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PA30, 0);	/* CTS2 */
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PA31, 0);	/* RTS2 */
 }
 
 static struct resource uart3_resources[] = {
@@ -811,27 +994,35 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart3_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91rm9200_uart3_device = {
 	.name		= "atmel_usart",
 	.id		= 4,
 	.dev		= {
-				.platform_data	= &uart3_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart3_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart3_data,
 	},
 	.resource	= uart3_resources,
 	.num_resources	= ARRAY_SIZE(uart3_resources),
 };
 
-static inline void configure_usart3_pins(void)
+static inline void configure_usart3_pins(unsigned pins)
 {
 	at91_set_B_periph(AT91_PIN_PA5, 1);		/* TXD3 */
 	at91_set_B_periph(AT91_PIN_PA6, 0);		/* RXD3 */
+
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PB1, 0);	/* CTS3 */
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PB0, 0);	/* RTS3 */
 }
 
-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init at91_init_serial(struct at91_uart_config *config)
+void __init __deprecated at91_init_serial(struct at91_uart_config *config)
 {
 	int i;
 
@@ -839,22 +1030,22 @@
 	for (i = 0; i < config->nr_tty; i++) {
 		switch (config->tty_map[i]) {
 			case 0:
-				configure_usart0_pins();
+				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91rm9200_uart0_device;
 				at91_clock_associate("usart0_clk", &at91rm9200_uart0_device.dev, "usart");
 				break;
 			case 1:
-				configure_usart1_pins();
+				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
 				at91_uarts[i] = &at91rm9200_uart1_device;
 				at91_clock_associate("usart1_clk", &at91rm9200_uart1_device.dev, "usart");
 				break;
 			case 2:
-				configure_usart2_pins();
+				configure_usart2_pins(0);
 				at91_uarts[i] = &at91rm9200_uart2_device;
 				at91_clock_associate("usart2_clk", &at91rm9200_uart2_device.dev, "usart");
 				break;
 			case 3:
-				configure_usart3_pins();
+				configure_usart3_pins(0);
 				at91_uarts[i] = &at91rm9200_uart3_device;
 				at91_clock_associate("usart3_clk", &at91rm9200_uart3_device.dev, "usart");
 				break;
@@ -876,6 +1067,53 @@
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91rm9200_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91RM9200_ID_US0:
+			pdev = &at91rm9200_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91RM9200_ID_US1:
+			pdev = &at91rm9200_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91RM9200_ID_US2:
+			pdev = &at91rm9200_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		case AT91RM9200_ID_US3:
+			pdev = &at91rm9200_uart3_device;
+			configure_usart3_pins(pins);
+			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -886,7 +1124,9 @@
 	}
 }
 #else
-void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index e47381e..18d0661 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -327,30 +327,30 @@
 static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
 	7,	/* Advanced Interrupt Controller */
 	7,	/* System Peripherals */
-	0,	/* Parallel IO Controller A */
-	0,	/* Parallel IO Controller B */
-	0,	/* Parallel IO Controller C */
+	1,	/* Parallel IO Controller A */
+	1,	/* Parallel IO Controller B */
+	1,	/* Parallel IO Controller C */
 	0,	/* Analog-to-Digital Converter */
-	6,	/* USART 0 */
-	6,	/* USART 1 */
-	6,	/* USART 2 */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
 	0,	/* Multimedia Card Interface */
-	4,	/* USB Device Port */
-	0,	/* Two-Wire Interface */
-	6,	/* Serial Peripheral Interface 0 */
-	6,	/* Serial Peripheral Interface 1 */
+	2,	/* USB Device Port */
+	6,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface 0 */
+	5,	/* Serial Peripheral Interface 1 */
 	5,	/* Serial Synchronous Controller */
 	0,
 	0,
 	0,	/* Timer Counter 0 */
 	0,	/* Timer Counter 1 */
 	0,	/* Timer Counter 2 */
-	3,	/* USB Host port */
+	2,	/* USB Host port */
 	3,	/* Ethernet */
 	0,	/* Image Sensor Interface */
-	6,	/* USART 3 */
-	6,	/* USART 4 */
-	6,	/* USART 5 */
+	5,	/* USART 3 */
+	5,	/* USART 4 */
+	5,	/* USART 5 */
 	0,	/* Timer Counter 3 */
 	0,	/* Timer Counter 4 */
 	0,	/* Timer Counter 5 */
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 3091bf4..105f840 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -12,6 +12,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -29,7 +30,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = 0xffffffffUL;
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
 static struct at91_usbh_data usbh_data;
 
 static struct resource usbh_resources[] = {
@@ -50,7 +51,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &ohci_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &usbh_data,
 	},
 	.resource	= usbh_resources,
@@ -125,7 +126,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = 0xffffffffUL;
+static u64 eth_dmamask = DMA_BIT_MASK(32);
 static struct at91_eth_data eth_data;
 
 static struct resource eth_resources[] = {
@@ -146,7 +147,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &eth_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &eth_data,
 	},
 	.resource	= eth_resources,
@@ -199,7 +200,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = 0xffffffffUL;
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct at91_mmc_data mmc_data;
 
 static struct resource mmc_resources[] = {
@@ -220,7 +221,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc_data,
 	},
 	.resource	= mmc_resources,
@@ -289,7 +290,7 @@
 static struct resource nand_resources[] = {
 	{
 		.start	= NAND_BASE,
-		.end	= NAND_BASE + SZ_8M - 1,
+		.end	= NAND_BASE + SZ_256M - 1,
 		.flags	= IORESOURCE_MEM,
 	}
 };
@@ -312,7 +313,7 @@
 		return;
 
 	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC);
+	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
 	/* set the bus interface characteristics */
 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
@@ -431,7 +432,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = 0xffffffffUL;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
 
 static struct resource spi0_resources[] = {
 	[0] = {
@@ -451,7 +452,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi0_resources,
 	.num_resources	= ARRAY_SIZE(spi0_resources),
@@ -477,7 +478,7 @@
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi1_resources,
 	.num_resources	= ARRAY_SIZE(spi1_resources),
@@ -539,24 +540,126 @@
 
 
 /* --------------------------------------------------------------------
- *  LEDs
+ *  RTT
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_LEDS)
-u8 at91_leds_cpu;
-u8 at91_leds_timer;
+static struct resource rtt_resources[] = {
+	{
+		.start	= AT91_BASE_SYS + AT91_RTT,
+		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
 
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+static struct platform_device at91sam9260_rtt_device = {
+	.name		= "at91_rtt",
+	.id		= -1,
+	.resource	= rtt_resources,
+	.num_resources	= ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
 {
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
+	platform_device_register(&at91sam9260_rtt_device);
+}
 
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9260_wdt_device = {
+	.name		= "at91_wdt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+	platform_device_register(&at91sam9260_wdt_device);
 }
 #else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_SSC,
+		.end	= AT91SAM9260_BASE_SSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_SSC,
+		.end	= AT91SAM9260_ID_SSC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9260_ssc_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc_resources,
+	.num_resources	= ARRAY_SIZE(ssc_resources),
+};
+
+static inline void configure_ssc_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB17, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB16, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB18, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB19, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB20, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB21, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91SAM9260_ID_SSC:
+		pdev = &at91sam9260_ssc_device;
+		configure_ssc_pins(pins);
+		at91_clock_associate("ssc_clk", &pdev->dev, "pclk");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #endif
 
 
@@ -583,12 +686,15 @@
 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_dbgu_device = {
 	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
-				.platform_data	= &dbgu_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
 	},
 	.resource	= dbgu_resources,
 	.num_resources	= ARRAY_SIZE(dbgu_resources),
@@ -618,27 +724,37 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart0_device = {
 	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
-				.platform_data	= &uart0_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
 	},
 	.resource	= uart0_resources,
 	.num_resources	= ARRAY_SIZE(uart0_resources),
 };
 
-static inline void configure_usart0_pins(void)
+static inline void configure_usart0_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PB4, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PB5, 0);		/* RXD0 */
-	at91_set_A_periph(AT91_PIN_PB26, 0);		/* RTS0 */
-	at91_set_A_periph(AT91_PIN_PB27, 0);		/* CTS0 */
-	at91_set_A_periph(AT91_PIN_PB24, 0);		/* DTR0 */
-	at91_set_A_periph(AT91_PIN_PB22, 0);		/* DSR0 */
-	at91_set_A_periph(AT91_PIN_PB23, 0);		/* DCD0 */
-	at91_set_A_periph(AT91_PIN_PB25, 0);		/* RI0 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PB26, 0);	/* RTS0 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PB27, 0);	/* CTS0 */
+	if (pins & ATMEL_UART_DTR)
+		at91_set_A_periph(AT91_PIN_PB24, 0);	/* DTR0 */
+	if (pins & ATMEL_UART_DSR)
+		at91_set_A_periph(AT91_PIN_PB22, 0);	/* DSR0 */
+	if (pins & ATMEL_UART_DCD)
+		at91_set_A_periph(AT91_PIN_PB23, 0);	/* DCD0 */
+	if (pins & ATMEL_UART_RI)
+		at91_set_A_periph(AT91_PIN_PB25, 0);	/* RI0 */
 }
 
 static struct resource uart1_resources[] = {
@@ -659,23 +775,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart1_device = {
 	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
-				.platform_data	= &uart1_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
 	},
 	.resource	= uart1_resources,
 	.num_resources	= ARRAY_SIZE(uart1_resources),
 };
 
-static inline void configure_usart1_pins(void)
+static inline void configure_usart1_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PB6, 1);		/* TXD1 */
 	at91_set_A_periph(AT91_PIN_PB7, 0);		/* RXD1 */
-	at91_set_A_periph(AT91_PIN_PB28, 0);		/* RTS1 */
-	at91_set_A_periph(AT91_PIN_PB29, 0);		/* CTS1 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PB28, 0);	/* RTS1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PB29, 0);	/* CTS1 */
 }
 
 static struct resource uart2_resources[] = {
@@ -696,21 +818,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart2_device = {
 	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
-				.platform_data	= &uart2_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
 	},
 	.resource	= uart2_resources,
 	.num_resources	= ARRAY_SIZE(uart2_resources),
 };
 
-static inline void configure_usart2_pins(void)
+static inline void configure_usart2_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PB8, 1);		/* TXD2 */
 	at91_set_A_periph(AT91_PIN_PB9, 0);		/* RXD2 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PA4, 0);	/* RTS2 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA5, 0);	/* CTS2 */
 }
 
 static struct resource uart3_resources[] = {
@@ -731,21 +861,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart3_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart3_device = {
 	.name		= "atmel_usart",
 	.id		= 4,
 	.dev		= {
-				.platform_data	= &uart3_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart3_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart3_data,
 	},
 	.resource	= uart3_resources,
 	.num_resources	= ARRAY_SIZE(uart3_resources),
 };
 
-static inline void configure_usart3_pins(void)
+static inline void configure_usart3_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PB10, 1);		/* TXD3 */
 	at91_set_A_periph(AT91_PIN_PB11, 0);		/* RXD3 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PC8, 0);	/* RTS3 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PC10, 0);	/* CTS3 */
 }
 
 static struct resource uart4_resources[] = {
@@ -766,12 +904,15 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart4_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart4_device = {
 	.name		= "atmel_usart",
 	.id		= 5,
 	.dev		= {
-				.platform_data	= &uart4_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart4_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart4_data,
 	},
 	.resource	= uart4_resources,
 	.num_resources	= ARRAY_SIZE(uart4_resources),
@@ -801,12 +942,15 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart5_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9260_uart5_device = {
 	.name		= "atmel_usart",
 	.id		= 6,
 	.dev		= {
-				.platform_data	= &uart5_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart5_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart5_data,
 	},
 	.resource	= uart5_resources,
 	.num_resources	= ARRAY_SIZE(uart5_resources),
@@ -818,10 +962,10 @@
 	at91_set_A_periph(AT91_PIN_PB13, 0);		/* RXD5 */
 }
 
-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init at91_init_serial(struct at91_uart_config *config)
+void __init __deprecated at91_init_serial(struct at91_uart_config *config)
 {
 	int i;
 
@@ -829,22 +973,22 @@
 	for (i = 0; i < config->nr_tty; i++) {
 		switch (config->tty_map[i]) {
 			case 0:
-				configure_usart0_pins();
+				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
 				at91_uarts[i] = &at91sam9260_uart0_device;
 				at91_clock_associate("usart0_clk", &at91sam9260_uart0_device.dev, "usart");
 				break;
 			case 1:
-				configure_usart1_pins();
+				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9260_uart1_device;
 				at91_clock_associate("usart1_clk", &at91sam9260_uart1_device.dev, "usart");
 				break;
 			case 2:
-				configure_usart2_pins();
+				configure_usart2_pins(0);
 				at91_uarts[i] = &at91sam9260_uart2_device;
 				at91_clock_associate("usart2_clk", &at91sam9260_uart2_device.dev, "usart");
 				break;
 			case 3:
-				configure_usart3_pins();
+				configure_usart3_pins(0);
 				at91_uarts[i] = &at91sam9260_uart3_device;
 				at91_clock_associate("usart3_clk", &at91sam9260_uart3_device.dev, "usart");
 				break;
@@ -876,6 +1020,63 @@
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91sam9260_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US0:
+			pdev = &at91sam9260_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US1:
+			pdev = &at91sam9260_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US2:
+			pdev = &at91sam9260_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US3:
+			pdev = &at91sam9260_uart3_device;
+			configure_usart3_pins(pins);
+			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US4:
+			pdev = &at91sam9260_uart4_device;
+			configure_usart4_pins();
+			at91_clock_associate("usart4_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9260_ID_US5:
+			pdev = &at91sam9260_uart5_device;
+			configure_usart5_pins();
+			at91_clock_associate("usart5_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -886,7 +1087,9 @@
 	}
 }
 #else
-void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -898,6 +1101,8 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	at91_add_device_rtt();
+	at91_add_device_watchdog();
 	return 0;
 }
 
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index dfe8c39..90b87e1 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -279,25 +279,25 @@
 static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
 	7,	/* Advanced Interrupt Controller */
 	7,	/* System Peripherals */
-	0,	/* Parallel IO Controller A */
-	0,	/* Parallel IO Controller B */
-	0,	/* Parallel IO Controller C */
+	1,	/* Parallel IO Controller A */
+	1,	/* Parallel IO Controller B */
+	1,	/* Parallel IO Controller C */
 	0,
-	6,	/* USART 0 */
-	6,	/* USART 1 */
-	6,	/* USART 2 */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
 	0,	/* Multimedia Card Interface */
-	4,	/* USB Device Port */
-	0,	/* Two-Wire Interface */
-	6,	/* Serial Peripheral Interface 0 */
-	6,	/* Serial Peripheral Interface 1 */
-	5,	/* Serial Synchronous Controller 0 */
-	5,	/* Serial Synchronous Controller 1 */
-	5,	/* Serial Synchronous Controller 2 */
+	2,	/* USB Device Port */
+	6,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface 0 */
+	5,	/* Serial Peripheral Interface 1 */
+	4,	/* Serial Synchronous Controller 0 */
+	4,	/* Serial Synchronous Controller 1 */
+	4,	/* Serial Synchronous Controller 2 */
 	0,	/* Timer Counter 0 */
 	0,	/* Timer Counter 1 */
 	0,	/* Timer Counter 2 */
-	3,	/* USB Host port */
+	2,	/* USB Host port */
 	3,	/* LCD Controller */
 	0,
 	0,
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 64979a9..2456412 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -13,6 +13,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -33,7 +34,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = 0xffffffffUL;
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
 static struct at91_usbh_data usbh_data;
 
 static struct resource usbh_resources[] = {
@@ -54,7 +55,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &ohci_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &usbh_data,
 	},
 	.resource	= usbh_resources,
@@ -106,8 +107,6 @@
 
 void __init at91_add_device_udc(struct at91_udc_data *data)
 {
-	unsigned long x;
-
 	if (!data)
 		return;
 
@@ -116,9 +115,7 @@
 		at91_set_deglitch(data->vbus_pin, 1);
 	}
 
-	/* Pullup pin is handled internally */
-	x = at91_sys_read(AT91_MATRIX_USBPUCR);
-	at91_sys_write(AT91_MATRIX_USBPUCR, x | AT91_MATRIX_USBPUCR_PUON);
+	/* Pullup pin is handled internally by USB device peripheral */
 
 	udc_data = *data;
 	platform_device_register(&at91sam9261_udc_device);
@@ -132,7 +129,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = 0xffffffffUL;
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct at91_mmc_data mmc_data;
 
 static struct resource mmc_resources[] = {
@@ -153,7 +150,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc_data,
 	},
 	.resource	= mmc_resources,
@@ -232,7 +229,7 @@
 		return;
 
 	csa = at91_sys_read(AT91_MATRIX_EBICSA);
-	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC);
+	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
 	/* set the bus interface characteristics */
 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
@@ -354,7 +351,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = 0xffffffffUL;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
 
 static struct resource spi0_resources[] = {
 	[0] = {
@@ -374,7 +371,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi0_resources,
 	.num_resources	= ARRAY_SIZE(spi0_resources),
@@ -400,7 +397,7 @@
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi1_resources,
 	.num_resources	= ARRAY_SIZE(spi1_resources),
@@ -466,7 +463,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = 0xffffffffUL;
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
 static struct atmel_lcdfb_info lcdc_data;
 
 static struct resource lcdc_resources[] = {
@@ -494,7 +491,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &lcdc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &lcdc_data,
 	},
 	.resource	= lcdc_resources,
@@ -507,6 +504,17 @@
 		return;
 	}
 
+#if defined(CONFIG_FB_ATMEL_STN)
+	at91_set_A_periph(AT91_PIN_PB0, 0);     /* LCDVSYNC */
+	at91_set_A_periph(AT91_PIN_PB1, 0);     /* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PB2, 0);     /* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PB3, 0);     /* LCDDEN */
+	at91_set_A_periph(AT91_PIN_PB4, 0);     /* LCDCC */
+	at91_set_A_periph(AT91_PIN_PB5, 0);     /* LCDD0 */
+	at91_set_A_periph(AT91_PIN_PB6, 0);     /* LCDD1 */
+	at91_set_A_periph(AT91_PIN_PB7, 0);     /* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PB8, 0);     /* LCDD3 */
+#else
 	at91_set_A_periph(AT91_PIN_PB1, 0);	/* LCDHSYNC */
 	at91_set_A_periph(AT91_PIN_PB2, 0);	/* LCDDOTCK */
 	at91_set_A_periph(AT91_PIN_PB3, 0);	/* LCDDEN */
@@ -529,6 +537,7 @@
 	at91_set_B_periph(AT91_PIN_PB26, 0);	/* LCDD21 */
 	at91_set_B_periph(AT91_PIN_PB27, 0);	/* LCDD22 */
 	at91_set_B_periph(AT91_PIN_PB28, 0);	/* LCDD23 */
+#endif
 
 	lcdc_data = *data;
 	platform_device_register(&at91_lcdc_device);
@@ -539,24 +548,220 @@
 
 
 /* --------------------------------------------------------------------
- *  LEDs
+ *  RTT
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_LEDS)
-u8 at91_leds_cpu;
-u8 at91_leds_timer;
+static struct resource rtt_resources[] = {
+	{
+		.start	= AT91_BASE_SYS + AT91_RTT,
+		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
 
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+static struct platform_device at91sam9261_rtt_device = {
+	.name		= "at91_rtt",
+	.id		= -1,
+	.resource	= rtt_resources,
+	.num_resources	= ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
 {
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
+	platform_device_register(&at91sam9261_rtt_device);
+}
 
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9261_wdt_device = {
+	.name		= "at91_wdt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+	platform_device_register(&at91sam9261_wdt_device);
 }
 #else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9261_BASE_SSC0,
+		.end	= AT91SAM9261_BASE_SSC0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9261_ID_SSC0,
+		.end	= AT91SAM9261_ID_SSC0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9261_ssc0_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc0_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc0_resources,
+	.num_resources	= ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB21, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB22, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB23, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB24, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB25, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB26, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9261_BASE_SSC1,
+		.end	= AT91SAM9261_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9261_ID_SSC1,
+		.end	= AT91SAM9261_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9261_ssc1_device = {
+	.name	= "ssc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ssc1_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc1_resources,
+	.num_resources	= ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_B_periph(AT91_PIN_PA17, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_B_periph(AT91_PIN_PA18, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_B_periph(AT91_PIN_PA19, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_B_periph(AT91_PIN_PA20, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_B_periph(AT91_PIN_PA21, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_B_periph(AT91_PIN_PA22, 1);
+}
+
+static u64 ssc2_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc2_resources[] = {
+	[0] = {
+		.start	= AT91SAM9261_BASE_SSC2,
+		.end	= AT91SAM9261_BASE_SSC2 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9261_ID_SSC2,
+		.end	= AT91SAM9261_ID_SSC2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9261_ssc2_device = {
+	.name	= "ssc",
+	.id	= 2,
+	.dev	= {
+		.dma_mask		= &ssc2_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc2_resources,
+	.num_resources	= ARRAY_SIZE(ssc2_resources),
+};
+
+static inline void configure_ssc2_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_B_periph(AT91_PIN_PC25, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_B_periph(AT91_PIN_PC26, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_B_periph(AT91_PIN_PC27, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_B_periph(AT91_PIN_PC28, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_B_periph(AT91_PIN_PC29, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_B_periph(AT91_PIN_PC30, 1);
+}
+
+/*
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91SAM9261_ID_SSC0:
+		pdev = &at91sam9261_ssc0_device;
+		configure_ssc0_pins(pins);
+		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
+		break;
+	case AT91SAM9261_ID_SSC1:
+		pdev = &at91sam9261_ssc1_device;
+		configure_ssc1_pins(pins);
+		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
+		break;
+	case AT91SAM9261_ID_SSC2:
+		pdev = &at91sam9261_ssc2_device;
+		configure_ssc2_pins(pins);
+		at91_clock_associate("ssc2_clk", &pdev->dev, "pclk");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #endif
 
 
@@ -584,12 +789,15 @@
 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9261_dbgu_device = {
 	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
-				.platform_data	= &dbgu_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
 	},
 	.resource	= dbgu_resources,
 	.num_resources	= ARRAY_SIZE(dbgu_resources),
@@ -619,23 +827,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9261_uart0_device = {
 	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
-				.platform_data	= &uart0_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
 	},
 	.resource	= uart0_resources,
 	.num_resources	= ARRAY_SIZE(uart0_resources),
 };
 
-static inline void configure_usart0_pins(void)
+static inline void configure_usart0_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PC8, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PC9, 0);		/* RXD0 */
-	at91_set_A_periph(AT91_PIN_PC10, 0);		/* RTS0 */
-	at91_set_A_periph(AT91_PIN_PC11, 0);		/* CTS0 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PC10, 0);	/* RTS0 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PC11, 0);	/* CTS0 */
 }
 
 static struct resource uart1_resources[] = {
@@ -656,21 +870,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9261_uart1_device = {
 	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
-				.platform_data	= &uart1_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
 	},
 	.resource	= uart1_resources,
 	.num_resources	= ARRAY_SIZE(uart1_resources),
 };
 
-static inline void configure_usart1_pins(void)
+static inline void configure_usart1_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PC12, 1);		/* TXD1 */
 	at91_set_A_periph(AT91_PIN_PC13, 0);		/* RXD1 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PA12, 0);	/* RTS1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PA13, 0);	/* CTS1 */
 }
 
 static struct resource uart2_resources[] = {
@@ -691,27 +913,35 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9261_uart2_device = {
 	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
-				.platform_data	= &uart2_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
 	},
 	.resource	= uart2_resources,
 	.num_resources	= ARRAY_SIZE(uart2_resources),
 };
 
-static inline void configure_usart2_pins(void)
+static inline void configure_usart2_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PC15, 0);		/* RXD2 */
 	at91_set_A_periph(AT91_PIN_PC14, 1);		/* TXD2 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PA15, 0);	/* RTS2*/
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PA16, 0);	/* CTS2 */
 }
 
-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init at91_init_serial(struct at91_uart_config *config)
+void __init __deprecated at91_init_serial(struct at91_uart_config *config)
 {
 	int i;
 
@@ -719,17 +949,17 @@
 	for (i = 0; i < config->nr_tty; i++) {
 		switch (config->tty_map[i]) {
 			case 0:
-				configure_usart0_pins();
+				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9261_uart0_device;
 				at91_clock_associate("usart0_clk", &at91sam9261_uart0_device.dev, "usart");
 				break;
 			case 1:
-				configure_usart1_pins();
+				configure_usart1_pins(0);
 				at91_uarts[i] = &at91sam9261_uart1_device;
 				at91_clock_associate("usart1_clk", &at91sam9261_uart1_device.dev, "usart");
 				break;
 			case 2:
-				configure_usart2_pins();
+				configure_usart2_pins(0);
 				at91_uarts[i] = &at91sam9261_uart2_device;
 				at91_clock_associate("usart2_clk", &at91sam9261_uart2_device.dev, "usart");
 				break;
@@ -751,6 +981,48 @@
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91sam9261_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91SAM9261_ID_US0:
+			pdev = &at91sam9261_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9261_ID_US1:
+			pdev = &at91sam9261_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9261_ID_US2:
+			pdev = &at91sam9261_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -761,7 +1033,9 @@
 	}
 }
 #else
-void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -774,6 +1048,8 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	at91_add_device_rtt();
+	at91_add_device_watchdog();
 	return 0;
 }
 
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 00e27b1..a53ba0f 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -304,34 +304,34 @@
 static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
 	7,	/* Advanced Interrupt Controller (FIQ) */
 	7,	/* System Peripherals */
-	0,	/* Parallel IO Controller A */
-	0,	/* Parallel IO Controller B */
-	0,	/* Parallel IO Controller C, D and E */
+	1,	/* Parallel IO Controller A */
+	1,	/* Parallel IO Controller B */
+	1,	/* Parallel IO Controller C, D and E */
 	0,
 	0,
-	6,	/* USART 0 */
-	6,	/* USART 1 */
-	6,	/* USART 2 */
+	5,	/* USART 0 */
+	5,	/* USART 1 */
+	5,	/* USART 2 */
 	0,	/* Multimedia Card Interface 0 */
 	0,	/* Multimedia Card Interface 1 */
-	4,	/* CAN */
-	0,	/* Two-Wire Interface */
-	6,	/* Serial Peripheral Interface 0 */
-	6,	/* Serial Peripheral Interface 1 */
-	5,	/* Serial Synchronous Controller 0 */
-	5,	/* Serial Synchronous Controller 1 */
-	6,	/* AC97 Controller */
+	3,	/* CAN */
+	6,	/* Two-Wire Interface */
+	5,	/* Serial Peripheral Interface 0 */
+	5,	/* Serial Peripheral Interface 1 */
+	4,	/* Serial Synchronous Controller 0 */
+	4,	/* Serial Synchronous Controller 1 */
+	5,	/* AC97 Controller */
 	0,	/* Timer Counter 0, 1 and 2 */
 	0,	/* Pulse Width Modulation Controller */
 	3,	/* Ethernet */
 	0,
 	0,	/* 2D Graphic Engine */
-	3,	/* USB Device Port */
+	2,	/* USB Device Port */
 	0,	/* Image Sensor Interface */
 	3,	/* LDC Controller */
 	0,	/* DMA Controller */
 	0,
-	3,	/* USB Host port */
+	2,	/* USB Host port */
 	0,	/* Advanced Interrupt Controller (IRQ0) */
 	0,	/* Advanced Interrupt Controller (IRQ1) */
 };
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index ac329a9..0b12e1a 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -12,6 +12,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -32,7 +33,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = 0xffffffffUL;
+static u64 ohci_dmamask = DMA_BIT_MASK(32);
 static struct at91_usbh_data usbh_data;
 
 static struct resource usbh_resources[] = {
@@ -53,7 +54,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &ohci_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &usbh_data,
 	},
 	.resource	= usbh_resources,
@@ -136,7 +137,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = 0xffffffffUL;
+static u64 eth_dmamask = DMA_BIT_MASK(32);
 static struct at91_eth_data eth_data;
 
 static struct resource eth_resources[] = {
@@ -157,7 +158,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &eth_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &eth_data,
 	},
 	.resource	= eth_resources,
@@ -210,7 +211,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = 0xffffffffUL;
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct at91_mmc_data mmc0_data, mmc1_data;
 
 static struct resource mmc0_resources[] = {
@@ -231,7 +232,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc0_data,
 	},
 	.resource	= mmc0_resources,
@@ -256,7 +257,7 @@
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc1_data,
 	},
 	.resource	= mmc1_resources,
@@ -382,7 +383,7 @@
 		return;
 
 	csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
-	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC);
+	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
 
 	/* set the bus interface characteristics */
 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
@@ -500,7 +501,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = 0xffffffffUL;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
 
 static struct resource spi0_resources[] = {
 	[0] = {
@@ -520,7 +521,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi0_resources,
 	.num_resources	= ARRAY_SIZE(spi0_resources),
@@ -546,7 +547,7 @@
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi1_resources,
 	.num_resources	= ARRAY_SIZE(spi1_resources),
@@ -612,7 +613,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
-static u64 ac97_dmamask = 0xffffffffUL;
+static u64 ac97_dmamask = DMA_BIT_MASK(32);
 static struct atmel_ac97_data ac97_data;
 
 static struct resource ac97_resources[] = {
@@ -633,7 +634,7 @@
 	.id		= 1,
 	.dev		= {
 				.dma_mask		= &ac97_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &ac97_data,
 	},
 	.resource	= ac97_resources,
@@ -667,7 +668,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = 0xffffffffUL;
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
 static struct atmel_lcdfb_info lcdc_data;
 
 static struct resource lcdc_resources[] = {
@@ -688,7 +689,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &lcdc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &lcdc_data,
 	},
 	.resource	= lcdc_resources,
@@ -732,24 +733,242 @@
 
 
 /* --------------------------------------------------------------------
- *  LEDs
+ *  Image Sensor Interface
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_LEDS)
-u8 at91_leds_cpu;
-u8 at91_leds_timer;
+#if defined(CONFIG_VIDEO_AT91_ISI) || defined(CONFIG_VIDEO_AT91_ISI_MODULE)
 
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+struct resource isi_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_ISI,
+		.end	= AT91SAM9263_BASE_ISI + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_ISI,
+		.end	= AT91SAM9263_ID_ISI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_isi_device = {
+	.name		= "at91_isi",
+	.id		= -1,
+	.resource	= isi_resources,
+	.num_resources	= ARRAY_SIZE(isi_resources),
+};
+
+void __init at91_add_device_isi(void)
 {
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
-
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
+	at91_set_A_periph(AT91_PIN_PE0, 0);	/* ISI_D0 */
+	at91_set_A_periph(AT91_PIN_PE1, 0);	/* ISI_D1 */
+	at91_set_A_periph(AT91_PIN_PE2, 0);	/* ISI_D2 */
+	at91_set_A_periph(AT91_PIN_PE3, 0);	/* ISI_D3 */
+	at91_set_A_periph(AT91_PIN_PE4, 0);	/* ISI_D4 */
+	at91_set_A_periph(AT91_PIN_PE5, 0);	/* ISI_D5 */
+	at91_set_A_periph(AT91_PIN_PE6, 0);	/* ISI_D6 */
+	at91_set_A_periph(AT91_PIN_PE7, 0);	/* ISI_D7 */
+	at91_set_A_periph(AT91_PIN_PE8, 0);	/* ISI_PCK */
+	at91_set_A_periph(AT91_PIN_PE9, 0);	/* ISI_HSYNC */
+	at91_set_A_periph(AT91_PIN_PE10, 0);	/* ISI_VSYNC */
+	at91_set_B_periph(AT91_PIN_PE11, 0);	/* ISI_MCK (PCK3) */
+	at91_set_B_periph(AT91_PIN_PE12, 0);	/* ISI_PD8 */
+	at91_set_B_periph(AT91_PIN_PE13, 0);	/* ISI_PD9 */
+	at91_set_B_periph(AT91_PIN_PE14, 0);	/* ISI_PD10 */
+	at91_set_B_periph(AT91_PIN_PE15, 0);	/* ISI_PD11 */
 }
 #else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+void __init at91_add_device_isi(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  RTT
+ * -------------------------------------------------------------------- */
+
+static struct resource rtt0_resources[] = {
+	{
+		.start	= AT91_BASE_SYS + AT91_RTT0,
+		.end	= AT91_BASE_SYS + AT91_RTT0 + SZ_16 - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device at91sam9263_rtt0_device = {
+	.name		= "at91_rtt",
+	.id		= 0,
+	.resource	= rtt0_resources,
+	.num_resources	= ARRAY_SIZE(rtt0_resources),
+};
+
+static struct resource rtt1_resources[] = {
+	{
+		.start	= AT91_BASE_SYS + AT91_RTT1,
+		.end	= AT91_BASE_SYS + AT91_RTT1 + SZ_16 - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device at91sam9263_rtt1_device = {
+	.name		= "at91_rtt",
+	.id		= 1,
+	.resource	= rtt1_resources,
+	.num_resources	= ARRAY_SIZE(rtt1_resources),
+};
+
+static void __init at91_add_device_rtt(void)
+{
+	platform_device_register(&at91sam9263_rtt0_device);
+	platform_device_register(&at91sam9263_rtt1_device);
+}
+
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9263_wdt_device = {
+	.name		= "at91_wdt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+	platform_device_register(&at91sam9263_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_SSC0,
+		.end	= AT91SAM9263_BASE_SSC0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_SSC0,
+		.end	= AT91SAM9263_ID_SSC0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_ssc0_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc0_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc0_resources,
+	.num_resources	= ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_B_periph(AT91_PIN_PB0, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_B_periph(AT91_PIN_PB1, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_B_periph(AT91_PIN_PB2, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_B_periph(AT91_PIN_PB3, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_B_periph(AT91_PIN_PB4, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_B_periph(AT91_PIN_PB5, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_SSC1,
+		.end	= AT91SAM9263_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_SSC1,
+		.end	= AT91SAM9263_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_ssc1_device = {
+	.name	= "ssc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ssc1_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc1_resources,
+	.num_resources	= ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PB6, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PB7, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PB8, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PB9, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_A_periph(AT91_PIN_PB10, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_A_periph(AT91_PIN_PB11, 1);
+}
+
+/*
+ * Return the device node so that board init code can use it as the
+ * parent for the device node reflecting how it's used on this board.
+ *
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91SAM9263_ID_SSC0:
+		pdev = &at91sam9263_ssc0_device;
+		configure_ssc0_pins(pins);
+		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
+		break;
+	case AT91SAM9263_ID_SSC1:
+		pdev = &at91sam9263_ssc1_device;
+		configure_ssc1_pins(pins);
+		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #endif
 
 
@@ -778,12 +997,15 @@
 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9263_dbgu_device = {
 	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
-				.platform_data	= &dbgu_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
 	},
 	.resource	= dbgu_resources,
 	.num_resources	= ARRAY_SIZE(dbgu_resources),
@@ -813,23 +1035,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9263_uart0_device = {
 	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
-				.platform_data	= &uart0_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
 	},
 	.resource	= uart0_resources,
 	.num_resources	= ARRAY_SIZE(uart0_resources),
 };
 
-static inline void configure_usart0_pins(void)
+static inline void configure_usart0_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA26, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PA27, 0);		/* RXD0 */
-	at91_set_A_periph(AT91_PIN_PA28, 0);		/* RTS0 */
-	at91_set_A_periph(AT91_PIN_PA29, 0);		/* CTS0 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PA28, 0);	/* RTS0 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA29, 0);	/* CTS0 */
 }
 
 static struct resource uart1_resources[] = {
@@ -850,23 +1078,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9263_uart1_device = {
 	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
-				.platform_data	= &uart1_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
 	},
 	.resource	= uart1_resources,
 	.num_resources	= ARRAY_SIZE(uart1_resources),
 };
 
-static inline void configure_usart1_pins(void)
+static inline void configure_usart1_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
 	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
-	at91_set_B_periph(AT91_PIN_PD7, 0);		/* RTS1 */
-	at91_set_B_periph(AT91_PIN_PD8, 0);		/* CTS1 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PD7, 0);	/* RTS1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PD8, 0);	/* CTS1 */
 }
 
 static struct resource uart2_resources[] = {
@@ -887,29 +1121,35 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9263_uart2_device = {
 	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
-				.platform_data	= &uart2_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
 	},
 	.resource	= uart2_resources,
 	.num_resources	= ARRAY_SIZE(uart2_resources),
 };
 
-static inline void configure_usart2_pins(void)
+static inline void configure_usart2_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
 	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
-	at91_set_B_periph(AT91_PIN_PD5, 0);		/* RTS2 */
-	at91_set_B_periph(AT91_PIN_PD6, 0);		/* CTS2 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PD5, 0);	/* RTS2 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PD6, 0);	/* CTS2 */
 }
 
-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init at91_init_serial(struct at91_uart_config *config)
+void __init __deprecated at91_init_serial(struct at91_uart_config *config)
 {
 	int i;
 
@@ -917,17 +1157,17 @@
 	for (i = 0; i < config->nr_tty; i++) {
 		switch (config->tty_map[i]) {
 			case 0:
-				configure_usart0_pins();
+				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9263_uart0_device;
 				at91_clock_associate("usart0_clk", &at91sam9263_uart0_device.dev, "usart");
 				break;
 			case 1:
-				configure_usart1_pins();
+				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9263_uart1_device;
 				at91_clock_associate("usart1_clk", &at91sam9263_uart1_device.dev, "usart");
 				break;
 			case 2:
-				configure_usart2_pins();
+				configure_usart2_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9263_uart2_device;
 				at91_clock_associate("usart2_clk", &at91sam9263_uart2_device.dev, "usart");
 				break;
@@ -949,6 +1189,48 @@
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91sam9263_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91SAM9263_ID_US0:
+			pdev = &at91sam9263_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9263_ID_US1:
+			pdev = &at91sam9263_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9263_ID_US2:
+			pdev = &at91sam9263_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -960,6 +1242,8 @@
 }
 #else
 void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -971,6 +1255,8 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	at91_add_device_rtt();
+	at91_add_device_watchdog();
 	return 0;
 }
 
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 2bd60a3..f43b5c3 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -9,6 +9,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+#include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -29,7 +30,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = 0xffffffffUL;
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct at91_mmc_data mmc_data;
 
 static struct resource mmc_resources[] = {
@@ -50,7 +51,7 @@
 	.id		= -1,
 	.dev		= {
 				.dma_mask		= &mmc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &mmc_data,
 	},
 	.resource	= mmc_resources,
@@ -247,7 +248,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = 0xffffffffUL;
+static u64 spi_dmamask = DMA_BIT_MASK(32);
 
 static struct resource spi_resources[] = {
 	[0] = {
@@ -267,7 +268,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	.resource	= spi_resources,
 	.num_resources	= ARRAY_SIZE(spi_resources),
@@ -312,7 +313,7 @@
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = 0xffffffffUL;
+static u64 lcdc_dmamask = DMA_BIT_MASK(32);
 static struct atmel_lcdfb_info lcdc_data;
 
 static struct resource lcdc_resources[] = {
@@ -340,7 +341,7 @@
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &lcdc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
 				.platform_data		= &lcdc_data,
 	},
 	.resource	= lcdc_resources,
@@ -384,24 +385,196 @@
 
 
 /* --------------------------------------------------------------------
- *  LEDs
+ *  RTC
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_LEDS)
-u8 at91_leds_cpu;
-u8 at91_leds_timer;
+#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
+static struct platform_device at91sam9rl_rtc_device = {
+	.name		= "at91_rtc",
+	.id		= -1,
+	.num_resources	= 0,
+};
 
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+static void __init at91_add_device_rtc(void)
 {
-	/* Enable GPIO to access the LEDs */
-	at91_set_gpio_output(cpu_led, 1);
-	at91_set_gpio_output(timer_led, 1);
-
-	at91_leds_cpu	= cpu_led;
-	at91_leds_timer	= timer_led;
+	platform_device_register(&at91sam9rl_rtc_device);
 }
 #else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+static void __init at91_add_device_rtc(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  RTT
+ * -------------------------------------------------------------------- */
+
+static struct resource rtt_resources[] = {
+	{
+		.start	= AT91_BASE_SYS + AT91_RTT,
+		.end	= AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device at91sam9rl_rtt_device = {
+	.name		= "at91_rtt",
+	.id		= -1,
+	.resource	= rtt_resources,
+	.num_resources	= ARRAY_SIZE(rtt_resources),
+};
+
+static void __init at91_add_device_rtt(void)
+{
+	platform_device_register(&at91sam9rl_rtt_device);
+}
+
+
+/* --------------------------------------------------------------------
+ *  Watchdog
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+static struct platform_device at91sam9rl_wdt_device = {
+	.name		= "at91_wdt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_watchdog(void)
+{
+	platform_device_register(&at91sam9rl_wdt_device);
+}
+#else
+static void __init at91_add_device_watchdog(void) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  SSC -- Synchronous Serial Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
+static u64 ssc0_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9RL_BASE_SSC0,
+		.end	= AT91SAM9RL_BASE_SSC0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9RL_ID_SSC0,
+		.end	= AT91SAM9RL_ID_SSC0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9rl_ssc0_device = {
+	.name	= "ssc",
+	.id	= 0,
+	.dev	= {
+		.dma_mask		= &ssc0_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc0_resources,
+	.num_resources	= ARRAY_SIZE(ssc0_resources),
+};
+
+static inline void configure_ssc0_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_A_periph(AT91_PIN_PC0, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_A_periph(AT91_PIN_PC1, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_A_periph(AT91_PIN_PA15, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_A_periph(AT91_PIN_PA16, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_B_periph(AT91_PIN_PA10, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_B_periph(AT91_PIN_PA22, 1);
+}
+
+static u64 ssc1_dmamask = DMA_BIT_MASK(32);
+
+static struct resource ssc1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9RL_BASE_SSC1,
+		.end	= AT91SAM9RL_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9RL_ID_SSC1,
+		.end	= AT91SAM9RL_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9rl_ssc1_device = {
+	.name	= "ssc",
+	.id	= 1,
+	.dev	= {
+		.dma_mask		= &ssc1_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.resource	= ssc1_resources,
+	.num_resources	= ARRAY_SIZE(ssc1_resources),
+};
+
+static inline void configure_ssc1_pins(unsigned pins)
+{
+	if (pins & ATMEL_SSC_TF)
+		at91_set_B_periph(AT91_PIN_PA29, 1);
+	if (pins & ATMEL_SSC_TK)
+		at91_set_B_periph(AT91_PIN_PA30, 1);
+	if (pins & ATMEL_SSC_TD)
+		at91_set_B_periph(AT91_PIN_PA13, 1);
+	if (pins & ATMEL_SSC_RD)
+		at91_set_B_periph(AT91_PIN_PA14, 1);
+	if (pins & ATMEL_SSC_RK)
+		at91_set_B_periph(AT91_PIN_PA9, 1);
+	if (pins & ATMEL_SSC_RF)
+		at91_set_B_periph(AT91_PIN_PA8, 1);
+}
+
+/*
+ * Return the device node so that board init code can use it as the
+ * parent for the device node reflecting how it's used on this board.
+ *
+ * SSC controllers are accessed through library code, instead of any
+ * kind of all-singing/all-dancing driver.  For example one could be
+ * used by a particular I2S audio codec's driver, while another one
+ * on the same system might be used by a custom data capture driver.
+ */
+void __init at91_add_device_ssc(unsigned id, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	/*
+	 * NOTE: caller is responsible for passing information matching
+	 * "pins" to whatever will be using each particular controller.
+	 */
+	switch (id) {
+	case AT91SAM9RL_ID_SSC0:
+		pdev = &at91sam9rl_ssc0_device;
+		configure_ssc0_pins(pins);
+		at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
+		break;
+	case AT91SAM9RL_ID_SSC1:
+		pdev = &at91sam9rl_ssc1_device;
+		configure_ssc1_pins(pins);
+		at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
+		break;
+	default:
+		return;
+	}
+
+	platform_device_register(pdev);
+}
+
+#else
+void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
 #endif
 
 
@@ -429,12 +602,15 @@
 	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
+static u64 dbgu_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9rl_dbgu_device = {
 	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
-				.platform_data	= &dbgu_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &dbgu_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &dbgu_data,
 	},
 	.resource	= dbgu_resources,
 	.num_resources	= ARRAY_SIZE(dbgu_resources),
@@ -464,23 +640,37 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart0_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9rl_uart0_device = {
 	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
-				.platform_data	= &uart0_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart0_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart0_data,
 	},
 	.resource	= uart0_resources,
 	.num_resources	= ARRAY_SIZE(uart0_resources),
 };
 
-static inline void configure_usart0_pins(void)
+static inline void configure_usart0_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA6, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PA7, 0);		/* RXD0 */
-	at91_set_A_periph(AT91_PIN_PA9, 0);		/* RTS0 */
-	at91_set_A_periph(AT91_PIN_PA10, 0);		/* CTS0 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PA9, 0);	/* RTS0 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA10, 0);	/* CTS0 */
+	if (pins & ATMEL_UART_DSR)
+		at91_set_A_periph(AT91_PIN_PD14, 0);	/* DSR0 */
+	if (pins & ATMEL_UART_DTR)
+		at91_set_A_periph(AT91_PIN_PD15, 0);	/* DTR0 */
+	if (pins & ATMEL_UART_DCD)
+		at91_set_A_periph(AT91_PIN_PD16, 0);	/* DCD0 */
+	if (pins & ATMEL_UART_RI)
+		at91_set_A_periph(AT91_PIN_PD17, 0);	/* RI0 */
 }
 
 static struct resource uart1_resources[] = {
@@ -501,21 +691,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart1_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9rl_uart1_device = {
 	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
-				.platform_data	= &uart1_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart1_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart1_data,
 	},
 	.resource	= uart1_resources,
 	.num_resources	= ARRAY_SIZE(uart1_resources),
 };
 
-static inline void configure_usart1_pins(void)
+static inline void configure_usart1_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA11, 1);		/* TXD1 */
 	at91_set_A_periph(AT91_PIN_PA12, 0);		/* RXD1 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PA18, 0);	/* RTS1 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PA19, 0);	/* CTS1 */
 }
 
 static struct resource uart2_resources[] = {
@@ -536,21 +734,29 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart2_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9rl_uart2_device = {
 	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
-				.platform_data	= &uart2_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart2_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart2_data,
 	},
 	.resource	= uart2_resources,
 	.num_resources	= ARRAY_SIZE(uart2_resources),
 };
 
-static inline void configure_usart2_pins(void)
+static inline void configure_usart2_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PA13, 1);		/* TXD2 */
 	at91_set_A_periph(AT91_PIN_PA14, 0);		/* RXD2 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_A_periph(AT91_PIN_PA29, 0);	/* RTS2 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_A_periph(AT91_PIN_PA30, 0);	/* CTS2 */
 }
 
 static struct resource uart3_resources[] = {
@@ -571,27 +777,35 @@
 	.use_dma_rx	= 1,
 };
 
+static u64 uart3_dmamask = DMA_BIT_MASK(32);
+
 static struct platform_device at91sam9rl_uart3_device = {
 	.name		= "atmel_usart",
 	.id		= 4,
 	.dev		= {
-				.platform_data	= &uart3_data,
-				.coherent_dma_mask = 0xffffffff,
+				.dma_mask		= &uart3_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &uart3_data,
 	},
 	.resource	= uart3_resources,
 	.num_resources	= ARRAY_SIZE(uart3_resources),
 };
 
-static inline void configure_usart3_pins(void)
+static inline void configure_usart3_pins(unsigned pins)
 {
 	at91_set_A_periph(AT91_PIN_PB0, 1);		/* TXD3 */
 	at91_set_A_periph(AT91_PIN_PB1, 0);		/* RXD3 */
+
+	if (pins & ATMEL_UART_RTS)
+		at91_set_B_periph(AT91_PIN_PD4, 0);	/* RTS3 */
+	if (pins & ATMEL_UART_CTS)
+		at91_set_B_periph(AT91_PIN_PD3, 0);	/* CTS3 */
 }
 
-struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+static struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init at91_init_serial(struct at91_uart_config *config)
+void __init __deprecated at91_init_serial(struct at91_uart_config *config)
 {
 	int i;
 
@@ -599,22 +813,22 @@
 	for (i = 0; i < config->nr_tty; i++) {
 		switch (config->tty_map[i]) {
 			case 0:
-				configure_usart0_pins();
+				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
 				at91_uarts[i] = &at91sam9rl_uart0_device;
 				at91_clock_associate("usart0_clk", &at91sam9rl_uart0_device.dev, "usart");
 				break;
 			case 1:
-				configure_usart1_pins();
+				configure_usart1_pins(0);
 				at91_uarts[i] = &at91sam9rl_uart1_device;
 				at91_clock_associate("usart1_clk", &at91sam9rl_uart1_device.dev, "usart");
 				break;
 			case 2:
-				configure_usart2_pins();
+				configure_usart2_pins(0);
 				at91_uarts[i] = &at91sam9rl_uart2_device;
 				at91_clock_associate("usart2_clk", &at91sam9rl_uart2_device.dev, "usart");
 				break;
 			case 3:
-				configure_usart3_pins();
+				configure_usart3_pins(0);
 				at91_uarts[i] = &at91sam9rl_uart3_device;
 				at91_clock_associate("usart3_clk", &at91sam9rl_uart3_device.dev, "usart");
 				break;
@@ -636,6 +850,53 @@
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+		case 0:		/* DBGU */
+			pdev = &at91sam9rl_dbgu_device;
+			configure_dbgu_pins();
+			at91_clock_associate("mck", &pdev->dev, "usart");
+			break;
+		case AT91SAM9RL_ID_US0:
+			pdev = &at91sam9rl_uart0_device;
+			configure_usart0_pins(pins);
+			at91_clock_associate("usart0_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9RL_ID_US1:
+			pdev = &at91sam9rl_uart1_device;
+			configure_usart1_pins(pins);
+			at91_clock_associate("usart1_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9RL_ID_US2:
+			pdev = &at91sam9rl_uart2_device;
+			configure_usart2_pins(pins);
+			at91_clock_associate("usart2_clk", &pdev->dev, "usart");
+			break;
+		case AT91SAM9RL_ID_US3:
+			pdev = &at91sam9rl_uart3_device;
+			configure_usart3_pins(pins);
+			at91_clock_associate("usart3_clk", &pdev->dev, "usart");
+			break;
+		default:
+			return;
+	}
+	pdev->id = portnr;		/* update to mapped ID */
+
+	if (portnr < ATMEL_MAX_UART)
+		at91_uarts[portnr] = pdev;
+}
+
+void __init at91_set_serial_console(unsigned portnr)
+{
+	if (portnr < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[portnr];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
 void __init at91_add_device_serial(void)
 {
 	int i;
@@ -646,7 +907,9 @@
 	}
 }
 #else
-void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init __deprecated at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
 void __init at91_add_device_serial(void) {}
 #endif
 
@@ -659,6 +922,9 @@
  */
 static int __init at91_add_standard_devices(void)
 {
+	at91_add_device_rtc();
+	at91_add_device_rtt();
+	at91_add_device_watchdog();
 	return 0;
 }
 
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
new file mode 100644
index 0000000..1854371
--- /dev/null
+++ b/arch/arm/mach-at91/board-cap9adk.c
@@ -0,0 +1,359 @@
+/*
+ * linux/arch/arm/mach-at91/board-cap9adk.c
+ *
+ *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
+ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
+ *  Copyright (C) 2005 SAN People
+ *  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 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/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/fb.h>
+#include <linux/mtd/physmap.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91cap9_matrix.h>
+#include <asm/arch/at91sam926x_mc.h>
+
+#include "generic.h"
+
+
+static void __init cap9adk_map_io(void)
+{
+	/* Initialize processor: 12 MHz crystal */
+	at91cap9_initialize(12000000);
+
+	/* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
+	at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
+	/* ... POWER LED always on */
+	at91_set_gpio_output(AT91_PIN_PC29, 1);
+
+	/* Setup the serial ports and console */
+	at91_register_uart(0, 0, 0);		/* DBGU = ttyS0 */
+	at91_set_serial_console(0);
+}
+
+static void __init cap9adk_init_irq(void)
+{
+	at91cap9_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata cap9adk_usbh_data = {
+	.ports		= 2,
+};
+
+
+/*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static int ads7843_pendown_state(void)
+{
+	return !at91_get_gpio_value(AT91_PIN_PC4);	/* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model			= 7843,
+	.x_min			= 150,
+	.x_max			= 3830,
+	.y_min			= 190,
+	.y_max			= 3830,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 450,
+	.y_plate_ohms		= 250,
+	.pressure_max		= 15000,
+	.debounce_max		= 1,
+	.debounce_rep		= 0,
+	.debounce_tol		= (~0),
+	.get_pendown_state	= ads7843_pendown_state,
+};
+
+static void __init cap9adk_add_device_ts(void)
+{
+	at91_set_gpio_input(AT91_PIN_PC4, 1);	/* Touchscreen PENIRQ */
+	at91_set_gpio_input(AT91_PIN_PC5, 1);	/* Touchscreen BUSY */
+}
+#else
+static void __init cap9adk_add_device_ts(void) {}
+#endif
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info cap9adk_spi_devices[] = {
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+	{	/* DataFlash card */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 0,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias	= "ads7846",
+		.chip_select	= 3,		/* can be 2 or 3, depending on J2 jumper */
+		.max_speed_hz	= 125000 * 26,	/* (max sample rate @ 3V) * (cmd + data + overhead) */
+		.bus_num	= 0,
+		.platform_data	= &ads_info,
+		.irq		= AT91_PIN_PC4,
+	},
+#endif
+};
+
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata cap9adk_mmc_data = {
+	.wire4		= 1,
+//	.det_pin	= ... not connected
+//	.wp_pin		= ... not connected
+//	.vcc_pin	= ... not connected
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata cap9adk_macb_data = {
+	.is_rmii	= 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata cap9adk_nand_partitions[] = {
+	{
+		.name	= "NAND partition",
+		.offset	= 0,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(cap9adk_nand_partitions);
+	return cap9adk_nand_partitions;
+}
+
+static struct at91_nand_data __initdata cap9adk_nand_data = {
+	.ale		= 21,
+	.cle		= 22,
+//	.det_pin	= ... not connected
+//	.rdy_pin	= ... not connected
+	.enable_pin	= AT91_PIN_PD15,
+	.partition_info	= nand_partitions,
+#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+	.bus_width_16	= 1,
+#else
+	.bus_width_16	= 0,
+#endif
+};
+
+
+/*
+ * NOR flash
+ */
+static struct mtd_partition cap9adk_nor_partitions[] = {
+	{
+		.name		= "NOR partition",
+		.offset		= 0,
+		.size		= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct physmap_flash_data cap9adk_nor_data = {
+	.width		= 2,
+	.parts		= cap9adk_nor_partitions,
+	.nr_parts	= ARRAY_SIZE(cap9adk_nor_partitions),
+};
+
+#define NOR_BASE	AT91_CHIPSELECT_0
+#define NOR_SIZE	0x800000
+
+static struct resource nor_flash_resources[] = {
+	{
+		.start	= NOR_BASE,
+		.end	= NOR_BASE + NOR_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device cap9adk_nor_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data	= &cap9adk_nor_data,
+	},
+	.resource	= nor_flash_resources,
+	.num_resources	= ARRAY_SIZE(nor_flash_resources),
+};
+
+static __init void cap9adk_add_device_nor(void)
+{
+	unsigned long csa;
+
+	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
+
+	/* set the bus interface characteristics */
+	at91_sys_write(AT91_SMC_SETUP(0), AT91_SMC_NWESETUP_(4) | AT91_SMC_NCS_WRSETUP_(2)
+			| AT91_SMC_NRDSETUP_(4) | AT91_SMC_NCS_RDSETUP_(2));
+
+	at91_sys_write(AT91_SMC_PULSE(0), AT91_SMC_NWEPULSE_(8) | AT91_SMC_NCS_WRPULSE_(10)
+			| AT91_SMC_NRDPULSE_(8) | AT91_SMC_NCS_RDPULSE_(10));
+
+	at91_sys_write(AT91_SMC_CYCLE(0), AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
+
+	at91_sys_write(AT91_SMC_MODE(0), AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+			| AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
+			| AT91_SMC_DBW_16 | AT91_SMC_TDF_(1));
+
+	platform_device_register(&cap9adk_nor_flash);
+}
+
+
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+	{
+	        .name           = "TX09D50VM1CCA @ 60",
+		.refresh	= 60,
+		.xres		= 240,		.yres		= 320,
+		.pixclock	= KHZ2PICOS(4965),
+
+		.left_margin	= 1,		.right_margin	= 33,
+		.upper_margin	= 1,		.lower_margin	= 0,
+		.hsync_len	= 5,		.vsync_len	= 1,
+
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+	.manufacturer	= "HIT",
+	.monitor        = "TX09D70VM1CCA",
+
+	.modedb		= at91_tft_vga_modes,
+	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
+	.hfmin		= 15000,
+	.hfmax		= 64000,
+	.vfmin		= 50,
+	.vfmax		= 150,
+};
+
+#define AT91CAP9_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
+					| ATMEL_LCDC_DISTYPE_TFT    \
+					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+static void at91_lcdc_power_control(int on)
+{
+	if (on)
+		at91_set_gpio_value(AT91_PIN_PC0, 0);	/* power up */
+	else
+		at91_set_gpio_value(AT91_PIN_PC0, 1);	/* power down */
+}
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data = {
+	.default_bpp			= 16,
+	.default_dmacon			= ATMEL_LCDC_DMAEN,
+	.default_lcdcon2		= AT91CAP9_DEFAULT_LCDCON2,
+	.default_monspecs		= &at91fb_default_monspecs,
+	.atmel_lcdfb_power_control	= at91_lcdc_power_control,
+	.guard_time			= 1,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data;
+#endif
+
+
+/*
+ * AC97
+ */
+static struct atmel_ac97_data cap9adk_ac97_data = {
+//	.reset_pin	= ... not connected
+};
+
+
+static void __init cap9adk_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	set_irq_type(AT91CAP9_ID_UHP, IRQT_HIGH);
+	at91_add_device_usbh(&cap9adk_usbh_data);
+	/* SPI */
+	at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
+	/* Touchscreen */
+	cap9adk_add_device_ts();
+	/* MMC */
+	at91_add_device_mmc(1, &cap9adk_mmc_data);
+	/* Ethernet */
+	at91_add_device_eth(&cap9adk_macb_data);
+	/* NAND */
+	at91_add_device_nand(&cap9adk_nand_data);
+	/* NOR Flash */
+	cap9adk_add_device_nor();
+	/* I2C */
+	at91_add_device_i2c(NULL, 0);
+	/* LCD Controller */
+	set_irq_type(AT91CAP9_ID_LCDC, IRQT_HIGH);
+	at91_add_device_lcdc(&cap9adk_lcdc_data);
+	/* AC97 */
+	at91_add_device_ac97(&cap9adk_ac97_data);
+}
+
+MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
+	/* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
+	.phys_io	= AT91_BASE_SYS,
+	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= cap9adk_map_io,
+	.init_irq	= cap9adk_init_irq,
+	.init_machine	= cap9adk_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index d0aa20c..0e2a11f 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -25,6 +25,8 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -156,6 +158,85 @@
 	.num_resources	= ARRAY_SIZE(csb_flash_resources),
 };
 
+/*
+ * GPIO Buttons (on CSB300)
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button csb300_buttons[] = {
+	{
+		.gpio		= AT91_PIN_PB29,
+		.code		= BTN_0,
+		.desc		= "sw0",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+	{
+		.gpio		= AT91_PIN_PB28,
+		.code		= BTN_1,
+		.desc		= "sw1",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+	{
+		.gpio		= AT91_PIN_PA21,
+		.code		= BTN_2,
+		.desc		= "sw2",
+		.active_low	= 1,
+		.wakeup		= 1,
+	}
+};
+
+static struct gpio_keys_platform_data csb300_button_data = {
+	.buttons	= csb300_buttons,
+	.nbuttons	= ARRAY_SIZE(csb300_buttons),
+};
+
+static struct platform_device csb300_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &csb300_button_data,
+	}
+};
+
+static void __init csb300_add_device_buttons(void)
+{
+	at91_set_gpio_input(AT91_PIN_PB29, 0);	/* sw0 */
+	at91_set_deglitch(AT91_PIN_PB29, 1);
+	at91_set_gpio_input(AT91_PIN_PB28, 0);	/* sw1 */
+	at91_set_deglitch(AT91_PIN_PB28, 1);
+	at91_set_gpio_input(AT91_PIN_PA21, 0);	/* sw2 */
+	at91_set_deglitch(AT91_PIN_PA21, 1);
+
+	platform_device_register(&csb300_button_device);
+}
+#else
+static void __init csb300_add_device_buttons(void) {}
+#endif
+
+static struct gpio_led csb_leds[] = {
+	{	/* "led0", yellow */
+		.name			= "led0",
+		.gpio			= AT91_PIN_PB2,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* "led1", green */
+		.name			= "led1",
+		.gpio			= AT91_PIN_PB1,
+		.active_low		= 1,
+		.default_trigger	= "mmc0",
+	},
+	{	/* "led2", yellow */
+		.name			= "led2",
+		.gpio			= AT91_PIN_PB0,
+		.active_low		= 1,
+		.default_trigger	= "ide-disk",
+	},
+};
+
+
 static void __init csb337_board_init(void)
 {
 	/* Serial */
@@ -177,6 +258,10 @@
 	at91_add_device_mmc(0, &csb337_mmc_data);
 	/* NOR flash */
 	platform_device_register(&csb_flash);
+	/* LEDs */
+	at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
+	/* Switches on CSB300 */
+	csb300_add_device_buttons();
 }
 
 MACHINE_START(CSB337, "Cogent CSB337")
diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c
index 40c9e43..0a897ef 100644
--- a/arch/arm/mach-at91/board-dk.c
+++ b/arch/arm/mach-at91/board-dk.c
@@ -183,6 +183,14 @@
 	.num_resources	= 1,
 };
 
+static struct gpio_led dk_leds[] = {
+	{
+		.name			= "led0",
+		.gpio			= AT91_PIN_PB2,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	}
+};
 
 static void __init dk_board_init(void)
 {
@@ -213,6 +221,8 @@
 	at91_add_device_nand(&dk_nand_data);
 	/* NOR Flash */
 	platform_device_register(&dk_flash);
+	/* LEDs */
+	at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds));
 	/* VGA */
 //	dk_add_device_video();
 }
diff --git a/arch/arm/mach-at91/board-ek.c b/arch/arm/mach-at91/board-ek.c
index 53a5ef9..0574e50 100644
--- a/arch/arm/mach-at91/board-ek.c
+++ b/arch/arm/mach-at91/board-ek.c
@@ -141,6 +141,25 @@
 	.num_resources	= 1,
 };
 
+static struct gpio_led ek_leds[] = {
+	{	/* "user led 1", DS2 */
+		.name			= "green",
+		.gpio			= AT91_PIN_PB0,
+		.active_low		= 1,
+		.default_trigger	= "mmc0",
+	},
+	{	/* "user led 2", DS4 */
+		.name			= "yellow",
+		.gpio			= AT91_PIN_PB1,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* "user led 3", DS6 */
+		.name			= "red",
+		.gpio			= AT91_PIN_PB2,
+		.active_low		= 1,
+	}
+};
 
 static void __init ek_board_init(void)
 {
@@ -167,6 +186,8 @@
 #endif
 	/* NOR Flash */
 	platform_device_register(&ek_flash);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 	/* VGA */
 //	ek_add_device_video();
 }
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 550ae59a..aa29ea5 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -280,6 +280,68 @@
  * LCD Controller
  */
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+
+#if defined(CONFIG_FB_ATMEL_STN)
+
+/* STN */
+static struct fb_videomode at91_stn_modes[] = {
+        {
+		.name           = "SP06Q002 @ 75",
+		.refresh        = 75,
+		.xres           = 320,          .yres           = 240,
+		.pixclock       = KHZ2PICOS(1440),
+
+		.left_margin    = 1,            .right_margin   = 1,
+		.upper_margin   = 0,            .lower_margin   = 0,
+		.hsync_len      = 1,            .vsync_len      = 1,
+
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode          = FB_VMODE_NONINTERLACED,
+        },
+};
+
+static struct fb_monspecs at91fb_default_stn_monspecs = {
+        .manufacturer   = "HIT",
+        .monitor        = "SP06Q002",
+
+        .modedb         = at91_stn_modes,
+        .modedb_len     = ARRAY_SIZE(at91_stn_modes),
+        .hfmin          = 15000,
+        .hfmax          = 64000,
+        .vfmin          = 50,
+        .vfmax          = 150,
+};
+
+#define AT91SAM9261_DEFAULT_STN_LCDCON2	(ATMEL_LCDC_MEMOR_LITTLE \
+					| ATMEL_LCDC_DISTYPE_STNMONO \
+					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE \
+					| ATMEL_LCDC_IFWIDTH_4 \
+					| ATMEL_LCDC_SCANMOD_SINGLE)
+
+static void at91_lcdc_stn_power_control(int on)
+{
+	/* backlight */
+	if (on) {	/* power up */
+		at91_set_gpio_value(AT91_PIN_PC14, 0);
+		at91_set_gpio_value(AT91_PIN_PC15, 0);
+	} else {	/* power down */
+		at91_set_gpio_value(AT91_PIN_PC14, 1);
+		at91_set_gpio_value(AT91_PIN_PC15, 1);
+	}
+}
+
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+	.default_bpp			= 1,
+	.default_dmacon			= ATMEL_LCDC_DMAEN,
+	.default_lcdcon2		= AT91SAM9261_DEFAULT_STN_LCDCON2,
+	.default_monspecs		= &at91fb_default_stn_monspecs,
+	.atmel_lcdfb_power_control	= at91_lcdc_stn_power_control,
+	.guard_time			= 1,
+};
+
+#else
+
+/* TFT */
 static struct fb_videomode at91_tft_vga_modes[] = {
 	{
 	        .name           = "TX09D50VM1CCA @ 60",
@@ -296,7 +358,7 @@
 	},
 };
 
-static struct fb_monspecs at91fb_default_monspecs = {
+static struct fb_monspecs at91fb_default_tft_monspecs = {
 	.manufacturer	= "HIT",
 	.monitor        = "TX09D50VM1CCA",
 
@@ -308,11 +370,11 @@
 	.vfmax		= 150,
 };
 
-#define AT91SAM9261_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
+#define AT91SAM9261_DEFAULT_TFT_LCDCON2	(ATMEL_LCDC_MEMOR_LITTLE \
 					| ATMEL_LCDC_DISTYPE_TFT    \
 					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
 
-static void at91_lcdc_power_control(int on)
+static void at91_lcdc_tft_power_control(int on)
 {
 	if (on)
 		at91_set_gpio_value(AT91_PIN_PA12, 0);	/* power up */
@@ -320,15 +382,15 @@
 		at91_set_gpio_value(AT91_PIN_PA12, 1);	/* power down */
 }
 
-/* Driver datas */
 static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
 	.default_bpp			= 16,
 	.default_dmacon			= ATMEL_LCDC_DMAEN,
-	.default_lcdcon2		= AT91SAM9261_DEFAULT_LCDCON2,
-	.default_monspecs		= &at91fb_default_monspecs,
-	.atmel_lcdfb_power_control	= at91_lcdc_power_control,
+	.default_lcdcon2		= AT91SAM9261_DEFAULT_TFT_LCDCON2,
+	.default_monspecs		= &at91fb_default_tft_monspecs,
+	.atmel_lcdfb_power_control	= at91_lcdc_tft_power_control,
 	.guard_time			= 1,
 };
+#endif
 
 #else
 static struct atmel_lcdfb_info __initdata ek_lcdc_data;
@@ -342,25 +404,25 @@
 static struct gpio_keys_button ek_buttons[] = {
 	{
 		.gpio		= AT91_PIN_PA27,
-		.keycode	= BTN_0,
+		.code		= BTN_0,
 		.desc		= "Button 0",
 		.active_low	= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA26,
-		.keycode	= BTN_1,
+		.code		= BTN_1,
 		.desc		= "Button 1",
 		.active_low	= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA25,
-		.keycode	= BTN_2,
+		.code		= BTN_2,
 		.desc		= "Button 2",
 		.active_low	= 1,
 	},
 	{
 		.gpio		= AT91_PIN_PA24,
-		.keycode	= BTN_3,
+		.code		= BTN_3,
 		.desc		= "Button 3",
 		.active_low	= 1,
 	}
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index ab9dcc0..f09347a 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -27,6 +27,8 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/fb.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -163,6 +165,7 @@
  * MACB Ethernet device
  */
 static struct at91_eth_data __initdata ek_macb_data = {
+	.phy_irq_pin	= AT91_PIN_PE31,
 	.is_rmii	= 1,
 };
 
@@ -264,6 +267,55 @@
 
 
 /*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+	{	/* BP1, "leftclic" */
+		.code		= BTN_LEFT,
+		.gpio		= AT91_PIN_PC5,
+		.active_low	= 1,
+		.desc		= "left_click",
+		.wakeup		= 1,
+	},
+	{	/* BP2, "rightclic" */
+		.code		= BTN_RIGHT,
+		.gpio		= AT91_PIN_PC4,
+		.active_low	= 1,
+		.desc		= "right_click",
+		.wakeup		= 1,
+	},
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+	.buttons	= ek_buttons,
+	.nbuttons	= ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &ek_button_data,
+	}
+};
+
+static void __init ek_add_device_buttons(void)
+{
+	at91_set_GPIO_periph(AT91_PIN_PC5, 0);	/* left button */
+	at91_set_deglitch(AT91_PIN_PC5, 1);
+	at91_set_GPIO_periph(AT91_PIN_PC4, 0);	/* right button */
+	at91_set_deglitch(AT91_PIN_PC4, 1);
+
+	platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
+
+/*
  * AC97
  */
 static struct atmel_ac97_data ek_ac97_data = {
@@ -271,6 +323,30 @@
 };
 
 
+/*
+ * LEDs ... these could all be PWM-driven, for variable brightness
+ */
+static struct gpio_led ek_leds[] = {
+	{	/* "left" led, green, userled1, pwm1 */
+		.name			= "ds1",
+		.gpio			= AT91_PIN_PB8,
+		.active_low		= 1,
+		.default_trigger	= "mmc0",
+	},
+	{	/* "right" led, green, userled2, pwm2 */
+		.name			= "ds2",
+		.gpio			= AT91_PIN_PC29,
+		.active_low		= 1,
+		.default_trigger	= "nand-disk",
+	},
+	{	/* "power" led, yellow, pwm0 */
+		.name			= "ds3",
+		.gpio			= AT91_PIN_PB7,
+		.default_trigger	= "heartbeat",
+	},
+};
+
+
 static void __init ek_board_init(void)
 {
 	/* Serial */
@@ -294,8 +370,12 @@
 	at91_add_device_i2c(NULL, 0);
 	/* LCD Controller */
 	at91_add_device_lcdc(&ek_lcdc_data);
+	/* Push Buttons */
+	ek_add_device_buttons();
 	/* AC97 */
 	at91_add_device_ac97(&ek_ac97_data);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 }
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 57c3b64..ec76eea 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -574,6 +574,8 @@
 	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) {
 		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
 		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
+	} else if (cpu_is_at91cap9()) {
+		uhpck.pmc_mask = AT91CAP9_PMC_UHP;
 	}
 	at91_sys_write(AT91_CKGR_PLLBR, 0);
 
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 77d4c0a3..b5daf7f 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -15,6 +15,7 @@
 extern void __init at91sam9263_initialize(unsigned long main_clock);
 extern void __init at91sam9rl_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
+extern void __init at91cap9_initialize(unsigned long main_clock);
 
  /* Interrupts */
 extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
@@ -23,6 +24,7 @@
 extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
+extern void __init at91cap9_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index aa2d365..6aeddd6 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -13,6 +13,8 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -414,6 +416,66 @@
 
 /*--------------------------------------------------------------------------*/
 
+#ifdef CONFIG_DEBUG_FS
+
+static int at91_gpio_show(struct seq_file *s, void *unused)
+{
+	int bank, j;
+
+	/* print heading */
+	seq_printf(s, "Pin\t");
+	for (bank = 0; bank < gpio_banks; bank++) {
+		seq_printf(s, "PIO%c\t", 'A' + bank);
+	};
+	seq_printf(s, "\n\n");
+
+	/* print pin status */
+	for (j = 0; j < 32; j++) {
+		seq_printf(s, "%i:\t", j);
+
+		for (bank = 0; bank < gpio_banks; bank++) {
+			unsigned	pin  = PIN_BASE + (32 * bank) + j;
+			void __iomem	*pio = pin_to_controller(pin);
+			unsigned	mask = pin_to_mask(pin);
+
+			if (__raw_readl(pio + PIO_PSR) & mask)
+				seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+			else
+				seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
+
+			seq_printf(s, "\t");
+		}
+
+		seq_printf(s, "\n");
+	}
+
+	return 0;
+}
+
+static int at91_gpio_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, at91_gpio_show, NULL);
+}
+
+static const struct file_operations at91_gpio_operations = {
+	.open		= at91_gpio_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init at91_gpio_debugfs_init(void)
+{
+	/* /sys/kernel/debug/at91_gpio */
+	(void) debugfs_create_file("at91_gpio", S_IFREG | S_IRUGO, NULL, NULL, &at91_gpio_operations);
+	return 0;
+}
+postcore_initcall(at91_gpio_debugfs_init);
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+
 /*
  * Called from the processor-specific init to enable GPIO interrupt support.
  */
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
index 0d51449..9cdcda5 100644
--- a/arch/arm/mach-at91/leds.c
+++ b/arch/arm/mach-at91/leds.c
@@ -14,11 +14,62 @@
 #include <linux/init.h>
 
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
 
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_NEW_LEDS)
+
+#include <linux/platform_device.h>
+
+/*
+ * New cross-platform LED support.
+ */
+
+static struct gpio_led_platform_data led_data;
+
+static struct platform_device at91_leds = {
+	.name			= "leds-gpio",
+	.id			= -1,
+	.dev.platform_data	= &led_data,
+};
+
+void __init at91_gpio_leds(struct gpio_led *leds, int nr)
+{
+	int i;
+
+	if (!nr)
+		return;
+
+	for (i = 0; i < nr; i++)
+		at91_set_gpio_output(leds[i].gpio, leds[i].active_low);
+
+	led_data.leds = leds;
+	led_data.num_leds = nr;
+	platform_device_register(&at91_leds);
+}
+
+#else
+void __init at91_gpio_leds(struct gpio_led *leds, int nr) {}
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+#if defined(CONFIG_LEDS)
+
+#include <asm/leds.h>
+
+/*
+ * Old ARM-specific LED framework; not fully functional when generic time is
+ * in use.
+ */
+
+static u8 at91_leds_cpu;
+static u8 at91_leds_timer;
+
 static inline void at91_led_on(unsigned int led)
 {
 	at91_set_gpio_value(led, 0);
@@ -93,3 +144,18 @@
 }
 
 __initcall(leds_init);
+
+
+void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+{
+	/* Enable GPIO to access the LEDs */
+	at91_set_gpio_output(cpu_led, 1);
+	at91_set_gpio_output(timer_led, 1);
+
+	at91_leds_cpu	= cpu_led;
+	at91_leds_timer	= timer_led;
+}
+
+#else
+void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+#endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 98cb614..4b120cc 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -80,6 +80,11 @@
 			pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
 			return 0;
 		}
+	} else if (cpu_is_at91cap9()) {
+		if ((scsr & AT91CAP9_PMC_UHP) != 0) {
+			pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n");
+			return 0;
+		}
 	}
 
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index f428af7..e5dc33f 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -50,9 +50,7 @@
 static irqreturn_t
 p720t_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
 	timer_tick();
-	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 986205e..2ac6367 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -298,8 +298,6 @@
 static irqreturn_t
 clps7500_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	timer_tick();
 
 	/* Why not using do_leds interface?? */
@@ -313,8 +311,6 @@
 		}
 	}
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 8c1b569..7710e14 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -178,8 +178,6 @@
 {
 	u32 count;
 
-	write_seqlock(&xtime_lock);
-
 	/* latch and read timer 1 */
 	__raw_writeb(0x40, PIT_CTRL);
 	count = __raw_readb(PIT_T1);
@@ -192,8 +190,6 @@
 
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 70b2c78..91f6a07 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -3,6 +3,7 @@
  * Core routines for Cirrus EP93xx chips.
  *
  * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
  *
  * Thanks go to Michael Burian and Ray Lehtiniemi for their key
  * role in the ep93xx linux community.
@@ -21,7 +22,6 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/bitops.h>
-#include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
@@ -99,8 +99,6 @@
 
 static int ep93xx_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	__raw_writel(1, EP93XX_TIMER1_CLEAR);
 	while ((signed long)
 		(__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
@@ -109,8 +107,6 @@
 		timer_tick();
 	}
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
@@ -157,38 +153,41 @@
 static unsigned char gpio_int_type1[3];
 static unsigned char gpio_int_type2[3];
 
-static void update_gpio_int_params(int abf)
+/* Port ordering is: A B F */
+static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c };
+static const u8 int_type2_register_offset[3]	= { 0x94, 0xb0, 0x50 };
+static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
+static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x5c };
+
+static void update_gpio_int_params(unsigned port)
 {
-	if (abf == 0) {
-		__raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE);
-		__raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2);
-		__raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1);
-		__raw_writeb(gpio_int_unmasked[0] & gpio_int_enabled[0], EP93XX_GPIO_A_INT_ENABLE);
-	} else if (abf == 1) {
-		__raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE);
-		__raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2);
-		__raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1);
-		__raw_writeb(gpio_int_unmasked[1] & gpio_int_enabled[1], EP93XX_GPIO_B_INT_ENABLE);
-	} else if (abf == 2) {
-		__raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE);
-		__raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2);
-		__raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1);
-		__raw_writeb(gpio_int_unmasked[2] & gpio_int_enabled[2], EP93XX_GPIO_F_INT_ENABLE);
-	} else {
-		BUG();
-	}
+	BUG_ON(port > 2);
+
+	__raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+
+	__raw_writeb(gpio_int_type2[port],
+		EP93XX_GPIO_REG(int_type2_register_offset[port]));
+
+	__raw_writeb(gpio_int_type1[port],
+		EP93XX_GPIO_REG(int_type1_register_offset[port]));
+
+	__raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
+		EP93XX_GPIO_REG(int_en_register_offset[port]));
 }
 
-
-static unsigned char data_register_offset[8] = {
-	0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40,
+/* Port ordering is: A B F D E C G H */
+static const u8 data_register_offset[8] = {
+	0x00, 0x04, 0x30, 0x0c, 0x20, 0x08, 0x38, 0x40,
 };
 
-static unsigned char data_direction_register_offset[8] = {
-	0x10, 0x14, 0x18, 0x1c, 0x24, 0x34, 0x3c, 0x44,
+static const u8 data_direction_register_offset[8] = {
+	0x10, 0x14, 0x34, 0x1c, 0x24, 0x18, 0x3c, 0x44,
 };
 
-void gpio_line_config(int line, int direction)
+#define GPIO_IN		0
+#define GPIO_OUT	1
+
+static void ep93xx_gpio_set_direction(unsigned line, int direction)
 {
 	unsigned int data_direction_register;
 	unsigned long flags;
@@ -199,14 +198,10 @@
 
 	local_irq_save(flags);
 	if (direction == GPIO_OUT) {
-		if (line >= 0 && line < 16) {
-			/* Port A/B.  */
+		if (line >= 0 && line <= EP93XX_GPIO_LINE_MAX_IRQ) {
+			/* Port A/B/F */
 			gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
 			update_gpio_int_params(line >> 3);
-		} else if (line >= 40 && line < 48) {
-			/* Port F.  */
-			gpio_int_unmasked[2] &= ~(1 << (line & 7));
-			update_gpio_int_params(2);
 		}
 
 		v = __raw_readb(data_direction_register);
@@ -219,39 +214,58 @@
 	}
 	local_irq_restore(flags);
 }
-EXPORT_SYMBOL(gpio_line_config);
 
-int gpio_line_get(int line)
+int gpio_direction_input(unsigned gpio)
+{
+	if (gpio > EP93XX_GPIO_LINE_MAX)
+		return -EINVAL;
+
+	ep93xx_gpio_set_direction(gpio, GPIO_IN);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+	if (gpio > EP93XX_GPIO_LINE_MAX)
+		return -EINVAL;
+
+	gpio_set_value(gpio, value);
+	ep93xx_gpio_set_direction(gpio, GPIO_OUT);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned gpio)
 {
 	unsigned int data_register;
 
-	data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]);
+	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);
 
-	return !!(__raw_readb(data_register) & (1 << (line & 7)));
+	return !!(__raw_readb(data_register) & (1 << (gpio & 7)));
 }
-EXPORT_SYMBOL(gpio_line_get);
+EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_line_set(int line, int value)
+void gpio_set_value(unsigned gpio, int value)
 {
 	unsigned int data_register;
 	unsigned long flags;
 	unsigned char v;
 
-	data_register = EP93XX_GPIO_REG(data_register_offset[line >> 3]);
+	data_register = EP93XX_GPIO_REG(data_register_offset[gpio >> 3]);
 
 	local_irq_save(flags);
-	if (value == EP93XX_GPIO_HIGH) {
-		v = __raw_readb(data_register);
-		v |= 1 << (line & 7);
-		__raw_writeb(v, data_register);
-	} else if (value == EP93XX_GPIO_LOW) {
-		v = __raw_readb(data_register);
-		v &= ~(1 << (line & 7));
-		__raw_writeb(v, data_register);
-	}
+	v = __raw_readb(data_register);
+	if (value)
+		v |= 1 << (gpio & 7);
+	else
+		v &= ~(1 << (gpio & 7));
+	__raw_writeb(v, data_register);
 	local_irq_restore(flags);
 }
-EXPORT_SYMBOL(gpio_line_set);
+EXPORT_SYMBOL(gpio_set_value);
 
 
 /*************************************************************************
@@ -265,47 +279,67 @@
 	status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
 	for (i = 0; i < 8; i++) {
 		if (status & (1 << i)) {
-			desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
-			desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc);
+			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
+			desc = irq_desc + gpio_irq;
+			desc_handle_irq(gpio_irq, desc);
 		}
 	}
 
 	status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
 	for (i = 0; i < 8; i++) {
 		if (status & (1 << i)) {
-			desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
-			desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc);
+			int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
+			desc = irq_desc + gpio_irq;
+			desc_handle_irq(gpio_irq, desc);
 		}
 	}
 }
 
 static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	int gpio_irq = IRQ_EP93XX_GPIO(16) + (((irq + 1) & 7) ^ 4);
+	/*
+	 * map discontiguous hw irq range to continous sw irq range:
+	 *
+	 *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
+	 */
+	int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
+	int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
 
 	desc_handle_irq(gpio_irq, irq_desc + gpio_irq);
 }
 
+static void ep93xx_gpio_irq_ack(unsigned int irq)
+{
+	int line = irq_to_gpio(irq);
+	int port = line >> 3;
+	int port_mask = 1 << (line & 7);
+
+	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) {
+		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
+		update_gpio_int_params(port);
+	}
+
+	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+}
+
 static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
 {
-	int line = irq - IRQ_EP93XX_GPIO(0);
+	int line = irq_to_gpio(irq);
 	int port = line >> 3;
+	int port_mask = 1 << (line & 7);
 
-	gpio_int_unmasked[port] &= ~(1 << (line & 7));
+	if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE)
+		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
+
+	gpio_int_unmasked[port] &= ~port_mask;
 	update_gpio_int_params(port);
 
-	if (port == 0) {
-		__raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
-	} else if (port == 1) {
-		__raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
-	} else if (port == 2) {
-		__raw_writel(1 << (line & 7), EP93XX_GPIO_F_INT_ACK);
-	}
+	__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
 }
 
 static void ep93xx_gpio_irq_mask(unsigned int irq)
 {
-	int line = irq - IRQ_EP93XX_GPIO(0);
+	int line = irq_to_gpio(irq);
 	int port = line >> 3;
 
 	gpio_int_unmasked[port] &= ~(1 << (line & 7));
@@ -314,7 +348,7 @@
 
 static void ep93xx_gpio_irq_unmask(unsigned int irq)
 {
-	int line = irq - IRQ_EP93XX_GPIO(0);
+	int line = irq_to_gpio(irq);
 	int port = line >> 3;
 
 	gpio_int_unmasked[port] |= 1 << (line & 7);
@@ -329,38 +363,54 @@
  */
 static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
 {
-	int port;
-	int line;
+	struct irq_desc *desc = irq_desc + irq;
+	const int gpio = irq_to_gpio(irq);
+	const int port = gpio >> 3;
+	const int port_mask = 1 << (gpio & 7);
 
-	line = irq - IRQ_EP93XX_GPIO(0);
-	if (line >= 0 && line < 16) {
-		gpio_line_config(line, GPIO_IN);
-	} else {
-		gpio_line_config(EP93XX_GPIO_LINE_F(line-16), GPIO_IN);
+	ep93xx_gpio_set_direction(gpio, GPIO_IN);
+
+	switch (type) {
+	case IRQT_RISING:
+		gpio_int_type1[port] |= port_mask;
+		gpio_int_type2[port] |= port_mask;
+		desc->handle_irq = handle_edge_irq;
+		break;
+	case IRQT_FALLING:
+		gpio_int_type1[port] |= port_mask;
+		gpio_int_type2[port] &= ~port_mask;
+		desc->handle_irq = handle_edge_irq;
+		break;
+	case IRQT_HIGH:
+		gpio_int_type1[port] &= ~port_mask;
+		gpio_int_type2[port] |= port_mask;
+		desc->handle_irq = handle_level_irq;
+		break;
+	case IRQT_LOW:
+		gpio_int_type1[port] &= ~port_mask;
+		gpio_int_type2[port] &= ~port_mask;
+		desc->handle_irq = handle_level_irq;
+		break;
+	case IRQT_BOTHEDGE:
+		gpio_int_type1[port] |= port_mask;
+		/* set initial polarity based on current input level */
+		if (gpio_get_value(gpio))
+			gpio_int_type2[port] &= ~port_mask; /* falling */
+		else
+			gpio_int_type2[port] |= port_mask; /* rising */
+		desc->handle_irq = handle_edge_irq;
+		break;
+	default:
+		pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
+		       type, gpio);
+		return -EINVAL;
 	}
 
-	port = line >> 3;
-	line &= 7;
+	gpio_int_enabled[port] |= port_mask;
 
-	if (type & IRQT_RISING) {
-		gpio_int_enabled[port] |= 1 << line;
-		gpio_int_type1[port] |= 1 << line;
-		gpio_int_type2[port] |= 1 << line;
-	} else if (type & IRQT_FALLING) {
-		gpio_int_enabled[port] |= 1 << line;
-		gpio_int_type1[port] |= 1 << line;
-		gpio_int_type2[port] &= ~(1 << line);
-	} else if (type & IRQT_HIGH) {
-		gpio_int_enabled[port] |= 1 << line;
-		gpio_int_type1[port] &= ~(1 << line);
-		gpio_int_type2[port] |= 1 << line;
-	} else if (type & IRQT_LOW) {
-		gpio_int_enabled[port] |= 1 << line;
-		gpio_int_type1[port] &= ~(1 << line);
-		gpio_int_type2[port] &= ~(1 << line);
-	} else {
-		gpio_int_enabled[port] &= ~(1 << line);
-	}
+	desc->status &= ~IRQ_TYPE_SENSE_MASK;
+	desc->status |= type & IRQ_TYPE_SENSE_MASK;
+
 	update_gpio_int_params(port);
 
 	return 0;
@@ -368,7 +418,8 @@
 
 static struct irq_chip ep93xx_gpio_irq_chip = {
 	.name		= "GPIO",
-	.ack		= ep93xx_gpio_irq_mask_ack,
+	.ack		= ep93xx_gpio_irq_ack,
+	.mask_ack	= ep93xx_gpio_irq_mask_ack,
 	.mask		= ep93xx_gpio_irq_mask,
 	.unmask		= ep93xx_gpio_irq_unmask,
 	.set_type	= ep93xx_gpio_irq_type,
@@ -377,15 +428,16 @@
 
 void __init ep93xx_init_irq(void)
 {
-	int irq;
+	int gpio_irq;
 
 	vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
 	vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
 
-	for (irq = IRQ_EP93XX_GPIO(0); irq <= IRQ_EP93XX_GPIO(23); irq++) {
-		set_irq_chip(irq, &ep93xx_gpio_irq_chip);
-		set_irq_handler(irq, handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
+	for (gpio_irq = gpio_to_irq(0);
+	     gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
+		set_irq_chip(gpio_irq, &ep93xx_gpio_irq_chip);
+		set_irq_handler(gpio_irq, handle_level_irq);
+		set_irq_flags(gpio_irq, IRQF_VALID);
 	}
 
 	set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index 3a63941..b2a2118 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -30,14 +30,10 @@
 static irqreturn_t
 timer1_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	*CSR_TIMER1_CLR = 0;
 
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index d08d641..a764e01 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -64,9 +64,7 @@
 static irqreturn_t
 isa_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
 	timer_tick();
-	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index 9107b8e..c2a431f 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -29,13 +29,9 @@
 static irqreturn_t
 h7201_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 0a1a25f..c627fa1 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -113,9 +113,7 @@
 	mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
 
 	if ( mask & TSTAT_T0INT ) {
-		write_seqlock(&xtime_lock);
 		timer_tick();
-		write_sequnlock(&xtime_lock);
 		if( mask == TSTAT_T0INT )
 			return;
 	}
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index e9c82de..7fbbc17 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -250,8 +250,6 @@
 static irqreturn_t
 integrator_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	/*
 	 * clear the interrupt
 	 */
@@ -259,8 +257,6 @@
 
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index d4d8134..d55fa4e 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -440,7 +440,7 @@
 	return 1;
 }
 
-static irqreturn_t v3_irq(int irq, void *devid)
+static irqreturn_t v3_irq(int dummy, void *devid)
 {
 #ifdef CONFIG_DEBUG_LL
 	struct pt_regs *regs = get_irq_regs();
@@ -448,8 +448,10 @@
 	unsigned long instr = *(unsigned long *)pc;
 	char buf[128];
 
-	sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", irq,
-		pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
+	sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x "
+		"ISTAT=%02x\n", IRQ_AP_V3INT, pc, instr,
+		__raw_readl(SC_LBFADDR),
+		__raw_readl(SC_LBFCODE) & 255,
 		v3_readb(V3_LB_ISTAT));
 	printascii(buf);
 #endif
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index cb6ad21..81cdc82 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -206,8 +206,6 @@
 
 static int ixp2000_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	/* clear timer 1 */
 	ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
 
@@ -217,8 +215,6 @@
 		next_jiffy_time -= ticks_per_jiffy;
 	}
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index 16356ff..5fea5a1 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -22,7 +22,6 @@
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/bitops.h>
-#include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
index 7a85ced..d3a779a 100644
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ b/arch/arm/mach-ixp23xx/espresso.c
@@ -19,7 +19,6 @@
 #include <linux/tty.h>
 #include <linux/bitops.h>
 #include <linux/ioport.h>
-#include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
@@ -40,7 +39,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/pci.h>
 
 static int __init espresso_pci_init(void)
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index c41a6b5..5c5d4d6 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -24,7 +24,6 @@
 #include <linux/tty.h>
 #include <linux/bitops.h>
 #include <linux/ioport.h>
-#include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
@@ -44,7 +43,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/pci.h>
 
 /*
diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
index e3564496..f0f70ba 100644
--- a/arch/arm/mach-ixp23xx/roadrunner.c
+++ b/arch/arm/mach-ixp23xx/roadrunner.c
@@ -23,7 +23,6 @@
 #include <linux/tty.h>
 #include <linux/bitops.h>
 #include <linux/ioport.h>
-#include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
@@ -44,7 +43,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/pci.h>
 
 /*
diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c
index d59b8dc..e38f45f 100644
--- a/arch/arm/mach-ixp4xx/avila-setup.c
+++ b/arch/arm/mach-ixp4xx/avila-setup.c
@@ -18,6 +18,7 @@
 #include <linux/tty.h>
 #include <linux/serial_8250.h>
 #include <linux/slab.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -47,18 +48,17 @@
 	.resource	= &avila_flash_resource,
 };
 
-static struct ixp4xx_i2c_pins avila_i2c_gpio_pins = {
+static struct i2c_gpio_platform_data avila_i2c_gpio_data = {
 	.sda_pin	= AVILA_SDA_PIN,
 	.scl_pin	= AVILA_SCL_PIN,
 };
 
-static struct platform_device avila_i2c_controller = {
-	.name		= "IXP4XX-I2C",
+static struct platform_device avila_i2c_gpio = {
+	.name		= "i2c-gpio",
 	.id		= 0,
-	.dev		= {
-		.platform_data = &avila_i2c_gpio_pins,
+	.dev	 = {
+		.platform_data	= &avila_i2c_gpio_data,
 	},
-	.num_resources	= 0
 };
 
 static struct resource avila_uart_resources[] = {
@@ -133,7 +133,7 @@
 };
 
 static struct platform_device *avila_devices[] __initdata = {
-	&avila_i2c_controller,
+	&avila_i2c_gpio,
 	&avila_flash,
 	&avila_uart
 };
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index 1e75e10..c473d40 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -37,15 +38,17 @@
 	.resource		= &dsmg600_flash_resource,
 };
 
-static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = {
+static struct i2c_gpio_platform_data dsmg600_i2c_gpio_data = {
 	.sda_pin		= DSMG600_SDA_PIN,
 	.scl_pin		= DSMG600_SCL_PIN,
 };
 
-static struct platform_device dsmg600_i2c_controller = {
-	.name			= "IXP4XX-I2C",
+static struct platform_device dsmg600_i2c_gpio = {
+	.name			= "i2c-gpio",
 	.id			= 0,
-	.dev.platform_data	= &dsmg600_i2c_gpio_pins,
+	.dev	 = {
+		.platform_data	= &dsmg600_i2c_gpio_data,
+	},
 };
 
 #ifdef CONFIG_LEDS_CLASS
@@ -116,7 +119,7 @@
 };
 
 static struct platform_device *dsmg600_devices[] __initdata = {
-	&dsmg600_i2c_controller,
+	&dsmg600_i2c_gpio,
 	&dsmg600_flash,
 };
 
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index d5008d8..e89070d 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -15,6 +15,7 @@
 #include <linux/tty.h>
 #include <linux/serial_8250.h>
 #include <linux/slab.h>
+#include <linux/i2c-gpio.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -120,18 +121,17 @@
 };
 #endif	/* CONFIG_MTD_NAND_PLATFORM */
 
-static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = {
+static struct i2c_gpio_platform_data ixdp425_i2c_gpio_data = {
 	.sda_pin	= IXDP425_SDA_PIN,
 	.scl_pin	= IXDP425_SCL_PIN,
 };
 
-static struct platform_device ixdp425_i2c_controller = {
-	.name		= "IXP4XX-I2C",
+static struct platform_device ixdp425_i2c_gpio = {
+	.name		= "i2c-gpio",
 	.id		= 0,
-	.dev		= {
-		.platform_data = &ixdp425_i2c_gpio_pins,
+	.dev	 = {
+		.platform_data	= &ixdp425_i2c_gpio_data,
 	},
-	.num_resources	= 0
 };
 
 static struct resource ixdp425_uart_resources[] = {
@@ -178,7 +178,7 @@
 };
 
 static struct platform_device *ixdp425_devices[] __initdata = {
-	&ixdp425_i2c_controller,
+	&ixdp425_i2c_gpio,
 	&ixdp425_flash,
 #if defined(CONFIG_MTD_NAND_PLATFORM) || \
     defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 78a1741..54d884f 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -16,6 +16,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/leds.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -68,16 +69,17 @@
 };
 #endif
 
-static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
+static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
 	.sda_pin		= NAS100D_SDA_PIN,
 	.scl_pin		= NAS100D_SCL_PIN,
 };
 
-static struct platform_device nas100d_i2c_controller = {
-	.name			= "IXP4XX-I2C",
+static struct platform_device nas100d_i2c_gpio = {
+	.name			= "i2c-gpio",
 	.id			= 0,
-	.dev.platform_data	= &nas100d_i2c_gpio_pins,
-	.num_resources		= 0,
+	.dev	 = {
+		.platform_data	= &nas100d_i2c_gpio_data,
+	},
 };
 
 static struct resource nas100d_uart_resources[] = {
@@ -124,7 +126,7 @@
 };
 
 static struct platform_device *nas100d_devices[] __initdata = {
-	&nas100d_i2c_controller,
+	&nas100d_i2c_gpio,
 	&nas100d_flash,
 #ifdef CONFIG_LEDS_IXP4XX
 	&nas100d_leds,
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
index acd71e9..6f10dc20 100644
--- a/arch/arm/mach-ixp4xx/nslu2-power.c
+++ b/arch/arm/mach-ixp4xx/nslu2-power.c
@@ -21,7 +21,6 @@
 #include <linux/reboot.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/reboot.h>
 
 #include <asm/mach-types.h>
 
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index 9bf8ccb..77277d2 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -18,6 +18,7 @@
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/leds.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -41,7 +42,7 @@
 	.resource		= &nslu2_flash_resource,
 };
 
-static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = {
+static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = {
 	.sda_pin		= NSLU2_SDA_PIN,
 	.scl_pin		= NSLU2_SCL_PIN,
 };
@@ -82,11 +83,12 @@
 };
 #endif
 
-static struct platform_device nslu2_i2c_controller = {
-	.name			= "IXP4XX-I2C",
+static struct platform_device nslu2_i2c_gpio = {
+	.name			= "i2c-gpio",
 	.id			= 0,
-	.dev.platform_data	= &nslu2_i2c_gpio_pins,
-	.num_resources		= 0,
+	.dev	 = {
+		.platform_data	= &nslu2_i2c_gpio_data,
+	},
 };
 
 static struct platform_device nslu2_beeper = {
@@ -139,7 +141,7 @@
 };
 
 static struct platform_device *nslu2_devices[] __initdata = {
-	&nslu2_i2c_controller,
+	&nslu2_i2c_gpio,
 	&nslu2_flash,
 	&nslu2_beeper,
 #ifdef CONFIG_LEDS_IXP4XX
diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
index 2a07a28..730a3af 100644
--- a/arch/arm/mach-ks8695/Makefile
+++ b/arch/arm/mach-ks8695/Makefile
@@ -9,7 +9,7 @@
 obj-				:=
 
 # PCI support is optional
-#obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_PCI)		+= pci.o
 
 # Board-specific support
 obj-$(CONFIG_MACH_KS8695)	+= board-micrel.o
diff --git a/arch/arm/mach-ks8695/board-micrel.c b/arch/arm/mach-ks8695/board-micrel.c
index 2feeef8..05ac2bd 100644
--- a/arch/arm/mach-ks8695/board-micrel.c
+++ b/arch/arm/mach-ks8695/board-micrel.c
@@ -40,7 +40,7 @@
 	printk(KERN_INFO "Micrel KS8695 Development Board initializing\n");
 
 #ifdef CONFIG_PCI
-//	ks8695_init_pci(&micrel_pci);
+	ks8695_init_pci(&micrel_pci);
 #endif
 
 	/* Add devices */
diff --git a/arch/arm/mach-ks8695/gpio.c b/arch/arm/mach-ks8695/gpio.c
index b1aa3cb..5e46191 100644
--- a/arch/arm/mach-ks8695/gpio.c
+++ b/arch/arm/mach-ks8695/gpio.c
@@ -20,6 +20,8 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/module.h>
 
 #include <asm/io.h>
@@ -216,3 +218,84 @@
 	return (irq - KS8695_IRQ_EXTERN0);
 }
 EXPORT_SYMBOL(irq_to_gpio);
+
+
+/* .... Debug interface ..................................................... */
+
+#ifdef CONFIG_DEBUG_FS
+
+static int ks8695_gpio_show(struct seq_file *s, void *unused)
+{
+	unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
+	unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
+	unsigned long mode, ctrl, data;
+	int i;
+
+	mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
+	ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
+	data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
+
+	seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
+
+	for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
+		seq_printf(s, "%i:\t", i);
+
+		seq_printf(s, "%s\t", (mode & IOPM_(i)) ? "Output" : "Input");
+
+		if (i <= KS8695_GPIO_3) {
+			if (ctrl & enable[i]) {
+				seq_printf(s, "EXT%i ", i);
+
+				switch ((ctrl & intmask[i]) >> (4 * i)) {
+					case IOPC_TM_LOW:
+						seq_printf(s, "(Low)");		break;
+					case IOPC_TM_HIGH:
+						seq_printf(s, "(High)");	break;
+					case IOPC_TM_RISING:
+						seq_printf(s, "(Rising)");	break;
+					case IOPC_TM_FALLING:
+						seq_printf(s, "(Falling)");	break;
+					case IOPC_TM_EDGE:
+						seq_printf(s, "(Edges)");	break;
+				}
+			}
+			else
+				seq_printf(s, "GPIO\t");
+		}
+		else if (i <= KS8695_GPIO_5) {
+			if (ctrl & enable[i])
+				seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
+			else
+				seq_printf(s, "GPIO\t");
+		}
+		else
+			seq_printf(s, "GPIO\t");
+
+		seq_printf(s, "\t");
+
+		seq_printf(s, "%i\n", (data & IOPD_(i)) ? 1 : 0);
+	}
+	return 0;
+}
+
+static int ks8695_gpio_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ks8695_gpio_show, NULL);
+}
+
+static const struct file_operations ks8695_gpio_operations = {
+	.open		= ks8695_gpio_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init ks8695_gpio_debugfs_init(void)
+{
+	/* /sys/kernel/debug/ks8695_gpio */
+	(void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations);
+	return 0;
+}
+postcore_initcall(ks8695_gpio_debugfs_init);
+
+#endif
diff --git a/arch/arm/mach-ks8695/pci.c b/arch/arm/mach-ks8695/pci.c
new file mode 100644
index 0000000..3f4e033
--- /dev/null
+++ b/arch/arm/mach-ks8695/pci.c
@@ -0,0 +1,326 @@
+/*
+ * arch/arm/mach-ks8695/pci.c
+ *
+ *  Copyright (C) 2003, Micrel Semiconductors
+ *  Copyright (C) 2006, Greg Ungerer <gerg@snapgear.com>
+ *  Copyright (C) 2006, Ben Dooks
+ *  Copyright (C) 2007, Andrew Victor
+ *
+ * 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/pci.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/signal.h>
+#include <asm/mach/pci.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/devices.h>
+#include <asm/arch/regs-pci.h>
+
+
+static int pci_dbg;
+static int pci_cfg_dbg;
+
+
+static void ks8695_pci_setupconfig(unsigned int bus_nr, unsigned int devfn, unsigned int where)
+{
+	unsigned long pbca;
+
+	pbca = PBCA_ENABLE | (where & ~3);
+	pbca |= PCI_SLOT(devfn) << 11 ;
+	pbca |= PCI_FUNC(devfn) << 8;
+	pbca |= bus_nr << 16;
+
+	if (bus_nr == 0) {
+		/* use Type-0 transaction */
+		__raw_writel(pbca, KS8695_PCI_VA + KS8695_PBCA);
+	} else {
+		/* use Type-1 transaction */
+		__raw_writel(pbca | PBCA_TYPE1, KS8695_PCI_VA + KS8695_PBCA);
+	}
+}
+
+
+/*
+ * The KS8695 datasheet prohibits anything other than 32bit accesses
+ * to the IO registers, so all our configuration must be done with
+ * 32bit operations, and the correct bit masking and shifting.
+ */
+
+static int ks8695_pci_readconfig(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 *value)
+{
+	ks8695_pci_setupconfig(bus->number, devfn, where);
+
+	*value = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
+
+	switch (size) {
+		case 4:
+			break;
+		case 2:
+			*value = *value >> ((where & 2) * 8);
+			*value &= 0xffff;
+			break;
+		case 1:
+			*value = *value >> ((where & 3) * 8);
+			*value &= 0xff;
+			break;
+	}
+
+	if (pci_cfg_dbg) {
+		printk("read: %d,%08x,%02x,%d: %08x (%08x)\n",
+			bus->number, devfn, where, size, *value,
+			__raw_readl(KS8695_PCI_VA +  KS8695_PBCD));
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int ks8695_pci_writeconfig(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 value)
+{
+	unsigned long tmp;
+
+	if (pci_cfg_dbg) {
+		printk("write: %d,%08x,%02x,%d: %08x\n",
+			bus->number, devfn, where, size, value);
+	}
+
+	ks8695_pci_setupconfig(bus->number, devfn, where);
+
+	switch (size) {
+		case 4:
+			__raw_writel(value, KS8695_PCI_VA +  KS8695_PBCD);
+			break;
+		case 2:
+			tmp = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
+			tmp &= ~(0xffff << ((where & 2) * 8));
+			tmp |= value << ((where & 2) * 8);
+
+			__raw_writel(tmp, KS8695_PCI_VA +  KS8695_PBCD);
+			break;
+		case 1:
+			tmp = __raw_readl(KS8695_PCI_VA +  KS8695_PBCD);
+			tmp &= ~(0xff << ((where & 3) * 8));
+			tmp |= value << ((where & 3) * 8);
+
+			__raw_writel(tmp, KS8695_PCI_VA +  KS8695_PBCD);
+			break;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static void ks8695_local_writeconfig(int where, u32 value)
+{
+	ks8695_pci_setupconfig(0, 0, where);
+	__raw_writel(value, KS8695_PCI_VA + KS8695_PBCD);
+}
+
+static struct pci_ops ks8695_pci_ops = {
+	.read	= ks8695_pci_readconfig,
+	.write	= ks8695_pci_writeconfig,
+};
+
+static struct pci_bus *ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
+}
+
+static struct resource pci_mem = {
+	.name	= "PCI Memory space",
+	.start	= KS8695_PCIMEM_PA,
+	.end	= KS8695_PCIMEM_PA + (KS8695_PCIMEM_SIZE - 1),
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource pci_io = {
+	.name	= "PCI IO space",
+	.start	= KS8695_PCIIO_PA,
+	.end	= KS8695_PCIIO_PA + (KS8695_PCIIO_SIZE - 1),
+	.flags	= IORESOURCE_IO,
+};
+
+static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys)
+{
+	if (nr > 0)
+		return 0;
+
+	request_resource(&iomem_resource, &pci_mem);
+	request_resource(&ioport_resource, &pci_io);
+
+	sys->resource[0] = &pci_io;
+	sys->resource[1] = &pci_mem;
+	sys->resource[2] = NULL;
+
+	/* Assign and enable processor bridge */
+	ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
+
+	/* Enable bus-master & Memory Space access */
+	ks8695_local_writeconfig(PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+
+	/* Set cache-line size & latency. */
+	ks8695_local_writeconfig(PCI_CACHE_LINE_SIZE, (32 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
+
+	/* Reserve PCI memory space for PCI-AHB resources */
+	if (!request_mem_region(KS8695_PCIMEM_PA, SZ_64M, "PCI-AHB Bridge")) {
+		printk(KERN_ERR "Cannot allocate PCI-AHB Bridge memory.\n");
+		return -EBUSY;
+	}
+
+	return 1;
+}
+
+static inline unsigned int size_mask(unsigned long size)
+{
+	return (~size) + 1;
+}
+
+static int ks8695_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+	unsigned long pc = instruction_pointer(regs);
+	unsigned long instr = *(unsigned long *)pc;
+	unsigned long cmdstat;
+
+	cmdstat = __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS);
+
+	printk(KERN_ERR "PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx [%s%s%s%s%s]\n",
+		addr, fsr, regs->ARM_pc, regs->ARM_lr,
+		cmdstat & (PCI_STATUS_SIG_TARGET_ABORT << 16) ? "GenTarget" : " ",
+		cmdstat & (PCI_STATUS_REC_TARGET_ABORT << 16) ? "RecvTarget" : " ",
+		cmdstat & (PCI_STATUS_REC_MASTER_ABORT << 16) ? "MasterAbort" : " ",
+		cmdstat & (PCI_STATUS_SIG_SYSTEM_ERROR << 16) ? "SysError" : " ",
+		cmdstat & (PCI_STATUS_DETECTED_PARITY << 16)  ? "Parity" : " "
+	);
+
+	__raw_writel(cmdstat, KS8695_PCI_VA + KS8695_CRCFCS);
+
+	/*
+	 * If the instruction being executed was a read,
+	 * make it look like it read all-ones.
+	 */
+	if ((instr & 0x0c100000) == 0x04100000) {
+		int reg = (instr >> 12) & 15;
+		unsigned long val;
+
+		if (instr & 0x00400000)
+			val = 255;
+		else
+			val = -1;
+
+		regs->uregs[reg] = val;
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void __init ks8695_pci_preinit(void)
+{
+	/* stage 1 initialization, subid, subdevice = 0x0001 */
+	__raw_writel(0x00010001, KS8695_PCI_VA + KS8695_CRCSID);
+
+	/* stage 2 initialization */
+	/* prefetch limits with 16 words, retry enable */
+	__raw_writel(0x40000000, KS8695_PCI_VA + KS8695_PBCS);
+
+	/* configure memory mapping */
+	__raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBA);
+	__raw_writel(size_mask(KS8695_PCIMEM_SIZE), KS8695_PCI_VA + KS8695_PMBAM);
+	__raw_writel(KS8695_PCIMEM_PA, KS8695_PCI_VA + KS8695_PMBAT);
+	__raw_writel(0, KS8695_PCI_VA + KS8695_PMBAC);
+
+	/* configure IO mapping */
+	__raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBA);
+	__raw_writel(size_mask(KS8695_PCIIO_SIZE), KS8695_PCI_VA + KS8695_PIOBAM);
+	__raw_writel(KS8695_PCIIO_PA, KS8695_PCI_VA + KS8695_PIOBAT);
+	__raw_writel(0, KS8695_PCI_VA + KS8695_PIOBAC);
+
+	/* hook in fault handlers */
+	hook_fault_code(8, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
+	hook_fault_code(10, ks8695_pci_fault, SIGBUS, "external abort on non-linefetch");
+}
+
+static void ks8695_show_pciregs(void)
+{
+	if (!pci_dbg)
+		return;
+
+	printk(KERN_INFO "PCI: CRCFID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFID));
+	printk(KERN_INFO "PCI: CRCFCS = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFCS));
+	printk(KERN_INFO "PCI: CRCFRV = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFRV));
+	printk(KERN_INFO "PCI: CRCFLT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFLT));
+	printk(KERN_INFO "PCI: CRCBMA = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCBMA));
+	printk(KERN_INFO "PCI: CRCSID = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCSID));
+	printk(KERN_INFO "PCI: CRCFIT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_CRCFIT));
+
+	printk(KERN_INFO "PCI: PBM    = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBM));
+	printk(KERN_INFO "PCI: PBCS   = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PBCS));
+
+	printk(KERN_INFO "PCI: PMBA   = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBA));
+	printk(KERN_INFO "PCI: PMBAC  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAC));
+	printk(KERN_INFO "PCI: PMBAM  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAM));
+	printk(KERN_INFO "PCI: PMBAT  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PMBAT));
+
+	printk(KERN_INFO "PCI: PIOBA  = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBA));
+	printk(KERN_INFO "PCI: PIOBAC = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAC));
+	printk(KERN_INFO "PCI: PIOBAM = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAM));
+	printk(KERN_INFO "PCI: PIOBAT = %08x\n", __raw_readl(KS8695_PCI_VA + KS8695_PIOBAT));
+}
+
+
+static struct hw_pci ks8695_pci __initdata = {
+	.nr_controllers	= 1,
+	.preinit	= ks8695_pci_preinit,
+	.setup		= ks8695_pci_setup,
+	.scan		= ks8695_pci_scan_bus,
+	.postinit	= NULL,
+	.swizzle	= pci_std_swizzle,
+	.map_irq	= NULL,
+};
+
+void __init ks8695_init_pci(struct ks8695_pci_cfg *cfg)
+{
+	if (__raw_readl(KS8695_PCI_VA + KS8695_CRCFRV) & CFRV_GUEST) {
+		printk("PCI: KS8695 in guest mode, not initialising\n");
+		return;
+	}
+
+	printk(KERN_INFO "PCI: Initialising\n");
+	ks8695_show_pciregs();
+
+	/* set Mode */
+	__raw_writel(cfg->mode << 29, KS8695_PCI_VA + KS8695_PBM);
+
+	ks8695_pci.map_irq = cfg->map_irq;	/* board-specific map_irq method */
+
+	pci_common_init(&ks8695_pci);
+}
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index d2c86e4..02f766b 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -70,10 +70,7 @@
  */
 static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
 	timer_tick();
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index c25316d..e50e60b 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -41,13 +41,9 @@
 static irqreturn_t
 lh7a40x_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	TIMER_EOI = 0;
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
new file mode 100644
index 0000000..3553bab
--- /dev/null
+++ b/arch/arm/mach-msm/Kconfig
@@ -0,0 +1,18 @@
+if ARCH_MSM7X00A
+
+comment "MSM7X00A Board Type"
+	depends on ARCH_MSM7X00A
+
+config MACH_HALIBUT
+	depends on ARCH_MSM7X00A
+	default y
+	bool "Halibut Board (QCT SURF7200A)"
+	help
+	  Support for the Qualcomm SURF7200A eval board.
+
+config MSM7X00A_IDLE
+	depends on ARCH_MSM7X00A
+	default y
+	bool "Idle Support for MSM7X00A"
+
+endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
new file mode 100644
index 0000000..d12f236
--- /dev/null
+++ b/arch/arm/mach-msm/Makefile
@@ -0,0 +1,7 @@
+obj-y += io.o idle.o irq.o timer.o dma.o
+
+# Common code for board init
+obj-y += common.o
+
+obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
+
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
new file mode 100644
index 0000000..24dfbf8
--- /dev/null
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -0,0 +1,3 @@
+  zreladdr-y		:= 0x10008000
+params_phys-y		:= 0x10000100
+initrd_phys-y		:= 0x10800000
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
new file mode 100644
index 0000000..86dfb2b
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -0,0 +1,114 @@
+/* linux/arch/arm/mach-msm/board-halibut.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/msm_iomap.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= 0x9C004300,
+		.end	= 0x9C004400,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= MSM_GPIO_TO_INT(49),
+		.end	= MSM_GPIO_TO_INT(49),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static void mddi0_panel_power(int on)
+{
+}
+
+static struct msm_mddi_platform_data msm_mddi0_pdata = {
+	.panel_power	= mddi0_panel_power,
+	.has_vsync_irq	= 0,
+};
+
+static struct platform_device msm_mddi0_device = {
+	.name	= "msm_mddi",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &msm_mddi0_pdata
+	},
+};
+
+static struct platform_device msm_serial0_device = {
+	.name	= "msm_serial",
+	.id	= 0,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&msm_serial0_device,
+	&msm_mddi0_device,
+	&smc91x_device,
+};
+
+extern struct sys_timer msm_timer;
+
+static void __init halibut_init_irq(void)
+{
+	msm_init_irq();
+}
+
+static void __init halibut_init(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+	msm_add_devices();
+}
+
+static void __init halibut_map_io(void)
+{
+	msm_map_common_io();
+}
+
+MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
+
+/* UART for LL DEBUG */
+	.phys_io	= MSM_UART1_PHYS,
+	.io_pg_offst	= ((MSM_UART1_BASE) >> 18) & 0xfffc,
+
+	.boot_params	= 0x10000100,
+	.map_io		= halibut_map_io,
+	.init_irq	= halibut_init_irq,
+	.init_machine	= halibut_init,
+	.timer		= &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/common.c b/arch/arm/mach-msm/common.c
new file mode 100644
index 0000000..3f5d336
--- /dev/null
+++ b/arch/arm/mach-msm/common.c
@@ -0,0 +1,116 @@
+/* linux/arch/arm/mach-msm/common.c
+ *
+ * Common setup code for MSM7K Boards
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/flash.h>
+#include <asm/io.h>
+
+#include <asm/setup.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/arch/msm_iomap.h>
+
+#include <asm/arch/board.h>
+
+struct flash_platform_data msm_nand_data = {
+	.parts		= 0,
+	.nr_parts	= 0,
+};
+
+static struct resource msm_nand_resources[] = {
+	[0] = {
+		.start	= 7,
+		.end	= 7,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device msm_nand_device = {
+	.name		= "msm_nand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(msm_nand_resources),
+	.resource	= msm_nand_resources,
+	.dev		= {
+		.platform_data	= &msm_nand_data,
+	},
+};
+
+static struct platform_device msm_smd_device = {
+	.name	= "msm_smd",
+	.id	= -1,
+};
+
+static struct resource msm_i2c_resources[] = {
+	{
+		.start	= MSM_I2C_BASE,
+		.end	= MSM_I2C_BASE + MSM_I2C_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_PWB_I2C,
+		.end	= INT_PWB_I2C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_i2c_device = {
+	.name		= "msm_i2c",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(msm_i2c_resources),
+	.resource	= msm_i2c_resources,
+};
+
+static struct resource usb_resources[] = {
+	{
+		.start	= MSM_HSUSB_PHYS,
+		.end	= MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HS,
+		.end	= INT_USB_HS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_hsusb_device = {
+	.name		= "msm_hsusb",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(usb_resources),
+	.resource	= usb_resources,
+	.dev		= {
+		.coherent_dma_mask	= 0xffffffff,
+	},
+};
+
+static struct platform_device *devices[] __initdata = {
+	&msm_nand_device,
+	&msm_smd_device,
+	&msm_i2c_device,
+	&msm_hsusb_device,
+};
+
+void __init msm_add_devices(void)
+{
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
new file mode 100644
index 0000000..8b0f339
--- /dev/null
+++ b/arch/arm/mach-msm/dma.c
@@ -0,0 +1,214 @@
+/* linux/arch/arm/mach-msm/dma.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <asm/arch/dma.h>
+
+#define MSM_DMOV_CHANNEL_COUNT 16
+
+enum {
+	MSM_DMOV_PRINT_ERRORS = 1,
+	MSM_DMOV_PRINT_IO = 2,
+	MSM_DMOV_PRINT_FLOW = 4
+};
+
+static DEFINE_SPINLOCK(msm_dmov_lock);
+static struct msm_dmov_cmd active_command;
+static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
+static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
+unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS;
+
+#define MSM_DMOV_DPRINTF(mask, format, args...) \
+	do { \
+		if ((mask) & msm_dmov_print_mask) \
+			printk(KERN_ERR format, args); \
+	} while (0)
+#define PRINT_ERROR(format, args...) \
+	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_ERRORS, format, args);
+#define PRINT_IO(format, args...) \
+	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_IO, format, args);
+#define PRINT_FLOW(format, args...) \
+	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
+
+void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
+{
+	unsigned long irq_flags;
+	unsigned int status;
+
+	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+	status = readl(DMOV_STATUS(id));
+	if (list_empty(&ready_commands[id]) &&
+		(status & DMOV_STATUS_CMD_PTR_RDY)) {
+#if 0
+		if (list_empty(&active_commands[id])) {
+			PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id);
+			writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
+		}
+#endif
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
+		list_add_tail(&cmd->list, &active_commands[id]);
+		writel(cmd->cmdptr, DMOV_CMD_PTR(id));
+	} else {
+		if (list_empty(&active_commands[id]))
+			PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
+
+		PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status);
+		list_add_tail(&cmd->list, &ready_commands[id]);
+	}
+	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+}
+
+struct msm_dmov_exec_cmdptr_cmd {
+	struct msm_dmov_cmd dmov_cmd;
+	struct completion complete;
+	unsigned id;
+	unsigned int result;
+	unsigned int flush[6];
+};
+
+static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result)
+{
+	struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd);
+	cmd->result = result;
+	if (result != 0x80000002) {
+		cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id));
+		cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id));
+		cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id));
+		cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id));
+		cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id));
+		cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id));
+	}
+	complete(&cmd->complete);
+}
+
+int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
+{
+	struct msm_dmov_exec_cmdptr_cmd cmd;
+
+	PRINT_FLOW("dmov_exec_cmdptr(%d, %x)\n", id, cmdptr);
+
+	cmd.dmov_cmd.cmdptr = cmdptr;
+	cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
+	cmd.id = id;
+	init_completion(&cmd.complete);
+
+	msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd);
+	wait_for_completion(&cmd.complete);
+
+	if (cmd.result != 0x80000002) {
+		PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result);
+		PRINT_ERROR("dmov_exec_cmdptr(%d):  flush: %x %x %x %x\n",
+			id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]);
+		return -EIO;
+	}
+	PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr);
+	return 0;
+}
+
+
+static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
+{
+	unsigned int int_status, mask, id;
+	unsigned long irq_flags;
+	unsigned int ch_status;
+	unsigned int ch_result;
+	struct msm_dmov_cmd *cmd;
+
+	spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+
+	int_status = readl(DMOV_ISR); /* read and clear interrupt */
+	PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
+
+	while (int_status) {
+		mask = int_status & -int_status;
+		id = fls(mask) - 1;
+		PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id);
+		int_status &= ~mask;
+		ch_status = readl(DMOV_STATUS(id));
+		if (!(ch_status & DMOV_STATUS_RSLT_VALID)) {
+			PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status);
+			continue;
+		}
+		do {
+			ch_result = readl(DMOV_RSLT(id));
+			if (list_empty(&active_commands[id])) {
+				PRINT_ERROR("msm_datamover_irq_handler id %d, got result "
+					"with no active command, status %x, result %x\n",
+					id, ch_status, ch_result);
+				cmd = NULL;
+			} else
+				cmd = list_entry(active_commands[id].next, typeof(*cmd), list);
+			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result);
+			if (ch_result & DMOV_RSLT_DONE) {
+				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n",
+					id, ch_status);
+				PRINT_IO("msm_datamover_irq_handler id %d, got result "
+					"for %p, result %x\n", id, cmd, ch_result);
+				if (cmd) {
+					list_del(&cmd->list);
+					cmd->complete_func(cmd, ch_result);
+				}
+			}
+			if (ch_result & DMOV_RSLT_FLUSH) {
+				unsigned int flush0 = readl(DMOV_FLUSH0(id));
+				PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
+				PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0);
+				if (cmd) {
+					list_del(&cmd->list);
+					cmd->complete_func(cmd, ch_result);
+				}
+			}
+			if (ch_result & DMOV_RSLT_ERROR) {
+				unsigned int flush0 = readl(DMOV_FLUSH0(id));
+				PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
+				PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0);
+				if (cmd) {
+					list_del(&cmd->list);
+					cmd->complete_func(cmd, ch_result);
+				}
+				/* this does not seem to work, once we get an error */
+				/* the datamover will no longer accept commands */
+				writel(0, DMOV_FLUSH0(id));
+			}
+			ch_status = readl(DMOV_STATUS(id));
+			PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
+			if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) {
+				cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
+				list_del(&cmd->list);
+				list_add_tail(&cmd->list, &active_commands[id]);
+				PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
+				writel(cmd->cmdptr, DMOV_CMD_PTR(id));
+			}
+		} while (ch_status & DMOV_STATUS_RSLT_VALID);
+		PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
+	}
+	spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+	return IRQ_HANDLED;
+}
+
+static int __init msm_init_datamover(void)
+{
+	int i;
+	for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
+		INIT_LIST_HEAD(&ready_commands[i]);
+		INIT_LIST_HEAD(&active_commands[i]);
+		writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
+	}
+	return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
+}
+
+arch_initcall(msm_init_datamover);
+
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
new file mode 100644
index 0000000..2b1cb7f
--- /dev/null
+++ b/arch/arm/mach-msm/idle.S
@@ -0,0 +1,36 @@
+/* linux/include/asm-arm/arch-msm/idle.S
+ *
+ * Idle processing for MSM7K - work around bugs with SWFI.
+ *
+ * Copyright (c) 2007 QUALCOMM Incorporated.
+ * Copyright (C) 2007 Google, Inc. 
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */ 
+		
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(arch_idle)
+#ifdef CONFIG_MSM7X00A_IDLE
+	mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
+	bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
+	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
+	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
+
+	mov     r0, #0                   /* prepare wfi value  */
+	mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */
+	mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */
+	mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
+
+	mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
+#endif
+	mov     pc, lr
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
new file mode 100644
index 0000000..c39edb9
--- /dev/null
+++ b/arch/arm/mach-msm/io.c
@@ -0,0 +1,85 @@
+/* arch/arm/mach-msm/io.c
+ *
+ * MSM7K io support
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/arch/msm_iomap.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/board.h>
+
+#define MSM_DEVICE(name) { \
+		.virtual = MSM_##name##_BASE, \
+		.pfn = __phys_to_pfn(MSM_##name##_PHYS), \
+		.length = MSM_##name##_SIZE, \
+		.type = MT_DEVICE_NONSHARED, \
+	 }
+
+static struct map_desc msm_io_desc[] __initdata = {
+	MSM_DEVICE(VIC),
+	MSM_DEVICE(CSR),
+	MSM_DEVICE(GPT),
+	MSM_DEVICE(DMOV),
+	MSM_DEVICE(UART1),
+	MSM_DEVICE(UART2),
+	MSM_DEVICE(UART3),
+	MSM_DEVICE(I2C),
+	MSM_DEVICE(GPIO1),
+	MSM_DEVICE(GPIO2),
+	MSM_DEVICE(HSUSB),
+	MSM_DEVICE(CLK_CTL),
+	MSM_DEVICE(PMDH),
+	MSM_DEVICE(EMDH),
+	MSM_DEVICE(MDP),
+	{
+		.virtual =  MSM_SHARED_RAM_BASE,
+		.pfn =      __phys_to_pfn(MSM_SHARED_RAM_PHYS),
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+};
+
+void __init msm_map_common_io(void)
+{
+	/* Make sure the peripheral register window is closed, since
+	 * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which
+	 * pages are peripheral interface or not.
+	 */
+	asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0));
+
+	iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc));
+}
+
+void __iomem *
+__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+{
+	if (mtype == MT_DEVICE) {
+		/* The peripherals in the 88000000 - D0000000 range
+		 * are only accessable by type MT_DEVICE_NONSHARED.
+		 * Adjust mtype as necessary to make this "just work."
+		 */
+		if ((phys_addr >= 0x88000000) && (phys_addr < 0xD0000000))
+			mtype = MT_DEVICE_NONSHARED;
+	}
+
+	return __arm_ioremap(phys_addr, size, mtype);
+}
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
new file mode 100644
index 0000000..2415804
--- /dev/null
+++ b/arch/arm/mach-msm/irq.c
@@ -0,0 +1,154 @@
+/* linux/arch/arm/mach-msm/irq.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+
+#include <linux/irq.h>
+#include <asm/hardware.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/msm_iomap.h>
+
+#define VIC_REG(off) (MSM_VIC_BASE + (off))
+
+#define VIC_INT_SELECT0     VIC_REG(0x0000)  /* 1: FIQ, 0: IRQ */
+#define VIC_INT_SELECT1     VIC_REG(0x0004)  /* 1: FIQ, 0: IRQ */
+#define VIC_INT_EN0         VIC_REG(0x0010)
+#define VIC_INT_EN1         VIC_REG(0x0014)
+#define VIC_INT_ENCLEAR0    VIC_REG(0x0020)
+#define VIC_INT_ENCLEAR1    VIC_REG(0x0024)
+#define VIC_INT_ENSET0      VIC_REG(0x0030)
+#define VIC_INT_ENSET1      VIC_REG(0x0034)
+#define VIC_INT_TYPE0       VIC_REG(0x0040)  /* 1: EDGE, 0: LEVEL  */
+#define VIC_INT_TYPE1       VIC_REG(0x0044)  /* 1: EDGE, 0: LEVEL  */
+#define VIC_INT_POLARITY0   VIC_REG(0x0050)  /* 1: NEG, 0: POS */
+#define VIC_INT_POLARITY1   VIC_REG(0x0054)  /* 1: NEG, 0: POS */
+#define VIC_NO_PEND_VAL     VIC_REG(0x0060)
+#define VIC_INT_MASTEREN    VIC_REG(0x0064)  /* 1: IRQ, 2: FIQ     */
+#define VIC_PROTECTION      VIC_REG(0x006C)  /* 1: ENABLE          */
+#define VIC_CONFIG          VIC_REG(0x0068)  /* 1: USE ARM1136 VIC */
+#define VIC_IRQ_STATUS0     VIC_REG(0x0080)
+#define VIC_IRQ_STATUS1     VIC_REG(0x0084)
+#define VIC_FIQ_STATUS0     VIC_REG(0x0090)
+#define VIC_FIQ_STATUS1     VIC_REG(0x0094)
+#define VIC_RAW_STATUS0     VIC_REG(0x00A0)
+#define VIC_RAW_STATUS1     VIC_REG(0x00A4)
+#define VIC_INT_CLEAR0      VIC_REG(0x00B0)
+#define VIC_INT_CLEAR1      VIC_REG(0x00B4)
+#define VIC_SOFTINT0        VIC_REG(0x00C0)
+#define VIC_SOFTINT1        VIC_REG(0x00C4)
+#define VIC_IRQ_VEC_RD      VIC_REG(0x00D0)  /* pending int # */
+#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4)  /* pending vector addr */
+#define VIC_IRQ_VEC_WR      VIC_REG(0x00D8)
+#define VIC_IRQ_IN_SERVICE  VIC_REG(0x00E0)
+#define VIC_IRQ_IN_STACK    VIC_REG(0x00E4)
+#define VIC_TEST_BUS_SEL    VIC_REG(0x00E8)
+
+#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
+#define VIC_VECTADDR(n)     VIC_REG(0x0400+((n) * 4))
+
+static void msm_irq_ack(unsigned int irq)
+{
+	unsigned reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
+	irq = 1 << (irq & 31);
+	writel(irq, reg);
+}
+
+static void msm_irq_mask(unsigned int irq)
+{
+	unsigned reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
+	writel(1 << (irq & 31), reg);
+}
+
+static void msm_irq_unmask(unsigned int irq)
+{
+	unsigned reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
+	writel(1 << (irq & 31), reg);
+}
+
+static int msm_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	return -EINVAL;
+}
+
+static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
+	unsigned preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
+	int b = 1 << (irq & 31);
+
+	if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
+		writel(readl(preg) | b, preg);
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+		writel(readl(preg) & (~b), preg);
+
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		writel(readl(treg) | b, treg);
+		set_irq_handler(irq, handle_edge_irq);
+	}
+	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
+		writel(readl(treg) & (~b), treg);
+		set_irq_handler(irq, handle_level_irq);
+	}
+	return 0;
+}
+
+static struct irq_chip msm_irq_chip = {
+	.name      = "msm",
+	.ack       = msm_irq_ack,
+	.mask      = msm_irq_mask,
+	.unmask    = msm_irq_unmask,
+	.set_wake  = msm_irq_set_wake,
+	.set_type  = msm_irq_set_type,
+};
+
+void __init msm_init_irq(void)
+{
+	unsigned n;
+
+	/* select level interrupts */
+	writel(0, VIC_INT_TYPE0);
+	writel(0, VIC_INT_TYPE1);
+
+	/* select highlevel interrupts */
+	writel(0, VIC_INT_POLARITY0);
+	writel(0, VIC_INT_POLARITY1);
+
+	/* select IRQ for all INTs */
+	writel(0, VIC_INT_SELECT0);
+	writel(0, VIC_INT_SELECT1);
+
+	/* disable all INTs */
+	writel(0, VIC_INT_EN0);
+	writel(0, VIC_INT_EN1);
+
+	/* don't use 1136 vic */
+	writel(0, VIC_CONFIG);
+
+	/* enable interrupt controller */
+	writel(1, VIC_INT_MASTEREN);
+
+	for (n = 0; n < NR_MSM_IRQS; n++) {
+		set_irq_chip(n, &msm_irq_chip);
+		set_irq_handler(n, handle_level_irq);
+		set_irq_flags(n, IRQF_VALID);
+	}
+}
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
new file mode 100644
index 0000000..bd4732d
--- /dev/null
+++ b/arch/arm/mach-msm/timer.c
@@ -0,0 +1,205 @@
+/* linux/arch/arm/mach-msm/timer.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/delay.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/msm_iomap.h>
+
+#include <asm/io.h>
+
+#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
+#define MSM_DGT_SHIFT (5)
+
+#define TIMER_MATCH_VAL         0x0000
+#define TIMER_COUNT_VAL         0x0004
+#define TIMER_ENABLE            0x0008
+#define TIMER_ENABLE_CLR_ON_MATCH_EN    2
+#define TIMER_ENABLE_EN                 1
+#define TIMER_CLEAR             0x000C
+
+#define CSR_PROTECTION          0x0020
+#define CSR_PROTECTION_EN               1
+
+#define GPT_HZ 32768
+#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+
+struct msm_clock {
+	struct clock_event_device   clockevent;
+	struct clocksource          clocksource;
+	struct irqaction            irq;
+	uint32_t                    regbase;
+	uint32_t                    freq;
+	uint32_t                    shift;
+};
+
+static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static cycle_t msm_gpt_read(void)
+{
+	return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+}
+
+static cycle_t msm_dgt_read(void)
+{
+	return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+}
+
+static int msm_timer_set_next_event(unsigned long cycles,
+				    struct clock_event_device *evt)
+{
+	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
+	uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
+	uint32_t alarm = now + (cycles << clock->shift);
+	int late;
+
+	writel(alarm, clock->regbase + TIMER_MATCH_VAL);
+	now = readl(clock->regbase + TIMER_COUNT_VAL);
+	late = now - alarm;
+	if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
+		printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
+		       "alarm already expired, now %x, alarm %x, late %d\n",
+		       cycles, clock->clockevent.name, now, alarm, late);
+		return -ETIME;
+	}
+	return 0;
+}
+
+static void msm_timer_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
+	switch (mode) {
+	case CLOCK_EVT_MODE_RESUME:
+	case CLOCK_EVT_MODE_PERIODIC:
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		writel(0, clock->regbase + TIMER_ENABLE);
+		break;
+	}
+}
+
+static struct msm_clock msm_clocks[] = {
+	{
+		.clockevent = {
+			.name           = "gp_timer",
+			.features       = CLOCK_EVT_FEAT_ONESHOT,
+			.shift          = 32,
+			.rating         = 200,
+			.set_next_event = msm_timer_set_next_event,
+			.set_mode       = msm_timer_set_mode,
+		},
+		.clocksource = {
+			.name           = "gp_timer",
+			.rating         = 200,
+			.read           = msm_gpt_read,
+			.mask           = CLOCKSOURCE_MASK(32),
+			.shift          = 24,
+			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+		},
+		.irq = {
+			.name    = "gp_timer",
+			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+			.handler = msm_timer_interrupt,
+			.dev_id  = &msm_clocks[0].clockevent,
+			.irq     = INT_GP_TIMER_EXP
+		},
+		.regbase = MSM_GPT_BASE,
+		.freq = GPT_HZ
+	},
+	{
+		.clockevent = {
+			.name           = "dg_timer",
+			.features       = CLOCK_EVT_FEAT_ONESHOT,
+			.shift          = 32 + MSM_DGT_SHIFT,
+			.rating         = 300,
+			.set_next_event = msm_timer_set_next_event,
+			.set_mode       = msm_timer_set_mode,
+		},
+		.clocksource = {
+			.name           = "dg_timer",
+			.rating         = 300,
+			.read           = msm_dgt_read,
+			.mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
+			.shift          = 24 - MSM_DGT_SHIFT,
+			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+		},
+		.irq = {
+			.name    = "dg_timer",
+			.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+			.handler = msm_timer_interrupt,
+			.dev_id  = &msm_clocks[1].clockevent,
+			.irq     = INT_DEBUG_TIMER_EXP
+		},
+		.regbase = MSM_DGT_BASE,
+		.freq = DGT_HZ >> MSM_DGT_SHIFT,
+		.shift = MSM_DGT_SHIFT
+	}
+};
+
+static void __init msm_timer_init(void)
+{
+	int i;
+	int res;
+
+	for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
+		struct msm_clock *clock = &msm_clocks[i];
+		struct clock_event_device *ce = &clock->clockevent;
+		struct clocksource *cs = &clock->clocksource;
+		writel(0, clock->regbase + TIMER_ENABLE);
+		writel(0, clock->regbase + TIMER_CLEAR);
+		writel(~0, clock->regbase + TIMER_MATCH_VAL);
+
+		ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
+		/* allow at least 10 seconds to notice that the timer wrapped */
+		ce->max_delta_ns =
+			clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
+		/* 4 gets rounded down to 3 */
+		ce->min_delta_ns = clockevent_delta2ns(4, ce);
+		ce->cpumask = cpumask_of_cpu(0);
+
+		cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
+		res = clocksource_register(cs);
+		if (res)
+			printk(KERN_ERR "msm_timer_init: clocksource_register "
+			       "failed for %s\n", cs->name);
+
+		res = setup_irq(clock->irq.irq, &clock->irq);
+		if (res)
+			printk(KERN_ERR "msm_timer_init: setup_irq "
+			       "failed for %s\n", cs->name);
+
+		clockevents_register_device(ce);
+	}
+}
+
+struct sys_timer msm_timer = {
+	.init = msm_timer_init
+};
diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c
index e81fb5c..fb565c9 100644
--- a/arch/arm/mach-mx3/time.c
+++ b/arch/arm/mach-mx3/time.c
@@ -45,8 +45,6 @@
 {
 	unsigned int next_match;
 
-	write_seqlock(&xtime_lock);
-
 	if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
 		do {
 			timer_tick();
@@ -57,8 +55,6 @@
 				       __raw_readl(MXC_GPT_GPTCNT)) <= 0);
 	}
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index 4762e20..ea07b54 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -33,12 +33,8 @@
 static irqreturn_t
 netx_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	/* acknowledge interrupt */
 	writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
 
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 1306812..9393824 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -27,6 +27,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/hardware.h>
 #include <asm/gpio.h>
@@ -36,7 +37,6 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/tps65010.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/irda.h>
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 4f84ae2..978cdab 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -26,6 +26,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -37,7 +38,6 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
-#include <asm/arch/tps65010.h>
 #include <asm/arch/gpioexpander.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/mux.h>
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 182a98a..e2c8ffd 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -32,7 +32,6 @@
 #include <asm/arch/common.h>
 #include <asm/arch/dsp_common.h>
 #include <asm/arch/aic23.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/omapfb.h>
 #include <asm/arch/lcd_mipid.h>
 
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 5db182d..4e01617 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -31,12 +31,13 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/interrupt.h>
 #include <linux/i2c.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/i2c/tps65010.h>
+
 #include <asm/hardware.h>
 #include <asm/gpio.h>
 
@@ -46,7 +47,6 @@
 #include <asm/mach/flash.h>
 
 #include <asm/arch/usb.h>
-#include <asm/arch/tps65010.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/common.h>
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index e47010f..ed7094a 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -42,7 +42,6 @@
 #include <asm/arch/common.h>
 #include <asm/arch/omap-alsa.h>
 
-#include <linux/input.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index c275d51..a9a0f66 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -44,7 +44,6 @@
 #include <asm/arch/common.h>
 #include <asm/arch/omap-alsa.h>
 
-#include <linux/input.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
index 86de303..6939d5e 100644
--- a/arch/arm/mach-omap1/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -5,13 +5,13 @@
  */
 #include <linux/init.h>
 #include <linux/workqueue.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/hardware.h>
 #include <asm/leds.h>
 #include <asm/system.h>
 
 #include <asm/arch/gpio.h>
-#include <asm/arch/tps65010.h>
 
 #include "leds.h"
 
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index d9805e3..06b7e54 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -639,7 +639,7 @@
 }
 
 
-static irqreturn_t  omap_wakeup_interrupt(int irq, void *dev)
+static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
 {
 	return IRQ_HANDLED;
 }
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index 3bb49c1..94e38cc 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/leds.h>
-#include <linux/irq.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 8d322c2..3234dee 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -40,13 +40,9 @@
 
 static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
 	timer_tick();
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 67e05f0..6d4ca8f 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -51,8 +51,6 @@
 {
 	if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
 
-		write_seqlock(&xtime_lock);
-
 		do {
 			timer_tick();
 
@@ -73,8 +71,6 @@
 		} while ((signed)
 			 (__raw_readl(HSTIM_MATCH0) -
 			  __raw_readl(HSTIM_COUNTER)) < 0);
-
-		write_sequnlock(&xtime_lock);
 	}
 
 	return IRQ_HANDLED;
diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
index 12d2fe0..254892a 100644
--- a/arch/arm/mach-pxa/akita-ioexp.c
+++ b/arch/arm/mach-pxa/akita-ioexp.c
@@ -29,7 +29,7 @@
 #define MAX7310_TIMEOUT  0x04
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
 
 /* I2C Magic */
 I2C_CLIENT_INSMOD;
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 9732d5d..006a6e0 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -111,11 +111,14 @@
  * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
  * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
  */
+static struct clk pxa25x_hwuart_clk =
+	INIT_CKEN("UARTCLK", HWUART, 14745600, 1, &pxa_device_hwuart.dev)
+;
+
 static struct clk pxa25x_clks[] = {
 	INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
 	INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
 	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
-	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
 	INIT_CKEN("UARTCLK", STUART, 14745600, 1, NULL),
 	INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
 	INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
@@ -303,6 +306,10 @@
 {
 	int ret = 0;
 
+	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
+	if (cpu_is_pxa25x())
+		clks_register(&pxa25x_hwuart_clk, 1);
+
 	if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
 		clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));
 
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 8e126e6..57efebd 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -24,6 +24,7 @@
 #include <asm/arch/ohci.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/dma.h>
+#include <asm/arch/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -423,6 +424,11 @@
 	.num_resources	= ARRAY_SIZE(i2c_power_resources),
 };
 
+void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info)
+{
+	pxa27x_device_i2c_power.dev.platform_data = info;
+}
+
 static struct platform_device *devices[] __initdata = {
 	&pxa_device_mci,
 	&pxa_device_udc,
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 61d9c9d..37e93f9 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -86,7 +86,7 @@
 			HSS / 1000000, (HSS % 1000000) / 10000);
 	}
 
-	return CLK;
+	return CLK / 1000;
 }
 
 /*
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 422afee..b2eb385 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -67,7 +67,7 @@
 
 static irqreturn_t ssp_interrupt(int irq, void *dev_id)
 {
-	struct ssp_dev *dev = (struct ssp_dev*) dev_id;
+	struct ssp_dev *dev = dev_id;
 	unsigned int status = SSSR_P(dev->port);
 
 	SSSR_P(dev->port) = status; /* clear status bits */
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index c7f1b44..61d7021 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -530,8 +530,6 @@
  */
 static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
-
 	// ...clear the interrupt
 	writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
 
@@ -542,8 +540,6 @@
 	update_process_times(user_mode(get_irq_regs()));
 #endif
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 587864fe..6617547 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -530,7 +530,7 @@
 
 	.displays = bast_lcd_info,
 	.num_displays = ARRAY_SIZE(bast_lcd_info),
-	.default_display = 4,
+	.default_display = 1,
 };
 
 /* Standard BAST devices */
@@ -540,7 +540,6 @@
 	&s3c_device_lcd,
 	&s3c_device_wdt,
 	&s3c_device_i2c,
-	&s3c_device_iis,
  	&s3c_device_rtc,
 	&s3c_device_nand,
 	&bast_device_nor,
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 9f43f3f..3aade7b 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -365,7 +365,6 @@
 	&s3c_device_lcd,
 	&s3c_device_wdt,
 	&s3c_device_i2c,
-	&s3c_device_iis,
 	&s3c_device_adc,
 	&serial_device,
 	&vr1000_nor,
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index bcd562a..6aec86a 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -60,7 +60,7 @@
 static irqreturn_t
 usb_simtec_ocirq(int irq, void *pw)
 {
-	struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
+	struct s3c2410_hcd_info *info = pw;
 
 	if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
 		pr_debug("usb_simtec: over-current irq (oc detected)\n");
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index 8e8fe48..0b43431 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -10,6 +10,7 @@
 	select CPU_LLSERIAL_S3C2440
 	select S3C2412_PM if PM
 	select S3C2412_DMA if S3C2410_DMA
+	select S3C2410_GPIO
 	help
 	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
 
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
index f8e0116..267f334 100644
--- a/arch/arm/mach-s3c2412/Makefile
+++ b/arch/arm/mach-s3c2412/Makefile
@@ -12,8 +12,9 @@
 obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
 obj-$(CONFIG_CPU_S3C2412)	+= irq.o
 obj-$(CONFIG_CPU_S3C2412)	+= clock.o
+obj-$(CONFIG_CPU_S3C2412)	+= gpio.o
 obj-$(CONFIG_S3C2412_DMA)	+= dma.o
-obj-$(CONFIG_S3C2412_PM)	+= pm.o
+obj-$(CONFIG_S3C2412_PM)	+= pm.o sleep.o
 
 # Machine support
 
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
index 4589936..2697a65 100644
--- a/arch/arm/mach-s3c2412/clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -217,7 +217,7 @@
 
 	if (parent == &clk_mdivclk)
 		clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
-	else if (parent == &clk_upll)
+	else if (parent == &clk_mpll)
 		clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
 	else
 		return -EINVAL;
@@ -234,6 +234,45 @@
 	.set_parent	= s3c2412_setparent_msysclk,
 };
 
+static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+	unsigned long flags;
+	unsigned long clkdiv;
+	unsigned long dvs;
+
+	/* Note, we current equate fclk andf msysclk for S3C2412 */
+
+	if (parent == &clk_msysclk || parent == &clk_f)
+		dvs = 0;
+	else if (parent == &clk_h)
+		dvs = S3C2412_CLKDIVN_DVSEN;
+	else
+		return -EINVAL;
+
+	clk->parent = parent;
+
+	/* update this under irq lockdown, clkdivn is not protected
+	 * by the clock system. */
+
+	local_irq_save(flags);
+
+	clkdiv  = __raw_readl(S3C2410_CLKDIVN);
+	clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
+	clkdiv |= dvs;
+	__raw_writel(clkdiv, S3C2410_CLKDIVN);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct clk clk_armclk = {
+	.name		= "armclk",
+	.id		= -1,
+	.parent		= &clk_msysclk,
+	.set_parent	= s3c2412_setparent_armclk,
+};
+
 /* these next clocks have an divider immediately after them,
  * so we can register them with their divider and leave out the
  * intermediate clock stage
@@ -630,11 +669,13 @@
 	&clk_erefclk,
 	&clk_urefclk,
 	&clk_mrefclk,
+	&clk_armclk,
 };
 
 int __init s3c2412_baseclk_add(void)
 {
 	unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
+	unsigned int dvs;
 	struct clk *clkp;
 	int ret;
 	int ptr;
@@ -643,6 +684,8 @@
 	clk_usb_bus.parent = &clk_usbsrc;
 	clk_usb_bus.rate = 0x0;
 
+	clk_f.parent = &clk_msysclk;
+
 	s3c2412_clk_initparents();
 
 	for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
@@ -655,6 +698,15 @@
 		}
 	}
 
+	/* set the dvs state according to what we got at boot time */
+
+	dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
+
+	if (dvs)
+		clk_armclk.parent = &clk_h;
+
+	printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
+
 	/* ensure usb bus clock is within correct rate of 48MHz */
 
 	if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index 53c1d5bb..1dd8649 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -30,6 +30,7 @@
 #include <asm/arch/regs-mem.h>
 #include <asm/arch/regs-lcd.h>
 #include <asm/arch/regs-sdi.h>
+#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
 #include <asm/plat-s3c24xx/regs-iis.h>
 #include <asm/plat-s3c24xx/regs-spi.h>
 
@@ -39,106 +40,141 @@
 	[DMACH_XD0] = {
 		.name		= "xdreq0",
 		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ0),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_XDREQ0),
 	},
 	[DMACH_XD1] = {
 		.name		= "xdreq1",
 		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ1),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_XDREQ1),
 	},
 	[DMACH_SDI] = {
 		.name		= "sdi",
 		.channels	= MAP(S3C2412_DMAREQSEL_SDI),
-		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
-		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_SDI),
+		.hw_addr.to	= S3C2410_PA_SDI + S3C2410_SDIDATA,
+		.hw_addr.from	= S3C2410_PA_SDI + S3C2410_SDIDATA,
 	},
 	[DMACH_SPI0] = {
 		.name		= "spi0",
 		.channels	= MAP(S3C2412_DMAREQSEL_SPI0TX),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_SPI0RX),
 		.hw_addr.to	= S3C2410_PA_SPI + S3C2410_SPTDAT,
 		.hw_addr.from	= S3C2410_PA_SPI + S3C2410_SPRDAT,
 	},
 	[DMACH_SPI1] = {
 		.name		= "spi1",
 		.channels	= MAP(S3C2412_DMAREQSEL_SPI1TX),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_SPI1RX),
 		.hw_addr.to	= S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT,
 		.hw_addr.from	= S3C2410_PA_SPI + S3C2412_SPI1  + S3C2410_SPRDAT,
 	},
 	[DMACH_UART0] = {
 		.name		= "uart0",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART0_0),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART0_0),
 		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
 	},
 	[DMACH_UART1] = {
 		.name		= "uart1",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART1_0),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART1_0),
 		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
 	},
       	[DMACH_UART2] = {
 		.name		= "uart2",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART2_0),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART2_0),
 		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
 	},
 	[DMACH_UART0_SRC2] = {
 		.name		= "uart0",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART0_1),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART0_1),
 		.hw_addr.to	= S3C2410_PA_UART0 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART0 + S3C2410_URXH,
 	},
 	[DMACH_UART1_SRC2] = {
 		.name		= "uart1",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART1_1),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART1_1),
 		.hw_addr.to	= S3C2410_PA_UART1 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART1 + S3C2410_URXH,
 	},
       	[DMACH_UART2_SRC2] = {
 		.name		= "uart2",
 		.channels	= MAP(S3C2412_DMAREQSEL_UART2_1),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_UART2_1),
 		.hw_addr.to	= S3C2410_PA_UART2 + S3C2410_UTXH,
 		.hw_addr.from	= S3C2410_PA_UART2 + S3C2410_URXH,
 	},
 	[DMACH_TIMER] = {
 		.name		= "timer",
 		.channels	= MAP(S3C2412_DMAREQSEL_TIMER),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_TIMER),
 	},
 	[DMACH_I2S_IN] = {
 		.name		= "i2s-sdi",
 		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX),
-		.hw_addr.from	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2SRX),
+		.hw_addr.from	= S3C2410_PA_IIS + S3C2412_IISRXD,
 	},
 	[DMACH_I2S_OUT] = {
 		.name		= "i2s-sdo",
 		.channels	= MAP(S3C2412_DMAREQSEL_I2STX),
-		.hw_addr.to	= S3C2410_PA_IIS + S3C2410_IISFIFO,
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_I2STX),
+		.hw_addr.to	= S3C2410_PA_IIS + S3C2412_IISTXD,
 	},
 	[DMACH_USB_EP1] = {
 		.name		= "usb-ep1",
 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP1),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP1),
 	},
 	[DMACH_USB_EP2] = {
 		.name		= "usb-ep2",
 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP2),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP2),
 	},
 	[DMACH_USB_EP3] = {
 		.name		= "usb-ep3",
 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP3),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP3),
 	},
 	[DMACH_USB_EP4] = {
 		.name		= "usb-ep4",
 		.channels	= MAP(S3C2412_DMAREQSEL_USBEP4),
+		.channels_rx	= MAP(S3C2412_DMAREQSEL_USBEP4),
 	},
 };
 
+static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
+				  struct s3c24xx_dma_map *map,
+				  enum s3c2410_dmasrc dir)
+{
+	unsigned long chsel;
+
+	if (dir == S3C2410_DMASRC_HW)
+		chsel = map->channels_rx[0];
+	else
+		chsel = map->channels[0];
+
+	chsel &= ~DMA_CH_VALID;
+	chsel |= S3C2412_DMAREQSEL_HW;
+
+	writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL);
+}
+
 static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
 			       struct s3c24xx_dma_map *map)
 {
-	writel(map->channels[0] | S3C2412_DMAREQSEL_HW,
-	       chan->regs + S3C2412_DMA_DMAREQSEL);
+	s3c2412_dma_direction(chan, map, chan->source);
 }
 
 static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
 	.select		= s3c2412_dma_select,
+	.direction	= s3c2412_dma_direction,
 	.dcon_mask	= 0,
 	.map		= s3c2412_dma_mappings,
 	.map_size	= ARRAY_SIZE(s3c2412_dma_mappings),
diff --git a/arch/arm/mach-s3c2412/gpio.c b/arch/arm/mach-s3c2412/gpio.c
new file mode 100644
index 0000000..8e55c3a
--- /dev/null
+++ b/arch/arm/mach-s3c2412/gpio.c
@@ -0,0 +1,60 @@
+/* linux/arch/arm/mach-s3c2412/gpio.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * S3C2412/S3C2413 specific GPIO support
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/hardware.h>
+
+int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state)
+{
+	void __iomem *base = S3C24XX_GPIO_BASE(pin);
+	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+	unsigned long flags;
+	unsigned long slpcon;
+
+	offs *= 2;
+
+	if (pin < S3C2410_GPIO_BANKB)
+		return -EINVAL;
+
+	if (pin >= S3C2410_GPIO_BANKF &&
+	    pin <= S3C2410_GPIO_BANKG)
+		return -EINVAL;
+
+	if (pin > (S3C2410_GPIO_BANKH + 32))
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	slpcon = __raw_readl(base + 0x0C);
+
+	slpcon &= ~(3 << offs);
+	slpcon |= state << offs;
+
+	__raw_writel(slpcon, base + 0x0C);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(s3c2412_gpio_set_sleepcfg);
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index e9d0c76..cc1917b 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -33,6 +33,7 @@
 
 #include <asm/arch/regs-irq.h>
 #include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-power.h>
 
 #include <asm/plat-s3c24xx/cpu.h>
 #include <asm/plat-s3c24xx/irq.h>
@@ -153,6 +154,22 @@
 	.unmask		= s3c2412_irq_cfsdi_unmask,
 };
 
+static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state)
+{
+	unsigned long pwrcfg;
+
+	pwrcfg = __raw_readl(S3C2412_PWRCFG);
+	if (state)
+		pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
+	else
+		pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
+	__raw_writel(pwrcfg, S3C2412_PWRCFG);
+
+	return s3c_irq_chip.set_wake(irqno, state);
+}
+
+static struct irq_chip s3c2412_irq_rtc_chip;
+
 static int s3c2412_irq_add(struct sys_device *sysdev)
 {
 	unsigned int irqno;
@@ -173,6 +190,13 @@
 		set_irq_flags(irqno, IRQF_VALID);
 	}
 
+	/* change RTC IRQ's set wake method */
+
+	s3c2412_irq_rtc_chip = s3c_irq_chip;
+	s3c2412_irq_rtc_chip.set_wake = s3c2412_irq_rtc_wake;
+
+	set_irq_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c
index 8988dac..d4ffb2d 100644
--- a/arch/arm/mach-s3c2412/pm.c
+++ b/arch/arm/mach-s3c2412/pm.c
@@ -33,6 +33,8 @@
 
 #include <asm/plat-s3c24xx/s3c2412.h>
 
+extern void s3c2412_sleep_enter(void);
+
 static void s3c2412_cpu_suspend(void)
 {
 	unsigned long tmp;
@@ -43,20 +45,7 @@
 	tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
 	__raw_writel(tmp, S3C2412_PWRCFG);
 
-	/* issue the standby signal into the pm unit. Note, we
-	 * issue a write-buffer drain just in case */
-
-	tmp = 0;
-
-	asm("b 1f\n\t"
-	    ".align 5\n\t"
-	    "1:\n\t"
-	    "mcr p15, 0, %0, c7, c10, 4\n\t"
-	    "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
-
-	/* we should never get past here */
-
-	panic("sleep resumed to originator?");
+	s3c2412_sleep_enter();
 }
 
 static void s3c2412_pm_prepare(void)
@@ -88,7 +77,6 @@
 	SAVE_ITEM(S3C2412_GPBSLPCON),
 	SAVE_ITEM(S3C2412_GPCSLPCON),
 	SAVE_ITEM(S3C2412_GPDSLPCON),
-	SAVE_ITEM(S3C2412_GPESLPCON),
 	SAVE_ITEM(S3C2412_GPFSLPCON),
 	SAVE_ITEM(S3C2412_GPGSLPCON),
 	SAVE_ITEM(S3C2412_GPHSLPCON),
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index 265cd3f..abf1599 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -168,6 +168,8 @@
 
 	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
 
+	clk_mpll.rate = fclk;
+
 	tmp = __raw_readl(S3C2410_CLKDIVN);
 
 	/* work out clock scalings */
diff --git a/arch/arm/mach-s3c2412/sleep.S b/arch/arm/mach-s3c2412/sleep.S
new file mode 100644
index 0000000..db32cac
--- /dev/null
+++ b/arch/arm/mach-s3c2412/sleep.S
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s3c2412/sleep.S
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412 Power Manager low-level sleep support
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+#include <asm/arch/map.h>
+
+#include <asm/arch/regs-irq.h>
+
+	.text
+
+	.global	s3c2412_sleep_enter
+
+s3c2412_sleep_enter:
+	mov	r0, #0			/* argument for coprocessors */
+	ldr	r1, =S3C2410_INTPND
+	ldr	r2, =S3C2410_SRCPND
+	ldr	r3, =S3C2410_EINTPEND
+
+	teq	r0, r0
+	bl	s3c2412_sleep_enter1
+	teq	pc, r0
+	bl	s3c2412_sleep_enter1
+
+	.align	5
+
+	/* this is called twice, first with the Z flag to ensure that the
+	 * instructions have been loaded into the cache, and the second
+	 * time to try and suspend the system.
+	*/
+s3c2412_sleep_enter1:
+	mcr	p15, 0, r0, c7, c10, 4
+	mcrne	p15, 0, r0, c7, c0, 4
+
+	/* if we return from here, it is because an interrupt was
+	 * active when we tried to shutdown. Try and ack the IRQ and
+	 * retry, as simply returning causes the system to lock.
+	*/
+
+	ldrne	r9, [ r1 ]
+	strne	r9, [ r1 ]
+	ldrne	r9, [ r2 ]
+	strne	r9, [ r2 ]
+	ldrne	r9, [ r3 ]
+	strne	r9, [ r3 ]
+	bne	s3c2412_sleep_enter1
+
+	mov	pc, r14
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
index 79e2ea4..184d804 100644
--- a/arch/arm/mach-s3c2440/clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -111,14 +111,9 @@
 
 static int s3c2440_clk_add(struct sys_device *sysdev)
 {
-	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
-	unsigned long clkdivn;
+	struct clk *clock_upll;
 	struct clk *clock_h;
 	struct clk *clock_p;
-	struct clk *clock_upll;
-
-	printk("S3C2440: Clock Support, DVS %s\n",
-	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
 
 	clock_p = clk_get(NULL, "pclk");
 	clock_h = clk_get(NULL, "hclk");
@@ -129,21 +124,6 @@
 		return -EINVAL;
 	}
 
-	/* check rate of UPLL, and if it is near 96MHz, then change
-	 * to using half the UPLL rate for the system */
-
-	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
-		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
-
-		mutex_lock(&clocks_mutex);
-
-		clkdivn = __raw_readl(S3C2410_CLKDIVN);
-		clkdivn |= S3C2440_CLKDIVN_UCLK;
-		__raw_writel(clkdivn, S3C2410_CLKDIVN);
-
-		mutex_unlock(&clocks_mutex);
-	}
-
 	s3c2440_clk_cam.parent = clock_h;
 	s3c2440_clk_ac97.parent = clock_p;
 	s3c2440_clk_cam_upll.parent = clock_upll;
diff --git a/arch/arm/mach-s3c2442/clock.c b/arch/arm/mach-s3c2442/clock.c
index 5b9e830..2d030d4 100644
--- a/arch/arm/mach-s3c2442/clock.c
+++ b/arch/arm/mach-s3c2442/clock.c
@@ -115,14 +115,9 @@
 
 static int s3c2442_clk_add(struct sys_device *sysdev)
 {
-	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
-	unsigned long clkdivn;
+	struct clk *clock_upll;
 	struct clk *clock_h;
 	struct clk *clock_p;
-	struct clk *clock_upll;
-
-	printk("S3C2442: Clock Support, DVS %s\n",
-	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
 
 	clock_p = clk_get(NULL, "pclk");
 	clock_h = clk_get(NULL, "hclk");
@@ -133,21 +128,6 @@
 		return -EINVAL;
 	}
 
-	/* check rate of UPLL, and if it is near 96MHz, then change
-	 * to using half the UPLL rate for the system */
-
-	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
-		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
-
-		mutex_lock(&clocks_mutex);
-
-		clkdivn = __raw_readl(S3C2410_CLKDIVN);
-		clkdivn |= S3C2440_CLKDIVN_UCLK;
-		__raw_writel(clkdivn, S3C2410_CLKDIVN);
-
-		mutex_unlock(&clocks_mutex);
-	}
-
 	s3c2442_clk_cam.parent = clock_h;
 	s3c2442_clk_cam_upll.parent = clock_upll;
 
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
index 59703c6..06206ce 100644
--- a/arch/arm/mach-sa1100/ssp.c
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -29,9 +29,8 @@
 {
 	unsigned int status = Ser4SSSR;
 
-	if (status & SSSR_ROR) {
+	if (status & SSSR_ROR)
 		printk(KERN_WARNING "SSP: receiver overrun\n");
-	}
 
 	Ser4SSSR = SSSR_ROR;
 
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index fdf7b01..c2677368 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/timex.h>
 #include <linux/signal.h>
+#include <linux/clocksource.h>
 
 #include <asm/mach/time.h>
 #include <asm/hardware.h>
@@ -35,23 +36,6 @@
 	return 0;
 }
 
-/* IRQs are disabled before entering here from do_gettimeofday() */
-static unsigned long sa1100_gettimeoffset (void)
-{
-	unsigned long ticks_to_match, elapsed, usec;
-
-	/* Get ticks before next timer match */
-	ticks_to_match = OSMR0 - OSCR;
-
-	/* We need elapsed ticks since last match */
-	elapsed = LATCH - ticks_to_match;
-
-	/* Now convert them to usec */
-	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
-
-	return usec;
-}
-
 #ifdef CONFIG_NO_IDLE_HZ
 static unsigned long initial_match;
 static int match_posponed;
@@ -62,8 +46,6 @@
 {
 	unsigned int next_match;
 
-	write_seqlock(&xtime_lock);
-
 #ifdef CONFIG_NO_IDLE_HZ
 	if (match_posponed) {
 		match_posponed = 0;
@@ -85,8 +67,6 @@
 		next_match = (OSMR0 += LATCH);
 	} while ((signed long)(next_match - OSCR) <= 0);
 
-	write_sequnlock(&xtime_lock);
-
 	return IRQ_HANDLED;
 }
 
@@ -96,6 +76,20 @@
 	.handler	= sa1100_timer_interrupt,
 };
 
+static cycle_t sa1100_read_oscr(void)
+{
+	return OSCR;
+}
+
+static struct clocksource cksrc_sa1100_oscr = {
+	.name		= "oscr",
+	.rating		= 200,
+	.read		= sa1100_read_oscr,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
 static void __init sa1100_timer_init(void)
 {
 	unsigned long flags;
@@ -109,6 +103,11 @@
 	OIER = OIER_E0;		/* enable match on timer 0 to cause interrupts */
 	OSMR0 = OSCR + LATCH;	/* set initial match */
 	local_irq_restore(flags);
+
+	cksrc_sa1100_oscr.mult =
+		clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_sa1100_oscr.shift);
+
+	clocksource_register(&cksrc_sa1100_oscr);
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -182,7 +181,6 @@
 	.init		= sa1100_timer_init,
 	.suspend	= sa1100_timer_suspend,
 	.resume		= sa1100_timer_resume,
-	.offset		= sa1100_gettimeoffset,
 #ifdef CONFIG_NO_IDLE_HZ
 	.dyn_tick	= &sa1100_dyn_tick,
 #endif
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index a0545db..09d9f33 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -82,9 +82,7 @@
 static irqreturn_t
 shark_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
 	timer_tick();
-	write_sequnlock(&xtime_lock);
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7868f4d..cb104c2 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -171,8 +171,8 @@
 # ARM926T
 config CPU_ARM926T
 	bool "Support ARM926T processor"
-	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_NS9XXX || ARCH_DAVINCI
-	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_NS9XXX || ARCH_DAVINCI
+	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
+	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || ARCH_NS9XXX || ARCH_DAVINCI
 	select CPU_32v5
 	select CPU_ABRT_EV5TJ
 	select CPU_CACHE_VIVT
@@ -345,8 +345,9 @@
 # ARMv6
 config CPU_V6
 	bool "Support ARM V6 processor"
-	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
+	depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM7X00A
 	default y if ARCH_MX3
+	default y if ARCH_MSM7X00A
 	select CPU_32v6
 	select CPU_ABRT_EV6
 	select CPU_CACHE_V6
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index a8a7dab..28ad7ab 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -12,6 +12,7 @@
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -20,6 +21,29 @@
 
 #include "fault.h"
 
+
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
+{
+	int ret = 0;
+
+	if (!user_mode(regs)) {
+		/* kprobe_running() needs smp_processor_id() */
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, fsr))
+			ret = 1;
+		preempt_enable();
+	}
+
+	return ret;
+}
+#else
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
+{
+	return 0;
+}
+#endif
+
 /*
  * This is useful to dump out the page tables associated with
  * 'addr' in mm 'mm'.
@@ -215,13 +239,16 @@
 	return fault;
 }
 
-static int
+static int __kprobes
 do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	int fault, sig, code;
 
+	if (notify_page_fault(regs, fsr))
+		return 0;
+
 	tsk = current;
 	mm  = tsk->mm;
 
@@ -311,7 +338,7 @@
  * interrupt or a critical region, and should only copy the information
  * from the master page table, nothing more.
  */
-static int
+static int __kprobes
 do_translation_fault(unsigned long addr, unsigned int fsr,
 		     struct pt_regs *regs)
 {
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 0360b1f..45a77df 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -212,7 +212,7 @@
 
 static irqreturn_t mbox_interrupt(int irq, void *p)
 {
-	struct omap_mbox *mbox = (struct omap_mbox *)p;
+	struct omap_mbox *mbox = p;
 
 	if (is_mbox_irq(mbox, IRQ_TX))
 		__mbox_tx_interrupt(mbox);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index f7b9ccd..2af5bd5 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -98,9 +98,10 @@
 
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
 {
-	struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
+	struct omap_mcbsp *mcbsp_tx = dev_id;
 
-	DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+	DBG("TX IRQ callback : 0x%x\n",
+	    OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
 
 	complete(&mcbsp_tx->tx_irq_completion);
 	return IRQ_HANDLED;
@@ -108,9 +109,10 @@
 
 static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
 {
-	struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
+	struct omap_mcbsp *mcbsp_rx = dev_id;
 
-	DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+	DBG("RX IRQ callback : 0x%x\n",
+	    OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
 
 	complete(&mcbsp_rx->rx_irq_completion);
 	return IRQ_HANDLED;
@@ -118,9 +120,10 @@
 
 static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
 {
-	struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
+	struct omap_mcbsp *mcbsp_dma_tx = data;
 
-	DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+	DBG("TX DMA callback : 0x%x\n",
+	    OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
 
 	/* We can free the channels */
 	omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
@@ -131,9 +134,10 @@
 
 static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
 {
-	struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
+	struct omap_mcbsp *mcbsp_dma_rx = data;
 
-	DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+	DBG("RX DMA callback : 0x%x\n",
+	    OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
 
 	/* We can free the channels */
 	omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index 8e5ccaa..131d202 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -23,6 +23,7 @@
 
 obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o
 obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-irq.o
+obj-$(CONFIG_CPU_S3C244X)	+= s3c244x-clock.o
 obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_PM)		+= sleep.o
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index 79cda0f..99a4474 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -172,6 +172,15 @@
 	if (IS_ERR(clk))
 		return -EINVAL;
 
+	/* We do not default just do a clk->rate = rate as
+	 * the clock may have been made this way by choice.
+	 */
+
+	WARN_ON(clk->set_rate == NULL);
+
+	if (clk->set_rate == NULL)
+		return -EINVAL;
+
 	mutex_lock(&clocks_mutex);
 	ret = (clk->set_rate)(clk, rate);
 	mutex_unlock(&clocks_mutex);
@@ -213,6 +222,12 @@
 
 /* base clocks */
 
+static int clk_default_setrate(struct clk *clk, unsigned long rate)
+{
+	clk->rate = rate;
+	return 0;
+}
+
 struct clk clk_xtal = {
 	.name		= "xtal",
 	.id		= -1,
@@ -224,6 +239,7 @@
 struct clk clk_mpll = {
 	.name		= "mpll",
 	.id		= -1,
+	.set_rate	= clk_default_setrate,
 };
 
 struct clk clk_upll = {
@@ -239,6 +255,7 @@
 	.rate		= 0,
 	.parent		= &clk_mpll,
 	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
 };
 
 struct clk clk_h = {
@@ -247,6 +264,7 @@
 	.rate		= 0,
 	.parent		= NULL,
 	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
 };
 
 struct clk clk_p = {
@@ -255,6 +273,7 @@
 	.rate		= 0,
 	.parent		= NULL,
 	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
 };
 
 struct clk clk_usb_bus = {
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index aae1b9c..ac9ff16 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -525,7 +525,8 @@
 		}
 	} else if (chan->state == S3C2410_DMA_IDLE) {
 		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
-			s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
+			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+					 S3C2410_DMAOP_START);
 		}
 	}
 
@@ -787,7 +788,7 @@
 
 	pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
 
-	return 0;
+	return chan->number | DMACH_LOW_LEVEL;
 }
 
 EXPORT_SYMBOL(s3c2410_dma_request);
@@ -1173,6 +1174,7 @@
 
 	chan->source = source;
 	chan->dev_addr = devaddr;
+	chan->hw_cfg = hwcfg;
 
 	switch (source) {
 	case S3C2410_DMASRC_HW:
@@ -1184,7 +1186,7 @@
 		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
 
 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
-		return 0;
+		break;
 
 	case S3C2410_DMASRC_MEM:
 		/* source is memory */
@@ -1195,11 +1197,19 @@
 		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
 
 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
-		return 0;
+		break;
+
+	default:
+		printk(KERN_ERR "dma%d: invalid source type (%d)\n",
+		       channel, source);
+
+		return -EINVAL;
 	}
 
-	printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
-	return -EINVAL;
+	if (dma_sel.direction != NULL)
+		(dma_sel.direction)(chan, chan->map, source);
+
+	return 0;
 }
 
 EXPORT_SYMBOL(s3c2410_dma_devconfig);
@@ -1227,6 +1237,10 @@
 
 EXPORT_SYMBOL(s3c2410_dma_getposition);
 
+static struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev)
+{
+	return container_of(dev, struct s3c2410_dma_chan, dev);
+}
 
 /* system device class */
 
@@ -1234,7 +1248,7 @@
 
 static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
 {
-	struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
+	struct s3c2410_dma_chan *cp = to_dma_chan(dev);
 
 	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
 
@@ -1256,6 +1270,24 @@
 
 static int s3c2410_dma_resume(struct sys_device *dev)
 {
+	struct s3c2410_dma_chan *cp = to_dma_chan(dev);
+	unsigned int no = cp->number | DMACH_LOW_LEVEL;
+
+	/* restore channel's hardware configuration */
+
+	if (!cp->in_use)
+		return 0;
+
+	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
+
+	s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
+	s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
+
+	/* re-select the dma source for this channel */
+
+	if (cp->map != NULL)
+		dma_sel.select(cp, cp->map);
+
 	return 0;
 }
 
@@ -1445,6 +1477,7 @@
 
  found:
 	dmach = &s3c2410_chans[ch];
+	dmach->map = ch_map;
 	dma_chan_map[channel] = dmach;
 
 	/* select the channel */
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
index ec3a09c..ee99dcc 100644
--- a/arch/arm/plat-s3c24xx/gpio.c
+++ b/arch/arm/plat-s3c24xx/gpio.c
@@ -122,6 +122,19 @@
 
 EXPORT_SYMBOL(s3c2410_gpio_pullup);
 
+int s3c2410_gpio_getpull(unsigned int pin)
+{
+	void __iomem *base = S3C24XX_GPIO_BASE(pin);
+	unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+
+	if (pin < S3C2410_GPIO_BANKB)
+		return -EINVAL;
+
+	return (__raw_readl(base + 0x08) & (1L << offs)) ? 1 : 0;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getpull);
+
 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
 {
 	void __iomem *base = S3C24XX_GPIO_BASE(pin);
@@ -186,3 +199,19 @@
 }
 
 EXPORT_SYMBOL(s3c2410_gpio_getirq);
+
+int s3c2410_gpio_irq2pin(unsigned int irq)
+{
+	if (irq >= IRQ_EINT0 && irq <= IRQ_EINT3)
+		return S3C2410_GPF0 + (irq - IRQ_EINT0);
+
+	if (irq >= IRQ_EINT4 && irq <= IRQ_EINT7)
+		return S3C2410_GPF4 + (irq - IRQ_EINT4);
+
+	if (irq >= IRQ_EINT8 && irq <= IRQ_EINT23)
+		return S3C2410_GPG0 + (irq - IRQ_EINT8);
+
+	return -EINVAL;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_irq2pin);
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 8fbc884..d486f51 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -187,7 +187,7 @@
 	.set_wake	= s3c_irq_wake
 };
 
-static struct irq_chip s3c_irq_chip = {
+struct irq_chip s3c_irq_chip = {
 	.name		= "s3c",
 	.ack		= s3c_irq_ack,
 	.mask		= s3c_irq_mask,
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index 4fdb311..bf5581a 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -83,38 +83,39 @@
 	SAVE_ITEM(S3C2410_REFRESH),
 };
 
-static struct sleep_save gpio_save[] = {
-	SAVE_ITEM(S3C2410_GPACON),
-	SAVE_ITEM(S3C2410_GPADAT),
+static struct gpio_sleep {
+	void __iomem	*base;
+	unsigned int	 gpcon;
+	unsigned int	 gpdat;
+	unsigned int	 gpup;
+} gpio_save[] = {
+	[0] = {
+		.base	= S3C2410_GPACON,
+	},
+	[1] = {
+		.base	= S3C2410_GPBCON,
+	},
+	[2] = {
+		.base	= S3C2410_GPCCON,
+	},
+	[3] = {
+		.base	= S3C2410_GPDCON,
+	},
+	[4] = {
+		.base	= S3C2410_GPECON,
+	},
+	[5] = {
+		.base	= S3C2410_GPFCON,
+	},
+	[6] = {
+		.base	= S3C2410_GPGCON,
+	},
+	[7] = {
+		.base	= S3C2410_GPHCON,
+	},
+};
 
-	SAVE_ITEM(S3C2410_GPBCON),
-	SAVE_ITEM(S3C2410_GPBDAT),
-	SAVE_ITEM(S3C2410_GPBUP),
-
-	SAVE_ITEM(S3C2410_GPCCON),
-	SAVE_ITEM(S3C2410_GPCDAT),
-	SAVE_ITEM(S3C2410_GPCUP),
-
-	SAVE_ITEM(S3C2410_GPDCON),
-	SAVE_ITEM(S3C2410_GPDDAT),
-	SAVE_ITEM(S3C2410_GPDUP),
-
-	SAVE_ITEM(S3C2410_GPECON),
-	SAVE_ITEM(S3C2410_GPEDAT),
-	SAVE_ITEM(S3C2410_GPEUP),
-
-	SAVE_ITEM(S3C2410_GPFCON),
-	SAVE_ITEM(S3C2410_GPFDAT),
-	SAVE_ITEM(S3C2410_GPFUP),
-
-	SAVE_ITEM(S3C2410_GPGCON),
-	SAVE_ITEM(S3C2410_GPGDAT),
-	SAVE_ITEM(S3C2410_GPGUP),
-
-	SAVE_ITEM(S3C2410_GPHCON),
-	SAVE_ITEM(S3C2410_GPHDAT),
-	SAVE_ITEM(S3C2410_GPHUP),
-
+static struct sleep_save misc_save[] = {
 	SAVE_ITEM(S3C2410_DCLKCON),
 };
 
@@ -486,6 +487,184 @@
 	}
 }
 
+/* offsets for CON/DAT/UP registers */
+
+#define OFFS_CON	(S3C2410_GPACON - S3C2410_GPACON)
+#define OFFS_DAT	(S3C2410_GPADAT - S3C2410_GPACON)
+#define OFFS_UP		(S3C2410_GPBUP  - S3C2410_GPBCON)
+
+/* s3c2410_pm_save_gpios()
+ *
+ * Save the state of the GPIOs
+ */
+
+static void s3c2410_pm_save_gpios(void)
+{
+	struct gpio_sleep *gps = gpio_save;
+	unsigned int gpio;
+
+	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
+		void __iomem *base = gps->base;
+
+		gps->gpcon = __raw_readl(base + OFFS_CON);
+		gps->gpdat = __raw_readl(base + OFFS_DAT);
+
+		if (gpio > 0)
+			gps->gpup = __raw_readl(base + OFFS_UP);
+
+	}
+}
+
+/* Test whether the given masked+shifted bits of an GPIO configuration
+ * are one of the SFN (special function) modes. */
+
+static inline int is_sfn(unsigned long con)
+{
+	return (con == 2 || con == 3);
+}
+
+/* Test if the given masked+shifted GPIO configuration is an input */
+
+static inline int is_in(unsigned long con)
+{
+	return con == 0;
+}
+
+/* Test if the given masked+shifted GPIO configuration is an output */
+
+static inline int is_out(unsigned long con)
+{
+	return con == 1;
+}
+
+/* s3c2410_pm_restore_gpio()
+ *
+ * Restore one of the GPIO banks that was saved during suspend. This is
+ * not as simple as once thought, due to the possibility of glitches
+ * from the order that the CON and DAT registers are set in.
+ *
+ * The three states the pin can be are {IN,OUT,SFN} which gives us 9
+ * combinations of changes to check. Three of these, if the pin stays
+ * in the same configuration can be discounted. This leaves us with
+ * the following:
+ *
+ * { IN => OUT }  Change DAT first
+ * { IN => SFN }  Change CON first
+ * { OUT => SFN } Change CON first, so new data will not glitch
+ * { OUT => IN }  Change CON first, so new data will not glitch
+ * { SFN => IN }  Change CON first
+ * { SFN => OUT } Change DAT first, so new data will not glitch [1]
+ *
+ * We do not currently deal with the UP registers as these control
+ * weak resistors, so a small delay in change should not need to bring
+ * these into the calculations.
+ *
+ * [1] this assumes that writing to a pin DAT whilst in SFN will set the
+ *     state for when it is next output.
+ */
+
+static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
+{
+	void __iomem *base = gps->base;
+	unsigned long gps_gpcon = gps->gpcon;
+	unsigned long gps_gpdat = gps->gpdat;
+	unsigned long old_gpcon;
+	unsigned long old_gpdat;
+	unsigned long old_gpup = 0x0;
+	unsigned long gpcon;
+	int nr;
+
+	old_gpcon = __raw_readl(base + OFFS_CON);
+	old_gpdat = __raw_readl(base + OFFS_DAT);
+
+	if (base == S3C2410_GPACON) {
+		/* GPACON only has one bit per control / data and no PULLUPs.
+		 * GPACON[x] = 0 => Output, 1 => SFN */
+
+		/* first set all SFN bits to SFN */
+
+		gpcon = old_gpcon | gps->gpcon;
+		__raw_writel(gpcon, base + OFFS_CON);
+
+		/* now set all the other bits */
+
+		__raw_writel(gps_gpdat, base + OFFS_DAT);
+		__raw_writel(gps_gpcon, base + OFFS_CON);
+	} else {
+		unsigned long old, new, mask;
+		unsigned long change_mask = 0x0;
+
+		old_gpup = __raw_readl(base + OFFS_UP);
+
+		/* Create a change_mask of all the items that need to have
+		 * their CON value changed before their DAT value, so that
+		 * we minimise the work between the two settings.
+		 */
+
+		for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
+			old = (old_gpcon & mask) >> nr;
+			new = (gps_gpcon & mask) >> nr;
+
+			/* If there is no change, then skip */
+
+			if (old == new)
+				continue;
+
+			/* If both are special function, then skip */
+
+			if (is_sfn(old) && is_sfn(new))
+				continue;
+
+			/* Change is IN => OUT, do not change now */
+
+			if (is_in(old) && is_out(new))
+				continue;
+
+			/* Change is SFN => OUT, do not change now */
+
+			if (is_sfn(old) && is_out(new))
+				continue;
+
+			/* We should now be at the case of IN=>SFN,
+			 * OUT=>SFN, OUT=>IN, SFN=>IN. */
+
+			change_mask |= mask;
+		}
+
+		/* Write the new CON settings */
+
+		gpcon = old_gpcon & ~change_mask;
+		gpcon |= gps_gpcon & change_mask;
+
+		__raw_writel(gpcon, base + OFFS_CON);
+
+		/* Now change any items that require DAT,CON */
+
+		__raw_writel(gps_gpdat, base + OFFS_DAT);
+		__raw_writel(gps_gpcon, base + OFFS_CON);
+		__raw_writel(gps->gpup, base + OFFS_UP);
+	}
+
+	DBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n",
+	    index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+}
+
+
+/** s3c2410_pm_restore_gpios()
+ *
+ * Restore the state of the GPIOs
+ */
+
+static void s3c2410_pm_restore_gpios(void)
+{
+	struct gpio_sleep *gps = gpio_save;
+	int gpio;
+
+	for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
+		s3c2410_pm_restore_gpio(gpio, gps);
+	}
+}
+
 void (*pm_cpu_prep)(void);
 void (*pm_cpu_sleep)(void);
 
@@ -535,7 +714,8 @@
 
 	/* save all necessary core registers not covered by the drivers */
 
-	s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
+	s3c2410_pm_save_gpios();
+	s3c2410_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
 	s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
 	s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
 
@@ -585,8 +765,9 @@
 	/* restore the system state */
 
 	s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
-	s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
+	s3c2410_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
 	s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
+	s3c2410_pm_restore_gpios();
 
 	s3c2410_pm_debug_init();
 
diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
new file mode 100644
index 0000000..faf3e0f
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
@@ -0,0 +1,137 @@
+/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
+ *
+ * Copyright (c) 2004-2005,2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440/S3C2442 Common clock support
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+	unsigned long camdivn;
+	unsigned long dvs;
+
+	if (parent == &clk_f)
+		dvs = 0;
+	else if (parent == &clk_h)
+		dvs = S3C2440_CAMDIVN_DVSEN;
+	else
+		return -EINVAL;
+
+	clk->parent = parent;
+
+	camdivn  = __raw_readl(S3C2440_CAMDIVN);
+	camdivn &= ~S3C2440_CAMDIVN_DVSEN;
+	camdivn |= dvs;
+	__raw_writel(camdivn, S3C2440_CAMDIVN);
+
+	return 0;
+}
+
+static struct clk clk_arm = {
+	.name		= "armclk",
+	.id		= -1,
+	.set_parent	= s3c2440_setparent_armclk,
+};
+
+static int s3c244x_clk_add(struct sys_device *sysdev)
+{
+	unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+	unsigned long clkdivn;
+	struct clk *clock_upll;
+	int ret;
+
+	printk("S3C244X: Clock Support, DVS %s\n",
+	       (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+
+	clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f;
+
+	ret = s3c24xx_register_clock(&clk_arm);
+	if (ret < 0) {
+		printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret);
+		return ret;
+	}
+
+	clock_upll = clk_get(NULL, "upll");
+	if (IS_ERR(clock_upll)) {
+		printk(KERN_ERR "S3C244X: Failed to get upll clock\n");
+		return -ENOENT;
+	}
+
+	/* check rate of UPLL, and if it is near 96MHz, then change
+	 * to using half the UPLL rate for the system */
+
+	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
+
+		mutex_lock(&clocks_mutex);
+
+		clkdivn = __raw_readl(S3C2410_CLKDIVN);
+		clkdivn |= S3C2440_CLKDIVN_UCLK;
+		__raw_writel(clkdivn, S3C2410_CLKDIVN);
+
+		mutex_unlock(&clocks_mutex);
+	}
+
+	return 0;
+}
+
+static struct sysdev_driver s3c2440_clk_driver = {
+	.add		= s3c244x_clk_add,
+};
+
+static int s3c2440_clk_init(void)
+{
+	return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
+}
+
+arch_initcall(s3c2440_clk_init);
+
+static struct sysdev_driver s3c2442_clk_driver = {
+	.add		= s3c244x_clk_add,
+};
+
+static int s3c2442_clk_init(void)
+{
+	return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
+}
+
+arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 0a9a5e7..7ed58c0 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Fri May 11 19:53:41 2007
+# Last update: Sat Jan 26 14:45:34 2008
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -266,7 +266,7 @@
 wismo			SA1100_WISMO		WISMO			249
 ezlinx			ARCH_EZLINX		EZLINX			250
 at91rm9200		ARCH_AT91RM9200		AT91RM9200		251
-orion			ARCH_ORION		ORION			252
+adtech_orion		ARCH_ADTECH_ORION	ADTECH_ORION		252
 neptune			ARCH_NEPTUNE		NEPTUNE			253
 hackkit			SA1100_HACKKIT		HACKKIT			254
 pxa_wins30		ARCH_PXA_WINS30		PXA_WINS30		255
@@ -661,7 +661,6 @@
 pnx0105			MACH_PNX0105		PNX0105			646
 adcpoecpu		MACH_ADCPOECPU		ADCPOECPU		647
 csb637			MACH_CSB637		CSB637			648
-ml69q6203		MACH_ML69Q6203		ML69Q6203		649
 mb9200			MACH_MB9200		MB9200			650
 kulun			MACH_KULUN		KULUN			651
 snapper			MACH_SNAPPER		SNAPPER			652
@@ -953,7 +952,6 @@
 ttg_color1		MACH_TTG_COLOR1		TTG_COLOR1		940
 nxeb500hmi		MACH_NXEB500HMI		NXEB500HMI		941
 netdcu8			MACH_NETDCU8		NETDCU8			942
-ml675050_cpu_boa	MACH_ML675050_CPU_BOA	ML675050_CPU_BOA	943
 ng_fvx538		MACH_NG_FVX538		NG_FVX538		944
 ng_fvs338		MACH_NG_FVS338		NG_FVS338		945
 pnx4103			MACH_PNX4103		PNX4103			946
@@ -1148,7 +1146,7 @@
 rema			MACH_REMA		REMA			1135
 bps1000			MACH_BPS1000		BPS1000			1136
 hw90350			MACH_HW90350		HW90350			1137
-omap_sdp3430		MACH_OMAP_SDP3430	OMAP_SDP3430		1138
+omap_3430sdp		MACH_OMAP_3430SDP	OMAP_3430SDP		1138
 bluetouch		MACH_BLUETOUCH		BLUETOUCH		1139
 vstms			MACH_VSTMS		VSTMS			1140
 xsbase270		MACH_XSBASE270		XSBASE270		1141
@@ -1214,7 +1212,7 @@
 kbat9261		MACH_KBAT9261		KBAT9261		1204
 ct1100			MACH_CT1100		CT1100			1205
 akcppxa			MACH_AKCPPXA		AKCPPXA			1206
-zevio_1020		MACH_ZEVIO_1020		ZEVIO_1020		1207
+ochaya1020		MACH_OCHAYA1020		OCHAYA1020		1207
 hitrack			MACH_HITRACK		HITRACK			1208
 syme1			MACH_SYME1		SYME1			1209
 syhl1			MACH_SYHL1		SYHL1			1210
@@ -1299,7 +1297,7 @@
 h4300			MACH_H4300		H4300			1291
 goramo_mlr		MACH_GORAMO_MLR		GORAMO_MLR		1292
 mxc30020evb		MACH_MXC30020EVB	MXC30020EVB		1293
-adsbitsymx		MACH_ADSBITSIMX		ADSBITSIMX		1294
+adsbitsyg5		MACH_ADSBITSYG5		ADSBITSYG5		1294
 adsportalplus		MACH_ADSPORTALPLUS	ADSPORTALPLUS		1295
 mmsp2plus		MACH_MMSP2PLUS		MMSP2PLUS		1296
 em_x270			MACH_EM_X270		EM_X270			1297
@@ -1367,3 +1365,249 @@
 csb726			MACH_CSB726		CSB726			1359
 tik27			MACH_TIK27		TIK27			1360
 mx_uc7420		MACH_MX_UC7420		MX_UC7420		1361
+rirm3			MACH_RIRM3		RIRM3			1362
+pelco_odyssey		MACH_PELCO_ODYSSEY	PELCO_ODYSSEY		1363
+adx_abox		MACH_ADX_ABOX		ADX_ABOX		1365
+adx_tpid		MACH_ADX_TPID		ADX_TPID		1366
+minicheck		MACH_MINICHECK		MINICHECK		1367
+idam			MACH_IDAM		IDAM			1368
+mario_mx		MACH_MARIO_MX		MARIO_MX		1369
+vi1888			MACH_VI1888		VI1888			1370
+zr4230			MACH_ZR4230		ZR4230			1371
+t1_ix_blue		MACH_T1_IX_BLUE		T1_IX_BLUE		1372
+syhq2			MACH_SYHQ2		SYHQ2			1373
+computime_r3		MACH_COMPUTIME_R3	COMPUTIME_R3		1374
+oratis			MACH_ORATIS		ORATIS			1375
+mikko			MACH_MIKKO		MIKKO			1376
+holon			MACH_HOLON		HOLON			1377
+olip8			MACH_OLIP8		OLIP8			1378
+ghi270hg		MACH_GHI270HG		GHI270HG		1379
+davinci_dm6467_evm	MACH_DAVINCI_DM6467_EVM	DAVINCI_DM6467_EVM	1380
+davinci_dm355_evm	MACH_DAVINCI_DM350_EVM	DAVINCI_DM350_EVM	1381
+blackriver		MACH_BLACKRIVER		BLACKRIVER		1383
+sandgate_wp		MACH_SANDGATEWP		SANDGATEWP		1384
+cdotbwsg		MACH_CDOTBWSG		CDOTBWSG		1385
+quark963		MACH_QUARK963		QUARK963		1386
+csb735			MACH_CSB735		CSB735			1387
+littleton		MACH_LITTLETON		LITTLETON		1388
+mio_p550		MACH_MIO_P550		MIO_P550		1389
+motion2440		MACH_MOTION2440		MOTION2440		1390
+imm500			MACH_IMM500		IMM500			1391
+homematic		MACH_HOMEMATIC		HOMEMATIC		1392
+ermine			MACH_ERMINE		ERMINE			1393
+kb9202b			MACH_KB9202B		KB9202B			1394
+hs1xx			MACH_HS1XX		HS1XX			1395
+studentmate2440		MACH_STUDENTMATE2440	STUDENTMATE2440		1396
+arvoo_l1_z1		MACH_ARVOO_L1_Z1	ARVOO_L1_Z1		1397
+dep2410k		MACH_DEP2410K		DEP2410K		1398
+xxsvideo		MACH_XXSVIDEO		XXSVIDEO		1399
+im4004			MACH_IM4004		IM4004			1400
+ochaya1050		MACH_OCHAYA1050		OCHAYA1050		1401
+lep9261			MACH_LEP9261		LEP9261			1402
+svenmeb			MACH_SVENMEB		SVENMEB			1403
+fortunet2ne		MACH_FORTUNET2NE	FORTUNET2NE		1404
+nxhx			MACH_NXHX		NXHX			1406
+realview_pb11mp		MACH_REALVIEW_PB11MP	REALVIEW_PB11MP		1407
+ids500			MACH_IDS500		IDS500			1408
+ors_n725		MACH_ORS_N725		ORS_N725		1409
+hsdarm			MACH_HSDARM		HSDARM			1410
+sha_pon003		MACH_SHA_PON003		SHA_PON003		1411
+sha_pon004		MACH_SHA_PON004		SHA_PON004		1412
+sha_pon007		MACH_SHA_PON007		SHA_PON007		1413
+sha_pon011		MACH_SHA_PON011		SHA_PON011		1414
+h6042			MACH_H6042		H6042			1415
+h6043			MACH_H6043		H6043			1416
+looxc550		MACH_LOOXC550		LOOXC550		1417
+cnty_titan		MACH_CNTY_TITAN		CNTY_TITAN		1418
+app3xx			MACH_APP3XX		APP3XX			1419
+sideoatsgrama		MACH_SIDEOATSGRAMA	SIDEOATSGRAMA		1420
+xscale_palmt700p	MACH_XSCALE_PALMT700P	XSCALE_PALMT700P	1421
+xscale_palmt700w	MACH_XSCALE_PALMT700W	XSCALE_PALMT700W	1422
+xscale_palmt750		MACH_XSCALE_PALMT750	XSCALE_PALMT750		1423
+xscale_palmt755p	MACH_XSCALE_PALMT755P	XSCALE_PALMT755P	1424
+ezreganut9200		MACH_EZREGANUT9200	EZREGANUT9200		1425
+sarge			MACH_SARGE		SARGE			1426
+a696			MACH_A696		A696			1427
+turtle1916		MACH_TURTLE		TURTLE			1428
+mx27_3ds		MACH_MX27_3DS		MX27_3DS		1430
+bishop			MACH_BISHOP		BISHOP			1431
+pxx			MACH_PXX		PXX			1432
+redwood			MACH_REDWOOD		REDWOOD			1433
+omap_2430dlp		MACH_OMAP_2430DLP	OMAP_2430DLP		1436
+omap_2430osk		MACH_OMAP_2430OSK	OMAP_2430OSK		1437
+sardine			MACH_SARDINE		SARDINE			1438
+halibut			MACH_HALIBUT		HALIBUT			1439
+trout			MACH_TROUT		TROUT			1440
+goldfish		MACH_GOLDFISH		GOLDFISH		1441
+gesbc2440		MACH_GESBC2440		GESBC2440		1442
+nomad			MACH_NOMAD		NOMAD			1443
+rosalind		MACH_ROSALIND		ROSALIND		1444
+cc9p9215		MACH_CC9P9215		CC9P9215		1445
+cc9p9210		MACH_CC9P9210		CC9P9210		1446
+cc9p9215js		MACH_CC9P9215JS		CC9P9215JS		1447
+cc9p9210js		MACH_CC9P9210JS		CC9P9210JS		1448
+nasffe			MACH_NASFFE		NASFFE			1449
+tn2x0bd			MACH_TN2X0BD		TN2X0BD			1450
+gwmpxa			MACH_GWMPXA		GWMPXA			1451
+exyplus			MACH_EXYPLUS		EXYPLUS			1452
+jadoo21			MACH_JADOO21		JADOO21			1453
+looxn560		MACH_LOOXN560		LOOXN560		1454
+bonsai			MACH_BONSAI		BONSAI			1455
+adsmilgato		MACH_ADSMILGATO		ADSMILGATO		1456
+gba			MACH_GBA		GBA			1457
+h6044			MACH_H6044		H6044			1458
+app			MACH_APP		APP			1459
+tct_hammer		MACH_TCT_HAMMER		TCT_HAMMER		1460
+herald			MACH_HERMES		HERMES			1461
+artemis			MACH_ARTEMIS		ARTEMIS			1462
+htctitan		MACH_HTCTITAN		HTCTITAN		1463
+qranium			MACH_QRANIUM		QRANIUM			1464
+adx_wsc2		MACH_ADX_WSC2		ADX_WSC2		1465
+adx_medinet		MACH_ADX_MEDINET	ADX_MEDINET		1466
+bboard			MACH_BBOARD		BBOARD			1467
+cambria			MACH_CAMBRIA		CAMBRIA			1468
+mt7xxx			MACH_MT7XXX		MT7XXX			1469
+matrix512		MACH_MATRIX512		MATRIX512		1470
+matrix522		MACH_MATRIX522		MATRIX522		1471
+ipac5010		MACH_IPAC5010		IPAC5010		1472
+sakura			MACH_SAKURA		SAKURA			1473
+grocx			MACH_GROCX		GROCX			1474
+pm9263			MACH_PM9263		PM9263			1475
+sim_one			MACH_SIM_ONE		SIM_ONE			1476
+acq132			MACH_ACQ132		ACQ132			1477
+datr			MACH_DATR		DATR			1478
+actux1			MACH_ACTUX1		ACTUX1			1479
+actux2			MACH_ACTUX2		ACTUX2			1480
+actux3			MACH_ACTUX3		ACTUX3			1481
+flexit			MACH_FLEXIT		FLEXIT			1482
+bh2x0bd			MACH_BH2X0BD		BH2X0BD			1483
+atb2002			MACH_ATB2002		ATB2002			1484
+xenon			MACH_XENON		XENON			1485
+fm607			MACH_FM607		FM607			1486
+matrix514		MACH_MATRIX514		MATRIX514		1487
+matrix524		MACH_MATRIX524		MATRIX524		1488
+inpod			MACH_INPOD		INPOD			1489
+jive			MACH_JIVE		JIVE			1490
+tll_mx21		MACH_TLL_MX21		TLL_MX21		1491
+sbc2800			MACH_SBC2800		SBC2800			1492
+cc7ucamry		MACH_CC7UCAMRY		CC7UCAMRY		1493
+ubisys_p9_sc15		MACH_UBISYS_P9_SC15	UBISYS_P9_SC15		1494
+ubisys_p9_ssc2d10	MACH_UBISYS_P9_SSC2D10	UBISYS_P9_SSC2D10	1495
+ubisys_p9_rcu3		MACH_UBISYS_P9_RCU3	UBISYS_P9_RCU3		1496
+aml_m8000		MACH_AML_M8000		AML_M8000		1497
+snapper_270		MACH_SNAPPER_270	SNAPPER_270		1498
+omap_bbx		MACH_OMAP_BBX		OMAP_BBX		1499
+ucn2410			MACH_UCN2410		UCN2410			1500
+sam9_l9260		MACH_SAM9_L9260		SAM9_L9260		1501
+eti_c2			MACH_ETI_C2		ETI_C2			1502
+avalanche		MACH_AVALANCHE		AVALANCHE		1503
+realview_pb1176		MACH_REALVIEW_PB1176	REALVIEW_PB1176		1504
+dp1500			MACH_DP1500		DP1500			1505
+apple_iphone		MACH_APPLE_IPHONE	APPLE_IPHONE		1506
+yl9200			MACH_YL9200		YL9200			1507
+rd88f5182		MACH_RD88F5182		RD88F5182		1508
+kurobox_pro		MACH_KUROBOX_PRO	KUROBOX_PRO		1509
+se_poet			MACH_SE_POET		SE_POET			1510
+mx31_3ds		MACH_MX31_3DS		MX31_3DS		1511
+r270			MACH_R270		R270			1512
+armour21		MACH_ARMOUR21		ARMOUR21		1513
+dt2			MACH_DT2		DT2			1514
+vt4			MACH_VT4		VT4			1515
+tyco320			MACH_TYCO320		TYCO320			1516
+adma			MACH_ADMA		ADMA			1517
+wp188			MACH_WP188		WP188			1518
+corsica			MACH_CORSICA		CORSICA			1519
+bigeye			MACH_BIGEYE		BIGEYE			1520
+tll5000			MACH_TLL5000		TLL5000			1522
+hni270			MACH_HNI_X270		HNI_X270		1523
+qong			MACH_QONG		QONG			1524
+tcompact		MACH_TCOMPACT		TCOMPACT		1525
+puma5			MACH_PUMA5		PUMA5			1526
+elara			MACH_ELARA		ELARA			1527
+ellington		MACH_ELLINGTON		ELLINGTON		1528
+xda_atom		MACH_XDA_ATOM		XDA_ATOM		1529
+energizer2		MACH_ENERGIZER2		ENERGIZER2		1530
+odin			MACH_ODIN		ODIN			1531
+actux4			MACH_ACTUX4		ACTUX4			1532
+esl_omap		MACH_ESL_OMAP		ESL_OMAP		1533
+omap2evm		MACH_OMAP2EVM		OMAP2EVM		1534
+omap3evm		MACH_OMAP3EVM		OMAP3EVM		1535
+adx_pcu57		MACH_ADX_PCU57		ADX_PCU57		1536
+monaco			MACH_MONACO		MONACO			1537
+levante			MACH_LEVANTE		LEVANTE			1538
+tmxipx425		MACH_TMXIPX425		TMXIPX425		1539
+leep			MACH_LEEP		LEEP			1540
+raad			MACH_RAAD		RAAD			1541
+dns323			MACH_DNS323		DNS323			1542
+ap1000			MACH_AP1000		AP1000			1543
+a9sam6432		MACH_A9SAM6432		A9SAM6432		1544
+shiny			MACH_SHINY		SHINY			1545
+omap3_beagle		MACH_OMAP3_BEAGLE	OMAP3_BEAGLE		1546
+csr_bdb2		MACH_CSR_BDB2		CSR_BDB2		1547
+nokia_n810		MACH_NOKIA_N810		NOKIA_N810		1548
+c270			MACH_C270		C270			1549
+sentry			MACH_SENTRY		SENTRY			1550
+pcm038			MACH_PCM038		PCM038			1551
+anc300			MACH_ANC300		ANC300			1552
+htckaiser		MACH_HTCKAISER		HTCKAISER		1553
+sbat100			MACH_SBAT100		SBAT100			1554
+modunorm		MACH_MODUNORM		MODUNORM		1555
+pelos_twarm		MACH_PELOS_TWARM	PELOS_TWARM		1556
+flank			MACH_FLANK		FLANK			1557
+sirloin			MACH_SIRLOIN		SIRLOIN			1558
+brisket			MACH_BRISKET		BRISKET			1559
+chuck			MACH_CHUCK		CHUCK			1560
+otter			MACH_OTTER		OTTER			1561
+davinci_ldk		MACH_DAVINCI_LDK	DAVINCI_LDK		1562
+phreedom		MACH_PHREEDOM		PHREEDOM		1563
+sg310			MACH_SG310		SG310			1564
+ts_x09			MACH_TS209		TS209			1565
+at91cap9adk		MACH_AT91CAP9ADK	AT91CAP9ADK		1566
+tion9315		MACH_TION9315		TION9315		1567
+mast			MACH_MAST		MAST			1568
+pfw			MACH_PFW		PFW			1569
+yl_p2440		MACH_YL_P2440		YL_P2440		1570
+zsbc32			MACH_ZSBC32		ZSBC32			1571
+omap_pace2		MACH_OMAP_PACE2		OMAP_PACE2		1572
+imx_pace2		MACH_IMX_PACE2		IMX_PACE2		1573
+mx31moboard		MACH_MX31MOBOARD	MX31MOBOARD		1574
+mx37_3ds		MACH_MX37_3DS		MX37_3DS		1575
+rcc			MACH_RCC		RCC			1576
+dmp			MACH_ARM9		ARM9			1577
+vision_ep9307		MACH_VISION_EP9307	VISION_EP9307		1578
+scly1000		MACH_SCLY1000		SCLY1000		1579
+fontel_ep		MACH_FONTEL_EP		FONTEL_EP		1580
+voiceblue3g		MACH_VOICEBLUE3G	VOICEBLUE3G		1581
+tt9200			MACH_TT9200		TT9200			1582
+digi2410		MACH_DIGI2410		DIGI2410		1583
+terastation_pro2	MACH_TERASTATION_PRO2	TERASTATION_PRO2	1584
+linkstation_pro		MACH_LINKSTATION_PRO	LINKSTATION_PRO		1585
+motorola_a780		MACH_MOTOROLA_A780	MOTOROLA_A780		1587
+motorola_e6		MACH_MOTOROLA_E6	MOTOROLA_E6		1588
+motorola_e2		MACH_MOTOROLA_E2	MOTOROLA_E2		1589
+motorola_e680		MACH_MOTOROLA_E680	MOTOROLA_E680		1590
+ur2410			MACH_UR2410		UR2410			1591
+tas9261			MACH_TAS9261		TAS9261			1592
+davinci_hermes_hd	MACH_HERMES_HD		HERMES_HD		1593
+davinci_perseo_hd	MACH_PERSEO_HD		PERSEO_HD		1594
+stargazer2		MACH_STARGAZER2		STARGAZER2		1595
+e350			MACH_E350		E350			1596
+wpcm450			MACH_WPCM450		WPCM450			1597
+cartesio		MACH_CARTESIO		CARTESIO		1598
+toybox			MACH_TOYBOX		TOYBOX			1599
+tx27			MACH_TX27		TX27			1600
+ts409			MACH_TS409		TS409			1601
+p300			MACH_P300		P300			1602
+xdacomet		MACH_XDACOMET		XDACOMET		1603
+dexflex2		MACH_DEXFLEX2		DEXFLEX2		1604
+ow			MACH_OW			OW			1605
+armebs3			MACH_ARMEBS3		ARMEBS3			1606
+u3			MACH_U3			U3			1607
+smdk2450		MACH_SMDK2450		SMDK2450		1608
+rsi_ews			MACH_RSI_EWS		RSI_EWS			1609
+tnb			MACH_TNB		TNB			1610
+toepath			MACH_TOEPATH		TOEPATH			1611
+kb9263			MACH_KB9263		KB9263			1612
+mt7108			MACH_MT7108		MT7108			1613
+smtr2440		MACH_SMTR2440		SMTR2440		1614
+manao			MACH_MANAO		MANAO			1615
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 791d023..c85860b 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -265,7 +265,11 @@
  * which returns (double)0.0.  This is useful for the compare with
  * zero instructions.
  */
+#ifdef CONFIG_VFPv3
+#define VFP_REG_ZERO	32
+#else
 #define VFP_REG_ZERO	16
+#endif
 extern u64 vfp_get_double(unsigned int reg);
 extern void vfp_put_double(u64 val, unsigned int reg);
 
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 0ac022f..353f9e5 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -99,12 +99,12 @@
 	DBGSTR1	"save old state %p", r4
 	cmp	r4, #0
 	beq	no_old_VFP_process
+	VFPFSTMIA r4, r5		@ save the working registers
 	VFPFMRX	r5, FPSCR		@ current status
-	VFPFMRX	r6, FPINST		@ FPINST (always there, rev0 onwards)
-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to read?
-	VFPFMRX	r8, FPINST2, NE		@ FPINST2 if needed - avoids reading
-					@ nonexistant reg on rev0
-	VFPFSTMIA r4 			@ save the working registers
+	tst	r1, #FPEXC_EX		@ is there additional state to save?
+	VFPFMRX	r6, FPINST, NE		@ FPINST (only if FPEXC.EX is set)
+	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to read?
+	VFPFMRX	r8, FPINST2, NE		@ FPINST2 if needed (and present)
 	stmia	r4, {r1, r5, r6, r8}	@ save FPEXC, FPSCR, FPINST, FPINST2
 					@ and point r4 at the word at the
 					@ start of the register dump
@@ -114,13 +114,13 @@
 	DBGSTR1	"load state %p", r10
 	str	r10, [r3, r11, lsl #2]	@ update the last_VFP_context pointer
 					@ Load the saved state back into the VFP
-	VFPFLDMIA r10	 		@ reload the working registers while
+	VFPFLDMIA r10, r5		@ reload the working registers while
 					@ FPEXC is in a safe state
 	ldmia	r10, {r1, r5, r6, r8}	@ load FPEXC, FPSCR, FPINST, FPINST2
-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to write?
-	VFPFMXR	FPINST2, r8, NE		@ FPINST2 if needed - avoids writing
-					@ nonexistant reg on rev0
-	VFPFMXR	FPINST, r6
+	tst	r1, #FPEXC_EX		@ is there additional state to restore?
+	VFPFMXR	FPINST, r6, NE		@ restore FPINST (only if FPEXC.EX is set)
+	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to write?
+	VFPFMXR	FPINST2, r8, NE		@ FPINST2 if needed (and present)
 	VFPFMXR	FPSCR, r5		@ restore status
 
 check_for_exception:
@@ -136,10 +136,14 @@
 
 
 look_for_VFP_exceptions:
-	tst	r1, #FPEXC_EX
+	@ Check for synchronous or asynchronous exception
+	tst	r1, #FPEXC_EX | FPEXC_DEX
 	bne	process_exception
+	@ On some implementations of the VFP subarch 1, setting FPSCR.IXE
+	@ causes all the CDP instructions to be bounced synchronously without
+	@ setting the FPEXC.EX bit
 	VFPFMRX	r5, FPSCR
-	tst	r5, #FPSCR_IXE		@ IXE doesn't set FPEXC_EX !
+	tst	r5, #FPSCR_IXE
 	bne	process_exception
 
 	@ Fall into hand on to next handler - appropriate coproc instr
@@ -150,10 +154,6 @@
 
 process_exception:
 	DBGSTR	"bounce"
-	sub	r2, r2, #4
-	str	r2, [sp, #S_PC]		@ retry the instruction on exit from
-					@ the imprecise exception handling in
-					@ the support code
 	mov	r2, sp			@ nothing stacked - regdump is at TOS
 	mov	lr, r9			@ setup for a return to the user code.
 
@@ -161,7 +161,7 @@
 	@   r0 holds the trigger instruction
 	@   r1 holds the FPEXC value
 	@   r2 pointer to register dump
-	b	VFP9_bounce		@ we have handled this - the support
+	b	VFP_bounce		@ we have handled this - the support
 					@ code will raise an exception if
 					@ required. If not, the user code will
 					@ retry the faulted instruction
@@ -174,12 +174,12 @@
 	@ r0 - save location
 	@ r1 - FPEXC
 	DBGSTR1	"save VFP state %p", r0
+	VFPFSTMIA r0, r2		@ save the working registers
 	VFPFMRX	r2, FPSCR		@ current status
-	VFPFMRX	r3, FPINST		@ FPINST (always there, rev0 onwards)
-	tst	r1, #FPEXC_FPV2		@ is there an FPINST2 to read?
-	VFPFMRX	r12, FPINST2, NE	@ FPINST2 if needed - avoids reading
-					@ nonexistant reg on rev0
-	VFPFSTMIA r0 			@ save the working registers
+	tst	r1, #FPEXC_EX		@ is there additional state to save?
+	VFPFMRX	r3, FPINST, NE		@ FPINST (only if FPEXC.EX is set)
+	tstne	r1, #FPEXC_FP2V		@ is there an FPINST2 to read?
+	VFPFMRX	r12, FPINST2, NE	@ FPINST2 if needed (and present)
 	stmia	r0, {r1, r2, r3, r12}	@ save FPEXC, FPSCR, FPINST, FPINST2
 	mov	pc, lr
 #endif
@@ -217,8 +217,15 @@
 	fmrrd	r0, r1, d\dr
 	mov	pc, lr
 	.endr
+#ifdef CONFIG_VFPv3
+	@ d16 - d31 registers
+	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	mrrc	p11, 3, r0, r1, c\dr	@ fmrrd	r0, r1, d\dr
+	mov	pc, lr
+	.endr
+#endif
 
-	@ virtual register 16 for compare with zero
+	@ virtual register 16 (or 32 if VFPv3) for compare with zero
 	mov	r0, #0
 	mov	r1, #0
 	mov	pc, lr
@@ -231,3 +238,10 @@
 	fmdrr	d\dr, r0, r1
 	mov	pc, lr
 	.endr
+#ifdef CONFIG_VFPv3
+	@ d16 - d31 registers
+	.irp	dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+	mcrr	p11, 3, r1, r2, c\dr	@ fmdrr	r1, r2, d\dr
+	mov	pc, lr
+	.endr
+#endif
diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h
index 7f343a4..15b95b5 100644
--- a/arch/arm/vfp/vfpinstr.h
+++ b/arch/arm/vfp/vfpinstr.h
@@ -52,11 +52,11 @@
 #define FEXT_TO_IDX(inst)	((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
 
 #define vfp_get_sd(inst)	((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
-#define vfp_get_dd(inst)	((inst & 0x0000f000) >> 12)
+#define vfp_get_dd(inst)	((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
 #define vfp_get_sm(inst)	((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
-#define vfp_get_dm(inst)	((inst & 0x0000000f))
+#define vfp_get_dm(inst)	((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
 #define vfp_get_sn(inst)	((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
-#define vfp_get_dn(inst)	((inst & 0x000f0000) >> 16)
+#define vfp_get_dn(inst)	((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
 
 #define vfp_single(inst)	(((inst) & 0x0000f00) == 0xa00)
 
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index b4e210d..32455c6 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -125,13 +125,13 @@
 	send_sig_info(SIGFPE, &info, current);
 }
 
-static void vfp_panic(char *reason)
+static void vfp_panic(char *reason, u32 inst)
 {
 	int i;
 
 	printk(KERN_ERR "VFP: Error: %s\n", reason);
 	printk(KERN_ERR "VFP: EXC 0x%08x SCR 0x%08x INST 0x%08x\n",
-		fmrx(FPEXC), fmrx(FPSCR), fmrx(FPINST));
+		fmrx(FPEXC), fmrx(FPSCR), inst);
 	for (i = 0; i < 32; i += 2)
 		printk(KERN_ERR "VFP: s%2u: 0x%08x s%2u: 0x%08x\n",
 		       i, vfp_get_float(i), i+1, vfp_get_float(i+1));
@@ -147,19 +147,16 @@
 	pr_debug("VFP: raising exceptions %08x\n", exceptions);
 
 	if (exceptions == VFP_EXCEPTION_ERROR) {
-		vfp_panic("unhandled bounce");
+		vfp_panic("unhandled bounce", inst);
 		vfp_raise_sigfpe(0, regs);
 		return;
 	}
 
 	/*
-	 * If any of the status flags are set, update the FPSCR.
+	 * Update the FPSCR with the additional exception flags.
 	 * Comparison instructions always return at least one of
 	 * these flags set.
 	 */
-	if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
-		fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
-
 	fpscr |= exceptions;
 
 	fmxr(FPSCR, fpscr);
@@ -220,35 +217,64 @@
 /*
  * Package up a bounce condition.
  */
-void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
+void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
 {
-	u32 fpscr, orig_fpscr, exceptions, inst;
+	u32 fpscr, orig_fpscr, fpsid, exceptions;
 
 	pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
 
 	/*
-	 * Enable access to the VFP so we can handle the bounce.
+	 * At this point, FPEXC can have the following configuration:
+	 *
+	 *  EX DEX IXE
+	 *  0   1   x   - synchronous exception
+	 *  1   x   0   - asynchronous exception
+	 *  1   x   1   - sychronous on VFP subarch 1 and asynchronous on later
+	 *  0   0   1   - synchronous on VFP9 (non-standard subarch 1
+	 *                implementation), undefined otherwise
+	 *
+	 * Clear various bits and enable access to the VFP so we can
+	 * handle the bounce.
 	 */
-	fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_FPV2|FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC));
+	fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_DEX|FPEXC_FP2V|FPEXC_VV|FPEXC_TRAP_MASK));
 
+	fpsid = fmrx(FPSID);
 	orig_fpscr = fpscr = fmrx(FPSCR);
 
 	/*
-	 * If we are running with inexact exceptions enabled, we need to
-	 * emulate the trigger instruction.  Note that as we're emulating
-	 * the trigger instruction, we need to increment PC.
+	 * Check for the special VFP subarch 1 and FPSCR.IXE bit case
 	 */
-	if (fpscr & FPSCR_IXE) {
-		regs->ARM_pc += 4;
+	if ((fpsid & FPSID_ARCH_MASK) == (1 << FPSID_ARCH_BIT)
+	    && (fpscr & FPSCR_IXE)) {
+		/*
+		 * Synchronous exception, emulate the trigger instruction
+		 */
 		goto emulate;
 	}
 
-	barrier();
+	if (fpexc & FPEXC_EX) {
+		/*
+		 * Asynchronous exception. The instruction is read from FPINST
+		 * and the interrupted instruction has to be restarted.
+		 */
+		trigger = fmrx(FPINST);
+		regs->ARM_pc -= 4;
+	} else if (!(fpexc & FPEXC_DEX)) {
+		/*
+		 * Illegal combination of bits. It can be caused by an
+		 * unallocated VFP instruction but with FPSCR.IXE set and not
+		 * on VFP subarch 1.
+		 */
+		 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
+		 return;
+	}
 
 	/*
-	 * Modify fpscr to indicate the number of iterations remaining
+	 * Modify fpscr to indicate the number of iterations remaining.
+	 * If FPEXC.EX is 0, FPEXC.DEX is 1 and the FPEXC.VV bit indicates
+	 * whether FPEXC.VECITR or FPSCR.LEN is used.
 	 */
-	if (fpexc & FPEXC_EX) {
+	if (fpexc & (FPEXC_EX | FPEXC_VV)) {
 		u32 len;
 
 		len = fpexc + (1 << FPEXC_LENGTH_BIT);
@@ -262,15 +288,15 @@
 	 * FPEXC bounce reason, but this appears to be unreliable.
 	 * Emulate the bounced instruction instead.
 	 */
-	inst = fmrx(FPINST);
-	exceptions = vfp_emulate_instruction(inst, fpscr, regs);
+	exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
 	if (exceptions)
-		vfp_raise_exceptions(exceptions, inst, orig_fpscr, regs);
+		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
 
 	/*
-	 * If there isn't a second FP instruction, exit now.
+	 * If there isn't a second FP instruction, exit now. Note that
+	 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
 	 */
-	if (!(fpexc & FPEXC_FPV2))
+	if (fpexc ^ (FPEXC_EX | FPEXC_FP2V))
 		return;
 
 	/*
@@ -279,10 +305,9 @@
 	 */
 	barrier();
 	trigger = fmrx(FPINST2);
-	orig_fpscr = fpscr = fmrx(FPSCR);
 
  emulate:
-	exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
+	exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
 	if (exceptions)
 		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
 }
@@ -306,16 +331,9 @@
 {
 	unsigned int vfpsid;
 	unsigned int cpu_arch = cpu_architecture();
-	u32 access = 0;
 
-	if (cpu_arch >= CPU_ARCH_ARMv6) {
-		access = get_copro_access();
-
-		/*
-		 * Enable full access to VFP (cp10 and cp11)
-		 */
-		set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
-	}
+	if (cpu_arch >= CPU_ARCH_ARMv6)
+		vfp_enable(NULL);
 
 	/*
 	 * First check that there is a VFP that we can use.
@@ -329,15 +347,9 @@
 	vfp_vector = vfp_null_entry;
 
 	printk(KERN_INFO "VFP support v0.3: ");
-	if (VFP_arch) {
+	if (VFP_arch)
 		printk("not present\n");
-
-		/*
-		 * Restore the copro access register.
-		 */
-		if (cpu_arch >= CPU_ARCH_ARMv6)
-			set_copro_access(access);
-	} else if (vfpsid & FPSID_NODOUBLE) {
+	else if (vfpsid & FPSID_NODOUBLE) {
 		printk("no double precision support\n");
 	} else {
 		smp_call_function(vfp_enable, NULL, 1, 1);
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 25232ba..fc7ca86 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -85,11 +85,26 @@
 	help
 	  BF522 Processor Support.
 
+config BF523
+	bool "BF523"
+	help
+	  BF523 Processor Support.
+
+config BF524
+	bool "BF524"
+	help
+	  BF524 Processor Support.
+
 config BF525
 	bool "BF525"
 	help
 	  BF525 Processor Support.
 
+config BF526
+	bool "BF526"
+	help
+	  BF526 Processor Support.
+
 config BF527
 	bool "BF527"
 	help
@@ -198,7 +213,7 @@
 
 config BF52x
 	bool
-	depends on (BF522 || BF525 || BF527)
+	depends on (BF522 || BF523 || BF524 || BF525 || BF526 || BF527)
 	default y
 
 config BF53x
@@ -253,11 +268,6 @@
 	depends on (BFIN527_EZKIT)
 	default y
 
-config BFIN_SHARED_FLASH_ENET
-	bool
-	depends on (BFIN533_STAMP)
-	default y
-
 source "arch/blackfin/mach-bf527/Kconfig"
 source "arch/blackfin/mach-bf533/Kconfig"
 source "arch/blackfin/mach-bf561/Kconfig"
@@ -317,7 +327,7 @@
 	range 1 64
 	default "22" if BFIN533_EZKIT
 	default "45" if BFIN533_STAMP
-	default "20" if (BFIN537_STAMP || BFIN527_EZKIT)
+	default "20" if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
 	default "22" if BFIN533_BLUETECHNIX_CM
 	default "20" if BFIN537_BLUETECHNIX_CM
 	default "20" if BFIN561_BLUETECHNIX_CM
@@ -354,7 +364,7 @@
 	range 1 15
 	default 5 if BFIN533_EZKIT
 	default 5 if BFIN533_STAMP
-	default 4 if (BFIN537_STAMP || BFIN527_EZKIT)
+	default 4 if (BFIN537_STAMP || BFIN527_EZKIT || BFIN548_EZKIT)
 	default 5 if BFIN533_BLUETECHNIX_CM
 	default 4 if BFIN537_BLUETECHNIX_CM
 	default 4 if BFIN561_BLUETECHNIX_CM
@@ -371,7 +381,10 @@
 config MAX_VCO_HZ
 	int
 	default 600000000 if BF522
+	default 400000000 if BF523
+	default 400000000 if BF524
 	default 600000000 if BF525
+	default 400000000 if BF526
 	default 600000000 if BF527
 	default 400000000 if BF531
 	default 400000000 if BF532
@@ -383,6 +396,8 @@
 	default 533333333 if BF539
 	default 600000000 if BF542
 	default 533333333 if BF544
+	default 600000000 if BF547
+	default 600000000 if BF548
 	default 533333333 if BF549
 	default 600000000 if BF561
 
@@ -409,6 +424,7 @@
 	default  32 if BFIN533_EZKIT
 	default  64 if BFIN527_EZKIT
 	default  64 if BFIN537_STAMP
+	default  64 if BFIN548_EZKIT
 	default  64 if BFIN561_EZKIT
 	default 128 if BFIN533_STAMP
 	default  64 if PNAV10
@@ -416,6 +432,7 @@
 
 config MEM_ADD_WIDTH
 	int "SDRAM Memory Address Width"
+	depends on (!BF54x)
 	default  9 if BFIN533_EZKIT
 	default  9 if BFIN561_EZKIT
 	default  9 if H8606_HVSISTEMAS
@@ -424,6 +441,19 @@
 	default 11 if BFIN533_STAMP
 	default 10 if PNAV10
 
+
+choice
+	prompt "DDR SDRAM Chip Type"
+	depends on BFIN548_EZKIT
+	default MEM_MT46V32M16_5B
+
+config MEM_MT46V32M16_6T
+        bool "MT46V32M16_6T"
+
+config MEM_MT46V32M16_5B
+        bool "MT46V32M16_5B"
+endchoice
+
 config ENET_FLASH_PIN
 	int "PF port/pin used for flash and ethernet sharing"
 	depends on (BFIN533_STAMP)
@@ -448,40 +478,6 @@
 	  memory region is used to capture NULL pointer references as well
 	  as some core kernel functions.
 
-comment "LED Status Indicators"
-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
-
-config BFIN_ALIVE_LED
-	bool "Enable Board Alive"
-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
-	default n
-	help
-	  Blink the LEDs you select when the kernel is running.  Helps detect
-	  a hung kernel.
-
-config BFIN_ALIVE_LED_NUM
-	int "LED"
-	depends on BFIN_ALIVE_LED
-	range 1 3 if BFIN533_STAMP
-	default "3" if BFIN533_STAMP
-	help
-	  Select the LED (marked on the board) for you to blink.
-
-config BFIN_IDLE_LED
-	bool "Enable System Load/Idle LED"
-	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
-	default n
-	help
-	  Blinks the LED you select when to determine kernel load.
-
-config BFIN_IDLE_LED_NUM
-	int "LED"
-	depends on BFIN_IDLE_LED
-	range 1 3 if BFIN533_STAMP
-	default "2" if BFIN533_STAMP
-	help
-	  Select the LED (marked on the board) for you to blink.
-
 choice
 	prompt "Blackfin Exception Scratch Register"
 	default BFIN_SCRATCH_REG_RETN
@@ -528,41 +524,6 @@
 
 endchoice
 
-#
-# Sorry - but you need to put the hex address here -
-#
-
-# Flag Data register
-config BFIN_ALIVE_LED_PORT
-	hex
-	default 0xFFC00700 if (BFIN533_STAMP)
-
-# Peripheral Flag Direction Register
-config BFIN_ALIVE_LED_DPORT
-	hex
-	default 0xFFC00730 if (BFIN533_STAMP)
-
-config BFIN_ALIVE_LED_PIN
-	hex
-	default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
-	default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
-	default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
-
-config BFIN_IDLE_LED_PORT
-	hex
-	default 0xFFC00700 if (BFIN533_STAMP)
-
-# Peripheral Flag Direction Register
-config BFIN_IDLE_LED_DPORT
-	hex
-	default 0xFFC00730 if (BFIN533_STAMP)
-
-config BFIN_IDLE_LED_PIN
-	hex
-	default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
-	default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
-	default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
-
 endmenu
 
 
@@ -799,6 +760,15 @@
 	  Set the max memory pieces for the L1 SRAM allocation algorithm.
 	  Min value is 16. Max value is 1024.
 
+
+config MPU
+	bool "Enable the memory protection unit (EXPERIMENTAL)"
+	default n
+	help
+	  Use the processor's MPU to protect applications from accessing
+	  memory they do not own.  This comes at a performance penalty
+	  and is recommended only for debugging.
+
 comment "Asynchonous Memory Configuration"
 
 menu "EBIU_AMGCTL Global Control"
@@ -808,7 +778,6 @@
 
 config C_CDPRIO
 	bool "DMA has priority over core for ext. accesses"
-	depends on !BF54x
 	default n
 
 config C_B0PEN
@@ -949,8 +918,10 @@
 config PM_WAKEUP_SIC_IWR
 	hex "Wakeup Events (SIC_IWR)"
 	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
-	default 0x80000000 if (BF537 || BF536 || BF534)
-	default 0x100000 if (BF533 || BF532 || BF531)
+	default 0x8 if (BF537 || BF536 || BF534)
+	default 0x80 if (BF533 || BF532 || BF531)
+	default 0x80 if (BF54x)
+	default 0x80 if (BF52x)
 
 config PM_WAKEUP_GPIO_NUMBER
 	int "Wakeup GPIO number"
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index c47e000..0edc402 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -21,7 +21,10 @@
 
 # setup the machine name and the machine dependent settings
 machine-$(CONFIG_BF522) := bf527
+machine-$(CONFIG_BF523) := bf527
+machine-$(CONFIG_BF524) := bf527
 machine-$(CONFIG_BF525) := bf527
+machine-$(CONFIG_BF526) := bf527
 machine-$(CONFIG_BF527) := bf527
 machine-$(CONFIG_BF531) := bf533
 machine-$(CONFIG_BF532) := bf533
@@ -39,7 +42,10 @@
 export MACHINE
 
 cpu-$(CONFIG_BF522) := bf522
+cpu-$(CONFIG_BF523) := bf523
+cpu-$(CONFIG_BF524) := bf524
 cpu-$(CONFIG_BF525) := bf525
+cpu-$(CONFIG_BF526) := bf526
 cpu-$(CONFIG_BF527) := bf527
 cpu-$(CONFIG_BF531) := bf531
 cpu-$(CONFIG_BF532) := bf532
@@ -76,6 +82,12 @@
 core-y   += arch/$(ARCH)/mach-$(MACHINE)/boards/
 endif
 
+ifeq ($(CONFIG_MPU),y)
+core-y	+= arch/$(ARCH)/kernel/cplb-mpu/
+else
+core-y	+= arch/$(ARCH)/kernel/cplb-nompu/
+endif
+
 libs-y   += arch/$(ARCH)/lib/
 
 drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index fa6eb4e..d59ee15 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -1,6 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.14
+# Thu Nov 29 17:32:47 2007
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -153,8 +154,8 @@
 CONFIG_BF527_SPORT0_PORTG=y
 CONFIG_BF527_SPORT0_TSCLK_PG10=y
 # CONFIG_BF527_SPORT0_TSCLK_PG14 is not set
-# CONFIG_BF527_UART1_PORTF is not set
-CONFIG_BF527_UART1_PORTG=y
+CONFIG_BF527_UART1_PORTF=y
+# CONFIG_BF527_UART1_PORTG is not set
 # CONFIG_BF527_NAND_D_PORTF is not set
 CONFIG_BF527_NAND_D_PORTH=y
 
@@ -232,7 +233,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=600000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -626,8 +627,8 @@
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -1183,7 +1184,7 @@
 #
 # CONFIG_PRINTK_TIME is not set
 CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
@@ -1208,7 +1209,7 @@
 # CONFIG_KEYS is not set
 CONFIG_SECURITY=y
 # CONFIG_SECURITY_NETWORK is not set
-CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_CAPABILITIES=m
 
 #
 # Cryptographic options
@@ -1219,7 +1220,7 @@
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
+CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index 4fdb493..811711f 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.16
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -115,7 +115,10 @@
 # Processor and Board Settings
 #
 # CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
 # CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
 # CONFIG_BF527 is not set
 # CONFIG_BF531 is not set
 # CONFIG_BF532 is not set
@@ -194,7 +197,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=750000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -267,6 +270,7 @@
 # CONFIG_BFIN_WB is not set
 CONFIG_BFIN_WT=y
 CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
 
 #
 # Asynchonous Memory Configuration
@@ -321,7 +325,7 @@
 CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
 # CONFIG_PM_WAKEUP_BY_GPIO is not set
 # CONFIG_PM_WAKEUP_GPIO_API is not set
-CONFIG_PM_WAKEUP_SIC_IWR=0x100000
+CONFIG_PM_WAKEUP_SIC_IWR=0x80
 
 #
 # CPU Frequency scaling
@@ -510,7 +514,6 @@
 # CONFIG_MTD_CFI_INTELEXT is not set
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_MW320D=m
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -520,9 +523,6 @@
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_BF5xx=m
-CONFIG_BFIN_FLASH_SIZE=0x400000
-CONFIG_EBIU_FLASH_BASE=0x20000000
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -610,8 +610,8 @@
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -680,7 +680,6 @@
 CONFIG_BFIN_SPORT=y
 # CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_AD5304 is not set
-# CONFIG_BF5xx_FBDMA is not set
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index b04e8e53..9b7123c 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.16
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -115,7 +115,10 @@
 # Processor and Board Settings
 #
 # CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
 # CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
 # CONFIG_BF527 is not set
 # CONFIG_BF531 is not set
 # CONFIG_BF532 is not set
@@ -140,7 +143,6 @@
 CONFIG_BF53x=y
 CONFIG_BFIN_SINGLE_CORE=y
 CONFIG_MEM_MT48LC64M4A2FB_7E=y
-CONFIG_BFIN_SHARED_FLASH_ENET=y
 # CONFIG_BFIN533_EZKIT is not set
 CONFIG_BFIN533_STAMP=y
 # CONFIG_BFIN533_BLUETECHNIX_CM is not set
@@ -195,7 +197,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=750000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -215,18 +217,10 @@
 CONFIG_ENET_FLASH_PIN=0
 CONFIG_BOOT_LOAD=0x1000
 
-#
-# LED Status Indicators
-#
-# CONFIG_BFIN_ALIVE_LED is not set
-# CONFIG_BFIN_IDLE_LED is not set
+
 CONFIG_BFIN_SCRATCH_REG_RETN=y
 # CONFIG_BFIN_SCRATCH_REG_RETE is not set
 # CONFIG_BFIN_SCRATCH_REG_CYCLES is not set
-CONFIG_BFIN_ALIVE_LED_PORT=0xFFC00700
-CONFIG_BFIN_ALIVE_LED_DPORT=0xFFC00730
-CONFIG_BFIN_IDLE_LED_PORT=0xFFC00700
-CONFIG_BFIN_IDLE_LED_DPORT=0xFFC00730
 
 #
 # Blackfin Kernel Optimizations
@@ -279,6 +273,7 @@
 # CONFIG_BFIN_WB is not set
 CONFIG_BFIN_WT=y
 CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
 
 #
 # Asynchonous Memory Configuration
@@ -333,7 +328,7 @@
 CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
 # CONFIG_PM_WAKEUP_BY_GPIO is not set
 # CONFIG_PM_WAKEUP_GPIO_API is not set
-CONFIG_PM_WAKEUP_SIC_IWR=0x100000
+CONFIG_PM_WAKEUP_SIC_IWR=0x80
 
 #
 # CPU Frequency scaling
@@ -522,7 +517,6 @@
 # CONFIG_MTD_CFI_INTELEXT is not set
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_MW320D=m
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -532,17 +526,6 @@
 #
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_BF5xx=m
-CONFIG_BFIN_FLASH_SIZE=0x400000
-CONFIG_EBIU_FLASH_BASE=0x20000000
-
-#
-# FLASH_EBIU_AMBCTL Control
-#
-CONFIG_BFIN_FLASH_BANK_0=0x7BB0
-CONFIG_BFIN_FLASH_BANK_1=0x7BB0
-CONFIG_BFIN_FLASH_BANK_2=0x7BB0
-CONFIG_BFIN_FLASH_BANK_3=0x7BB0
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -630,8 +613,8 @@
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -687,7 +670,6 @@
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
 CONFIG_TWI_KEYPAD=m
 CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=39
 
@@ -711,8 +693,6 @@
 CONFIG_TWI_LCD=m
 CONFIG_TWI_LCD_SLAVE_ADDR=34
 # CONFIG_AD5304 is not set
-# CONFIG_BF5xx_TEA5764 is not set
-# CONFIG_BF5xx_FBDMA is not set
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
@@ -778,7 +758,6 @@
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_BLACKFIN_GPIO is not set
 # CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index f812b66..b37ccc6 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.16
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -115,7 +115,10 @@
 # Processor and Board Settings
 #
 # CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
 # CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
 # CONFIG_BF527 is not set
 # CONFIG_BF531 is not set
 # CONFIG_BF532 is not set
@@ -170,6 +173,7 @@
 CONFIG_BFIN537_STAMP=y
 # CONFIG_BFIN537_BLUETECHNIX_CM is not set
 # CONFIG_PNAV10 is not set
+# CONFIG_CAMSIG_MINOTAUR is not set
 # CONFIG_GENERIC_BF537_BOARD is not set
 
 #
@@ -201,7 +205,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=600000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -274,6 +278,7 @@
 # CONFIG_BFIN_WB is not set
 CONFIG_BFIN_WT=y
 CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
 
 #
 # Asynchonous Memory Configuration
@@ -328,7 +333,7 @@
 CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
 # CONFIG_PM_WAKEUP_BY_GPIO is not set
 # CONFIG_PM_WAKEUP_GPIO_API is not set
-CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
+CONFIG_PM_WAKEUP_SIC_IWR=0x8
 
 #
 # CPU Frequency scaling
@@ -483,7 +488,7 @@
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
 
 #
 # User Modules And Translation Layers
@@ -500,8 +505,8 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
-CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
@@ -515,9 +520,9 @@
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
+CONFIG_MTD_CFI_AMDSTD=m
 # CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_MW320D=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -525,11 +530,11 @@
 #
 # Mapping drivers for chip access
 #
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-# CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_BF5xx=m
-CONFIG_BFIN_FLASH_SIZE=0x400000
-CONFIG_EBIU_FLASH_BASE=0x20000000
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x20000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -647,8 +652,8 @@
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -704,7 +709,6 @@
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
 CONFIG_TWI_KEYPAD=m
 CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72
 
@@ -728,8 +732,6 @@
 CONFIG_TWI_LCD=m
 CONFIG_TWI_LCD_SLAVE_ADDR=34
 # CONFIG_AD5304 is not set
-# CONFIG_BF5xx_TEA5764 is not set
-# CONFIG_BF5xx_FBDMA is not set
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
@@ -802,7 +804,6 @@
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_BLACKFIN_GPIO is not set
 CONFIG_I2C_BLACKFIN_TWI=m
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
 # CONFIG_I2C_GPIO is not set
@@ -957,6 +958,7 @@
 # CONFIG_FB_BFIN_LANDSCAPE is not set
 # CONFIG_FB_BFIN_BGR is not set
 # CONFIG_FB_BFIN_T350MCQB is not set
+# CONFIG_FB_HITACHI_TX09 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_LOGO is not set
@@ -1008,12 +1010,22 @@
 #
 # System on Chip audio support
 #
-# CONFIG_SND_SOC is not set
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_SOC=m
+CONFIG_SND_BF5XX_SOC=m
+CONFIG_SND_BF5XX_SOC_AC97=m
+# CONFIG_SND_BF5XX_SOC_WM8750 is not set
+# CONFIG_SND_BF5XX_SOC_WM8731 is not set
+CONFIG_SND_BF5XX_SOC_BF5xx=m
+CONFIG_SND_BF5XX_SPORT_NUM=0
+# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_SOC_AD1980=m
 
 #
 # Open Sound System
 #
 # CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
 
 #
 # HID Devices
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index 48367cc9..fd70216 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.16
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -115,7 +115,10 @@
 # Processor and Board Settings
 #
 # CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
 # CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
 # CONFIG_BF527 is not set
 # CONFIG_BF531 is not set
 # CONFIG_BF532 is not set
@@ -126,8 +129,8 @@
 # CONFIG_BF542 is not set
 # CONFIG_BF544 is not set
 # CONFIG_BF547 is not set
-# CONFIG_BF548 is not set
-CONFIG_BF549=y
+CONFIG_BF548=y
+# CONFIG_BF549 is not set
 # CONFIG_BF561 is not set
 CONFIG_BF_REV_0_0=y
 # CONFIG_BF_REV_0_1 is not set
@@ -265,9 +268,9 @@
 #
 CONFIG_CLKIN_HZ=25000000
 # CONFIG_BFIN_KERNEL_CLOCK is not set
-CONFIG_MAX_VCO_HZ=533000000
+CONFIG_MAX_VCO_HZ=600000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -283,7 +286,8 @@
 # Memory Setup
 #
 CONFIG_MEM_SIZE=64
-CONFIG_MEM_ADD_WIDTH=10
+# CONFIG_MEM_MT46V32M16_6T is not set
+CONFIG_MEM_MT46V32M16_5B=y
 CONFIG_BOOT_LOAD=0x1000
 CONFIG_BFIN_SCRATCH_REG_RETN=y
 # CONFIG_BFIN_SCRATCH_REG_RETE is not set
@@ -340,6 +344,7 @@
 # CONFIG_BFIN_WB is not set
 CONFIG_BFIN_WT=y
 CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
 
 #
 # Asynchonous Memory Configuration
@@ -349,6 +354,7 @@
 # EBIU_AMGCTL Global Control
 #
 CONFIG_C_AMCKEN=y
+# CONFIG_C_CDPRIO is not set
 # CONFIG_C_AMBEN is not set
 # CONFIG_C_AMBEN_B0 is not set
 # CONFIG_C_AMBEN_B0_B1 is not set
@@ -362,9 +368,9 @@
 CONFIG_BANK_1=0x5554
 CONFIG_BANK_2=0x7BB0
 CONFIG_BANK_3=0x99B3
-CONFIG_EBUI_MBSCTLVAL=0x0
-CONFIG_EBUI_MODEVAL=0x1
-CONFIG_EBUI_FCTLVAL=0x6
+CONFIG_EBIU_MBSCTLVAL=0x0
+CONFIG_EBIU_MODEVAL=0x1
+CONFIG_EBIU_FCTLVAL=0x6
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -537,7 +543,6 @@
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
-# CONFIG_MTD_MW320D is not set
 CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
@@ -549,9 +554,8 @@
 CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_START=0x20000000
-CONFIG_MTD_PHYSMAP_LEN=0x400000
+CONFIG_MTD_PHYSMAP_LEN=0
 CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-# CONFIG_MTD_BF5xx is not set
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -690,8 +694,8 @@
 CONFIG_SMSC911X=y
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -719,7 +723,7 @@
 #
 # Input device support
 #
-CONFIG_INPUT=m
+CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
 # CONFIG_INPUT_POLLDEV is not set
 
@@ -745,7 +749,8 @@
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_GPIO is not set
-CONFIG_KEYBOARD_BFIN=m
+CONFIG_KEYBOARD_BFIN=y
+# CONFIG_KEYBOARD_OPENCORES is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
@@ -768,7 +773,6 @@
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_UINPUT is not set
-# CONFIG_BF53X_PFBUTTONS is not set
 # CONFIG_TWI_KEYPAD is not set
 
 #
@@ -786,13 +790,16 @@
 # CONFIG_BF5xx_PPIFCD is not set
 # CONFIG_BFIN_SIMPLE_TIMER is not set
 # CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_OTP=y
+# CONFIG_BFIN_OTP_WRITE_ENABLE is not set
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_TWI_LCD is not set
 # CONFIG_AD5304 is not set
-# CONFIG_BF5xx_TEA5764 is not set
-# CONFIG_BF5xx_FBDMA is not set
-# CONFIG_VT is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -858,7 +865,6 @@
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_BLACKFIN_GPIO is not set
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=50
 # CONFIG_I2C_GPIO is not set
@@ -976,12 +982,12 @@
 #
 # CONFIG_DISPLAY_SUPPORT is not set
 # CONFIG_VGASTATE is not set
-CONFIG_FB=m
+CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 # CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=m
-CONFIG_FB_CFB_COPYAREA=m
-CONFIG_FB_CFB_IMAGEBLIT=m
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_SYS_FILLRECT is not set
 # CONFIG_FB_SYS_COPYAREA is not set
 # CONFIG_FB_SYS_IMAGEBLIT is not set
@@ -998,11 +1004,34 @@
 #
 # CONFIG_FB_BFIN_7171 is not set
 # CONFIG_FB_BFIN_7393 is not set
-CONFIG_FB_BF54X_LQ043=m
+CONFIG_FB_BF54X_LQ043=y
 # CONFIG_FB_BFIN_T350MCQB is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_LOGO is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+CONFIG_FONT_6x11=y
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_BLACKFIN_VGA16 is not set
+CONFIG_LOGO_BLACKFIN_CLUT224=y
 
 #
 # Sound
@@ -1051,7 +1080,8 @@
 # CONFIG_SND_BF5XX_SOC_WM8750 is not set
 # CONFIG_SND_BF5XX_SOC_WM8731 is not set
 CONFIG_SND_BF5XX_SPORT_NUM=0
-# CONFIG_SND_BF5XX_HAVE_COLD_RESET is not set
+CONFIG_SND_BF5XX_HAVE_COLD_RESET=y
+CONFIG_SND_BF5XX_RESET_GPIO_NUM=19
 CONFIG_SND_SOC_AD1980=y
 
 #
@@ -1403,7 +1433,7 @@
 #
 # CONFIG_PRINTK_TIME is not set
 CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
@@ -1428,7 +1458,7 @@
 # CONFIG_KEYS is not set
 CONFIG_SECURITY=y
 # CONFIG_SECURITY_NETWORK is not set
-CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_CAPABILITIES=m
 
 #
 # Cryptographic options
@@ -1439,7 +1469,7 @@
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
+CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index e9f100b..8546994 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -1,6 +1,6 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22.12
+# Linux kernel version: 2.6.22.16
 #
 # CONFIG_MMU is not set
 # CONFIG_FPU is not set
@@ -115,7 +115,10 @@
 # Processor and Board Settings
 #
 # CONFIG_BF522 is not set
+# CONFIG_BF523 is not set
+# CONFIG_BF524 is not set
 # CONFIG_BF525 is not set
+# CONFIG_BF526 is not set
 # CONFIG_BF527 is not set
 # CONFIG_BF531 is not set
 # CONFIG_BF532 is not set
@@ -238,7 +241,7 @@
 # CONFIG_BFIN_KERNEL_CLOCK is not set
 CONFIG_MAX_VCO_HZ=600000000
 CONFIG_MIN_VCO_HZ=50000000
-CONFIG_MAX_SCLK_HZ=133000000
+CONFIG_MAX_SCLK_HZ=133333333
 CONFIG_MIN_SCLK_HZ=27000000
 
 #
@@ -311,6 +314,7 @@
 # CONFIG_BFIN_WB is not set
 CONFIG_BFIN_WT=y
 CONFIG_L1_MAX_PIECE=16
+# CONFIG_MPU is not set
 
 #
 # Asynchonous Memory Configuration
@@ -512,7 +516,7 @@
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
 
 #
 # User Modules And Translation Layers
@@ -529,8 +533,8 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
-CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
@@ -544,9 +548,9 @@
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
+CONFIG_MTD_CFI_AMDSTD=m
 # CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_MW320D=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=y
 CONFIG_MTD_ROM=m
 # CONFIG_MTD_ABSENT is not set
@@ -554,12 +558,11 @@
 #
 # Mapping drivers for chip access
 #
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_EZKIT561 is not set
-CONFIG_MTD_BF5xx=m
-CONFIG_BFIN_FLASH_SIZE=0x0400000
-CONFIG_EBIU_FLASH_BASE=0x20000000
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x20000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
 # CONFIG_MTD_UCLINUX is not set
 # CONFIG_MTD_PLATRAM is not set
 
@@ -647,8 +650,8 @@
 # CONFIG_SMSC911X is not set
 # CONFIG_DM9000 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
 # CONFIG_AX88180 is not set
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -717,7 +720,6 @@
 # CONFIG_BFIN_SPORT is not set
 # CONFIG_BFIN_TIMER_LATENCY is not set
 # CONFIG_AD5304 is not set
-# CONFIG_BF5xx_FBDMA is not set
 # CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index 8a4cfb2..318b9b6 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -7,7 +7,7 @@
 obj-y := \
 	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
 	sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
-	fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o
+	fixed_code.o reboot.o bfin_gpio.o
 
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
 obj-$(CONFIG_MODULES)                += module.o
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index b544460..fa9debe8 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -339,13 +339,13 @@
 
 unsigned short
 set_bfin_dma_config(char direction, char flow_mode,
-		    char intr_mode, char dma_mode, char width)
+		    char intr_mode, char dma_mode, char width, char syncmode)
 {
 	unsigned short config;
 
 	config =
 	    ((direction << 1) | (width << 2) | (dma_mode << 4) |
-	     (intr_mode << 6) | (flow_mode << 12) | RESTART);
+	     (intr_mode << 6) | (flow_mode << 12) | (syncmode << 5));
 	return config;
 }
 EXPORT_SYMBOL(set_bfin_dma_config);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index ce85d4b..6bbe0a2 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -7,7 +7,7 @@
  * Description:  GPIO Abstraction Layer
  *
  * Modified:
- *               Copyright 2007 Analog Devices Inc.
+ *               Copyright 2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -83,6 +83,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/err.h>
+#include <linux/proc_fs.h>
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
 #include <asm/portmux.h>
@@ -136,7 +137,6 @@
 	(unsigned short *) PORTG_FER,
 	(unsigned short *) PORTH_FER,
 };
-
 #endif
 
 #ifdef BF527_FAMILY
@@ -178,15 +178,13 @@
 #endif
 
 static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
-static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];
+static unsigned short reserved_peri_map[gpio_bank(MAX_RESOURCES)];
 
-#define MAX_RESOURCES 		256
 #define RESOURCE_LABEL_SIZE 	16
 
-struct str_ident {
+static struct str_ident {
 	char name[RESOURCE_LABEL_SIZE];
-} *str_ident;
-
+} str_ident[MAX_RESOURCES];
 
 #ifdef CONFIG_PM
 static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -212,7 +210,7 @@
 #endif /* CONFIG_PM */
 
 #if defined(BF548_FAMILY)
-inline int check_gpio(unsigned short gpio)
+inline int check_gpio(unsigned gpio)
 {
 	if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
 	    || gpio == GPIO_PH14 || gpio == GPIO_PH15
@@ -222,7 +220,7 @@
 	return 0;
 }
 #else
-inline int check_gpio(unsigned short gpio)
+inline int check_gpio(unsigned gpio)
 {
 	if (gpio >= MAX_BLACKFIN_GPIOS)
 		return -EINVAL;
@@ -230,9 +228,13 @@
 }
 #endif
 
+void gpio_error(unsigned gpio)
+{
+	printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio);
+}
+
 static void set_label(unsigned short ident, const char *label)
 {
-
 	if (label && str_ident) {
 		strncpy(str_ident[ident].name, label,
 			 RESOURCE_LABEL_SIZE);
@@ -250,6 +252,11 @@
 
 static int cmp_label(unsigned short ident, const char *label)
 {
+	if (label == NULL) {
+		dump_stack();
+		printk(KERN_ERR "Please provide none-null label\n");
+	}
+
 	if (label && str_ident)
 		return strncmp(str_ident[ident].name,
 				 label, strlen(label));
@@ -258,7 +265,7 @@
 }
 
 #if defined(BF527_FAMILY) || defined(BF537_FAMILY)
-static void port_setup(unsigned short gpio, unsigned short usage)
+static void port_setup(unsigned gpio, unsigned short usage)
 {
 	if (!check_gpio(gpio)) {
 		if (usage == GPIO_USAGE)
@@ -269,7 +276,7 @@
 	}
 }
 #elif defined(BF548_FAMILY)
-static void port_setup(unsigned short gpio, unsigned short usage)
+static void port_setup(unsigned gpio, unsigned short usage)
 {
 	if (usage == GPIO_USAGE)
 		gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
@@ -390,7 +397,7 @@
 #endif
 
 #ifndef BF548_FAMILY
-static void default_gpio(unsigned short gpio)
+static void default_gpio(unsigned gpio)
 {
 	unsigned short bank, bitmask;
 	unsigned long flags;
@@ -410,7 +417,6 @@
 	gpio_bankb[bank]->edge &= ~bitmask;
 	AWA_DUMMY_READ(edge);
 	local_irq_restore(flags);
-
 }
 #else
 # define default_gpio(...)  do { } while (0)
@@ -418,12 +424,6 @@
 
 static int __init bfin_gpio_init(void)
 {
-	str_ident = kcalloc(MAX_RESOURCES,
-				 sizeof(struct str_ident), GFP_KERNEL);
-	if (str_ident == NULL)
-		return -ENOMEM;
-
-	memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident));
 
 	printk(KERN_INFO "Blackfin GPIO Controller\n");
 
@@ -454,10 +454,9 @@
 /* Set a specific bit */
 
 #define SET_GPIO(name) \
-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
 	unsigned long flags; \
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
 	local_irq_save(flags); \
 	if (arg) \
 		gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
@@ -477,10 +476,9 @@
 
 #if ANOMALY_05000311 || ANOMALY_05000323
 #define SET_GPIO_SC(name) \
-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
 	unsigned long flags; \
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
 	local_irq_save(flags); \
 	if (arg) \
 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
@@ -492,9 +490,8 @@
 EXPORT_SYMBOL(set_gpio_ ## name);
 #else
 #define SET_GPIO_SC(name) \
-void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
 	if (arg) \
 		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
 	else \
@@ -508,19 +505,17 @@
 SET_GPIO_SC(data)
 
 #if ANOMALY_05000311 || ANOMALY_05000323
-void set_gpio_toggle(unsigned short gpio)
+void set_gpio_toggle(unsigned gpio)
 {
 	unsigned long flags;
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
 	local_irq_save(flags);
 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
 	AWA_DUMMY_READ(toggle);
 	local_irq_restore(flags);
 }
 #else
-void set_gpio_toggle(unsigned short gpio)
+void set_gpio_toggle(unsigned gpio)
 {
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
 	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
 }
 #endif
@@ -531,7 +526,7 @@
 
 #if ANOMALY_05000311 || ANOMALY_05000323
 #define SET_GPIO_P(name) \
-void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
 { \
 	unsigned long flags; \
 	local_irq_save(flags); \
@@ -542,7 +537,7 @@
 EXPORT_SYMBOL(set_gpiop_ ## name);
 #else
 #define SET_GPIO_P(name) \
-void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
 { \
 	gpio_bankb[gpio_bank(gpio)]->name = arg; \
 } \
@@ -558,11 +553,10 @@
 SET_GPIO_P(maska)
 SET_GPIO_P(maskb)
 
-
 /* Get a specific bit */
 #if ANOMALY_05000311 || ANOMALY_05000323
 #define GET_GPIO(name) \
-unsigned short get_gpio_ ## name(unsigned short gpio) \
+unsigned short get_gpio_ ## name(unsigned gpio) \
 { \
 	unsigned long flags; \
 	unsigned short ret; \
@@ -575,7 +569,7 @@
 EXPORT_SYMBOL(get_gpio_ ## name);
 #else
 #define GET_GPIO(name) \
-unsigned short get_gpio_ ## name(unsigned short gpio) \
+unsigned short get_gpio_ ## name(unsigned gpio) \
 { \
 	return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
 } \
@@ -595,7 +589,7 @@
 
 #if ANOMALY_05000311 || ANOMALY_05000323
 #define GET_GPIO_P(name) \
-unsigned short get_gpiop_ ## name(unsigned short gpio) \
+unsigned short get_gpiop_ ## name(unsigned gpio) \
 { \
 	unsigned long flags; \
 	unsigned short ret; \
@@ -608,7 +602,7 @@
 EXPORT_SYMBOL(get_gpiop_ ## name);
 #else
 #define GET_GPIO_P(name) \
-unsigned short get_gpiop_ ## name(unsigned short gpio) \
+unsigned short get_gpiop_ ## name(unsigned gpio) \
 { \
 	return (gpio_bankb[gpio_bank(gpio)]->name);\
 } \
@@ -645,7 +639,7 @@
 *************************************************************
 * MODIFICATION HISTORY :
 **************************************************************/
-int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
+int gpio_pm_wakeup_request(unsigned gpio, unsigned char type)
 {
 	unsigned long flags;
 
@@ -653,7 +647,6 @@
 		return -EINVAL;
 
 	local_irq_save(flags);
-
 	wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
 	wakeup_flags_map[gpio] = type;
 	local_irq_restore(flags);
@@ -662,7 +655,7 @@
 }
 EXPORT_SYMBOL(gpio_pm_wakeup_request);
 
-void gpio_pm_wakeup_free(unsigned short gpio)
+void gpio_pm_wakeup_free(unsigned gpio)
 {
 	unsigned long flags;
 
@@ -677,7 +670,7 @@
 }
 EXPORT_SYMBOL(gpio_pm_wakeup_free);
 
-static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
+static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
 {
 	port_setup(gpio, GPIO_USAGE);
 	set_gpio_dir(gpio, 0);
@@ -784,6 +777,14 @@
 }
 
 #endif
+#else /* BF548_FAMILY */
+
+unsigned short get_gpio_dir(unsigned gpio)
+{
+	return (0x01 & (gpio_array[gpio_bank(gpio)]->port_dir_clear >> gpio_sub_n(gpio)));
+}
+EXPORT_SYMBOL(get_gpio_dir);
+
 #endif /* BF548_FAMILY */
 
 /***********************************************************
@@ -1028,7 +1029,7 @@
 * MODIFICATION HISTORY :
 **************************************************************/
 
-int gpio_request(unsigned short gpio, const char *label)
+int gpio_request(unsigned gpio, const char *label)
 {
 	unsigned long flags;
 
@@ -1075,7 +1076,7 @@
 }
 EXPORT_SYMBOL(gpio_request);
 
-void gpio_free(unsigned short gpio)
+void gpio_free(unsigned gpio)
 {
 	unsigned long flags;
 
@@ -1085,7 +1086,7 @@
 	local_irq_save(flags);
 
 	if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
-		printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
+		gpio_error(gpio);
 		dump_stack();
 		local_irq_restore(flags);
 		return;
@@ -1101,44 +1102,55 @@
 }
 EXPORT_SYMBOL(gpio_free);
 
+
 #ifdef BF548_FAMILY
-void gpio_direction_input(unsigned short gpio)
+int gpio_direction_input(unsigned gpio)
 {
 	unsigned long flags;
 
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		gpio_error(gpio);
+		return -EINVAL;
+	}
 
 	local_irq_save(flags);
 	gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
 	gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
 	local_irq_restore(flags);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpio_direction_input);
 
-void gpio_direction_output(unsigned short gpio)
+int gpio_direction_output(unsigned gpio, int value)
 {
 	unsigned long flags;
 
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		gpio_error(gpio);
+		return -EINVAL;
+	}
 
 	local_irq_save(flags);
 	gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
+	gpio_set_value(gpio, value);
 	gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
 	local_irq_restore(flags);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpio_direction_output);
 
-void gpio_set_value(unsigned short gpio, unsigned short arg)
+void gpio_set_value(unsigned gpio, int arg)
 {
 	if (arg)
 		gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio);
 	else
 		gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio);
-
 }
 EXPORT_SYMBOL(gpio_set_value);
 
-unsigned short gpio_get_value(unsigned short gpio)
+int gpio_get_value(unsigned gpio)
 {
 	return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio)));
 }
@@ -1146,31 +1158,47 @@
 
 #else
 
-void gpio_direction_input(unsigned short gpio)
+int gpio_direction_input(unsigned gpio)
 {
 	unsigned long flags;
 
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		gpio_error(gpio);
+		return -EINVAL;
+	}
 
 	local_irq_save(flags);
 	gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
 	gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
 	AWA_DUMMY_READ(inen);
 	local_irq_restore(flags);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpio_direction_input);
 
-void gpio_direction_output(unsigned short gpio)
+int gpio_direction_output(unsigned gpio, int value)
 {
 	unsigned long flags;
 
-	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		gpio_error(gpio);
+		return -EINVAL;
+	}
 
 	local_irq_save(flags);
 	gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
+
+	if (value)
+		gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+	else
+		gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
+
 	gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
 	AWA_DUMMY_READ(dir);
 	local_irq_restore(flags);
+
+	return 0;
 }
 EXPORT_SYMBOL(gpio_direction_output);
 
@@ -1190,7 +1218,40 @@
 
 	port_setup(gpio, GPIO_USAGE);
 	gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+	AWA_DUMMY_READ(data_set);
 	udelay(1);
 }
 
 #endif /*BF548_FAMILY */
+
+#if defined(CONFIG_PROC_FS)
+static int gpio_proc_read(char *buf, char **start, off_t offset,
+			  int len, int *unused_i, void *unused_v)
+{
+	int c, outlen = 0;
+
+	for (c = 0; c < MAX_RESOURCES; c++) {
+		if (!check_gpio(c) && (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c)))
+			len = sprintf(buf, "GPIO_%d: %s \t\tGPIO %s\n", c,
+				 get_label(c), get_gpio_dir(c) ? "OUTPUT" : "INPUT");
+		else if (reserved_peri_map[gpio_bank(c)] & gpio_bit(c))
+			len = sprintf(buf, "GPIO_%d: %s \t\tPeripheral\n", c, get_label(c));
+		else
+			continue;
+		buf += len;
+		outlen += len;
+	}
+	return outlen;
+}
+
+static __init int gpio_register_proc(void)
+{
+	struct proc_dir_entry *proc_gpio;
+
+	proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
+	if (proc_gpio)
+		proc_gpio->read_proc = gpio_proc_read;
+	return proc_gpio != NULL;
+}
+__initcall(gpio_register_proc);
+#endif
diff --git a/arch/blackfin/kernel/cplb-mpu/Makefile b/arch/blackfin/kernel/cplb-mpu/Makefile
new file mode 100644
index 0000000..286b693
--- /dev/null
+++ b/arch/blackfin/kernel/cplb-mpu/Makefile
@@ -0,0 +1,8 @@
+#
+# arch/blackfin/kernel/cplb-nompu/Makefile
+#
+
+obj-y := cplbinit.o cacheinit.o cplbmgr.o
+
+obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
+
diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
similarity index 74%
copy from arch/blackfin/kernel/cacheinit.c
copy to arch/blackfin/kernel/cplb-mpu/cacheinit.c
index 62cbba7..9eecfa4 100644
--- a/arch/blackfin/kernel/cacheinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cacheinit.c
@@ -27,41 +27,36 @@
 #if defined(CONFIG_BFIN_ICACHE)
 void bfin_icache_init(void)
 {
-	unsigned long *table = icplb_table;
 	unsigned long ctrl;
 	int i;
 
+	SSYNC();
 	for (i = 0; i < MAX_CPLBS; i++) {
-		unsigned long addr = *table++;
-		unsigned long data = *table++;
-		if (addr == (unsigned long)-1)
-			break;
-		bfin_write32(ICPLB_ADDR0 + i * 4, addr);
-		bfin_write32(ICPLB_DATA0 + i * 4, data);
+		bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
+		bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
 	}
 	ctrl = bfin_read_IMEM_CONTROL();
 	ctrl |= IMC | ENICPLB;
 	bfin_write_IMEM_CONTROL(ctrl);
+	SSYNC();
 }
 #endif
 
 #if defined(CONFIG_BFIN_DCACHE)
 void bfin_dcache_init(void)
 {
-	unsigned long *table = dcplb_table;
 	unsigned long ctrl;
 	int i;
 
+	SSYNC();
 	for (i = 0; i < MAX_CPLBS; i++) {
-		unsigned long addr = *table++;
-		unsigned long data = *table++;
-		if (addr == (unsigned long)-1)
-			break;
-		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
-		bfin_write32(DCPLB_DATA0 + i * 4, data);
+		bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
+		bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
 	}
+
 	ctrl = bfin_read_DMEM_CONTROL();
 	ctrl |= DMEM_CNTR;
 	bfin_write_DMEM_CONTROL(ctrl);
+	SSYNC();
 }
 #endif
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinfo.c b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
new file mode 100644
index 0000000..bd07229
--- /dev/null
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinfo.c
@@ -0,0 +1,144 @@
+/*
+ * File:         arch/blackfin/mach-common/cplbinfo.c
+ * Based on:
+ * Author:       Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:      Jan. 2005
+ * Description:  Display CPLB status
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+
+#include <asm/current.h>
+#include <asm/system.h>
+#include <asm/cplb.h>
+#include <asm/cplbinit.h>
+#include <asm/blackfin.h>
+
+#define CPLB_I 1
+#define CPLB_D 2
+
+#define SYNC_SYS    SSYNC()
+#define SYNC_CORE   CSYNC()
+
+#define CPLB_BIT_PAGESIZE 0x30000
+
+static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+
+static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
+{
+	int i;
+	buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
+	for (i = 0; i < MAX_CPLBS; i++) {
+		unsigned long data = tbl[i].data;
+		unsigned long addr = tbl[i].addr;
+		if (!(data & CPLB_VALID))
+			continue;
+
+		buf +=
+		    sprintf(buf,
+			    "%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n",
+			    i, addr, data,
+			    page_size_string_table[(data & 0x30000) >> 16],
+			    (data & CPLB_USER_RD) ? 'Y' : 'N',
+			    (data & CPLB_USER_WR) ? 'Y' : 'N',
+			    (data & CPLB_SUPV_WR) ? 'Y' : 'N',
+			    i < switched ? 'N' : 'Y');
+	}
+	buf += sprintf(buf, "\n");
+
+	return buf;
+}
+
+int cplbinfo_proc_output(char *buf)
+{
+	char *p;
+
+	p = buf;
+
+	p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
+
+	if (bfin_read_IMEM_CONTROL() & ENICPLB) {
+		p += sprintf(p, "Instruction CPLB entry:\n");
+		p = cplb_print_entry(p, icplb_tbl, first_switched_icplb);
+	} else
+		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
+
+	if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) {
+		p += sprintf(p, "Data CPLB entry:\n");
+		p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb);
+	} else
+		p += sprintf(p, "Data CPLB is disabled.\n");
+
+	p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n",
+		     nr_icplb_miss, nr_icplb_supv_miss);
+	p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n",
+		     nr_dcplb_miss, nr_dcplb_prot);
+	p += sprintf(p, "CPLB flushes: %d\n",
+		     nr_cplb_flush);
+
+	return p - buf;
+}
+
+static int cplbinfo_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	int len;
+
+	len = cplbinfo_proc_output(page);
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+static int __init cplbinfo_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_entry("cplbinfo", 0, NULL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->read_proc = cplbinfo_read_proc;
+	entry->data = NULL;
+
+	return 0;
+}
+
+static void __exit cplbinfo_exit(void)
+{
+	remove_proc_entry("cplbinfo", NULL);
+}
+
+module_init(cplbinfo_init);
+module_exit(cplbinfo_exit);
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
new file mode 100644
index 0000000..e2e2b50
--- /dev/null
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -0,0 +1,91 @@
+/*
+ * Blackfin CPLB initialization
+ *
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/module.h>
+
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+#include <asm/cplbinit.h>
+
+struct cplb_entry icplb_tbl[MAX_CPLBS];
+struct cplb_entry dcplb_tbl[MAX_CPLBS];
+
+int first_switched_icplb, first_switched_dcplb;
+int first_mask_dcplb;
+
+void __init generate_cpl_tables(void)
+{
+	int i_d, i_i;
+	unsigned long addr;
+	unsigned long d_data, i_data;
+	unsigned long d_cache = 0, i_cache = 0;
+
+#ifdef CONFIG_BFIN_ICACHE
+	i_cache = CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
+#endif
+
+#ifdef CONFIG_BFIN_DCACHE
+	d_cache = CPLB_L1_CHBL;
+#ifdef CONFIG_BLKFIN_WT
+	d_cache |= CPLB_L1_AOW | CPLB_WT;
+#endif
+#endif
+	i_d = i_i = 0;
+
+	/* Set up the zero page.  */
+	dcplb_tbl[i_d].addr = 0;
+	dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
+
+#if 0
+	icplb_tbl[i_i].addr = 0;
+	icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB;
+#endif
+
+	/* Cover kernel memory with 4M pages.  */
+	addr = 0;
+	d_data = d_cache | CPLB_SUPV_WR | CPLB_VALID | PAGE_SIZE_4MB | CPLB_DIRTY;
+	i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB;
+
+	for (; addr < memory_start; addr += 4 * 1024 * 1024) {
+		dcplb_tbl[i_d].addr = addr;
+		dcplb_tbl[i_d++].data = d_data;
+		icplb_tbl[i_i].addr = addr;
+		icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
+	}
+
+	/* Cover L1 memory.  One 4M area for code and data each is enough.  */
+#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
+	dcplb_tbl[i_d].addr = L1_DATA_A_START;
+	dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
+#endif
+	icplb_tbl[i_i].addr = L1_CODE_START;
+	icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
+
+	first_mask_dcplb = i_d;
+	first_switched_dcplb = i_d + (1 << page_mask_order);
+	first_switched_icplb = i_i;
+
+	while (i_d < MAX_CPLBS)
+		dcplb_tbl[i_d++].data = 0;
+	while (i_i < MAX_CPLBS)
+		icplb_tbl[i_i++].data = 0;
+}
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
new file mode 100644
index 0000000..c426a22
--- /dev/null
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -0,0 +1,338 @@
+/*
+ *               Blackfin CPLB exception handling.
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+
+#include <asm/blackfin.h>
+#include <asm/cplbinit.h>
+#include <asm/mmu_context.h>
+
+#ifdef CONFIG_BFIN_ICACHE
+
+#define FAULT_RW	(1 << 16)
+#define FAULT_USERSUPV	(1 << 17)
+
+int page_mask_nelts;
+int page_mask_order;
+unsigned long *current_rwx_mask;
+
+int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
+int nr_cplb_flush;
+
+static inline void disable_dcplb(void)
+{
+	unsigned long ctrl;
+	SSYNC();
+	ctrl = bfin_read_DMEM_CONTROL();
+	ctrl &= ~ENDCPLB;
+	bfin_write_DMEM_CONTROL(ctrl);
+	SSYNC();
+}
+
+static inline void enable_dcplb(void)
+{
+	unsigned long ctrl;
+	SSYNC();
+	ctrl = bfin_read_DMEM_CONTROL();
+	ctrl |= ENDCPLB;
+	bfin_write_DMEM_CONTROL(ctrl);
+	SSYNC();
+}
+
+static inline void disable_icplb(void)
+{
+	unsigned long ctrl;
+	SSYNC();
+	ctrl = bfin_read_IMEM_CONTROL();
+	ctrl &= ~ENICPLB;
+	bfin_write_IMEM_CONTROL(ctrl);
+	SSYNC();
+}
+
+static inline void enable_icplb(void)
+{
+	unsigned long ctrl;
+	SSYNC();
+	ctrl = bfin_read_IMEM_CONTROL();
+	ctrl |= ENICPLB;
+	bfin_write_IMEM_CONTROL(ctrl);
+	SSYNC();
+}
+
+/*
+ * Given the contents of the status register, return the index of the
+ * CPLB that caused the fault.
+ */
+static inline int faulting_cplb_index(int status)
+{
+	int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
+	return 30 - signbits;
+}
+
+/*
+ * Given the contents of the status register and the DCPLB_DATA contents,
+ * return true if a write access should be permitted.
+ */
+static inline int write_permitted(int status, unsigned long data)
+{
+	if (status & FAULT_USERSUPV)
+		return !!(data & CPLB_SUPV_WR);
+	else
+		return !!(data & CPLB_USER_WR);
+}
+
+/* Counters to implement round-robin replacement.  */
+static int icplb_rr_index, dcplb_rr_index;
+
+/*
+ * Find an ICPLB entry to be evicted and return its index.
+ */
+static int evict_one_icplb(void)
+{
+	int i;
+	for (i = first_switched_icplb; i < MAX_CPLBS; i++)
+		if ((icplb_tbl[i].data & CPLB_VALID) == 0)
+			return i;
+	i = first_switched_icplb + icplb_rr_index;
+	if (i >= MAX_CPLBS) {
+		i -= MAX_CPLBS - first_switched_icplb;
+		icplb_rr_index -= MAX_CPLBS - first_switched_icplb;
+	}
+	icplb_rr_index++;
+	return i;
+}
+
+static int evict_one_dcplb(void)
+{
+	int i;
+	for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
+		if ((dcplb_tbl[i].data & CPLB_VALID) == 0)
+			return i;
+	i = first_switched_dcplb + dcplb_rr_index;
+	if (i >= MAX_CPLBS) {
+		i -= MAX_CPLBS - first_switched_dcplb;
+		dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb;
+	}
+	dcplb_rr_index++;
+	return i;
+}
+
+static noinline int dcplb_miss(void)
+{
+	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
+	int status = bfin_read_DCPLB_STATUS();
+	unsigned long *mask;
+	int idx;
+	unsigned long d_data;
+
+	nr_dcplb_miss++;
+	if (addr >= _ramend)
+		return CPLB_PROT_VIOL;
+
+	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
+#ifdef CONFIG_BFIN_DCACHE
+	d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
+#ifdef CONFIG_BLKFIN_WT
+	d_data |= CPLB_L1_AOW | CPLB_WT;
+#endif
+#endif
+	mask = current_rwx_mask;
+	if (mask) {
+		int page = addr >> PAGE_SHIFT;
+		int offs = page >> 5;
+		int bit = 1 << (page & 31);
+
+		if (mask[offs] & bit)
+			d_data |= CPLB_USER_RD;
+
+		mask += page_mask_nelts;
+		if (mask[offs] & bit)
+			d_data |= CPLB_USER_WR;
+	}
+
+	idx = evict_one_dcplb();
+
+	addr &= PAGE_MASK;
+	dcplb_tbl[idx].addr = addr;
+	dcplb_tbl[idx].data = d_data;
+
+	disable_dcplb();
+	bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
+	bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
+	enable_dcplb();
+
+	return 0;
+}
+
+static noinline int icplb_miss(void)
+{
+	unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
+	int status = bfin_read_ICPLB_STATUS();
+	int idx;
+	unsigned long i_data;
+
+	nr_icplb_miss++;
+	if (status & FAULT_USERSUPV)
+		nr_icplb_supv_miss++;
+
+	if (addr >= _ramend)
+		return CPLB_PROT_VIOL;
+
+	/*
+	 * First, try to find a CPLB that matches this address.  If we
+	 * find one, then the fact that we're in the miss handler means
+	 * that the instruction crosses a page boundary.
+	 */
+	for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
+		if (icplb_tbl[idx].data & CPLB_VALID) {
+			unsigned long this_addr = icplb_tbl[idx].addr;
+			if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
+				addr += PAGE_SIZE;
+				break;
+			}
+		}
+	}
+
+	i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
+#ifdef CONFIG_BFIN_ICACHE
+	i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
+#endif
+
+	/*
+	 * Two cases to distinguish - a supervisor access must necessarily
+	 * be for a module page; we grant it unconditionally (could do better
+	 * here in the future).  Otherwise, check the x bitmap of the current
+	 * process.
+	 */
+	if (!(status & FAULT_USERSUPV)) {
+		unsigned long *mask = current_rwx_mask;
+
+		if (mask) {
+			int page = addr >> PAGE_SHIFT;
+			int offs = page >> 5;
+			int bit = 1 << (page & 31);
+
+			mask += 2 * page_mask_nelts;
+			if (mask[offs] & bit)
+				i_data |= CPLB_USER_RD;
+		}
+	}
+
+	idx = evict_one_icplb();
+	addr &= PAGE_MASK;
+	icplb_tbl[idx].addr = addr;
+	icplb_tbl[idx].data = i_data;
+
+	disable_icplb();
+	bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
+	bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
+	enable_icplb();
+
+	return 0;
+}
+
+static noinline int dcplb_protection_fault(void)
+{
+	unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
+	int status = bfin_read_DCPLB_STATUS();
+
+	nr_dcplb_prot++;
+
+	if (status & FAULT_RW) {
+		int idx = faulting_cplb_index(status);
+		unsigned long data = dcplb_tbl[idx].data;
+		if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
+		    write_permitted(status, data)) {
+			data |= CPLB_DIRTY;
+			dcplb_tbl[idx].data = data;
+			bfin_write32(DCPLB_DATA0 + idx * 4, data);
+			return 0;
+		}
+	}
+	return CPLB_PROT_VIOL;
+}
+
+int cplb_hdr(int seqstat, struct pt_regs *regs)
+{
+	int cause = seqstat & 0x3f;
+	switch (cause) {
+	case 0x23:
+		return dcplb_protection_fault();
+	case 0x2C:
+		return icplb_miss();
+	case 0x26:
+		return dcplb_miss();
+	default:
+	    return 1;
+		panic_cplb_error(seqstat, regs);
+	}
+}
+
+void flush_switched_cplbs(void)
+{
+	int i;
+
+	nr_cplb_flush++;
+
+	disable_icplb();
+	for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
+		icplb_tbl[i].data = 0;
+		bfin_write32(ICPLB_DATA0 + i * 4, 0);
+	}
+	enable_icplb();
+
+	disable_dcplb();
+	for (i = first_mask_dcplb; i < MAX_CPLBS; i++) {
+		dcplb_tbl[i].data = 0;
+		bfin_write32(DCPLB_DATA0 + i * 4, 0);
+	}
+	enable_dcplb();
+}
+
+void set_mask_dcplbs(unsigned long *masks)
+{
+	int i;
+	unsigned long addr = (unsigned long)masks;
+	unsigned long d_data;
+	current_rwx_mask = masks;
+
+	if (!masks)
+		return;
+
+	d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
+#ifdef CONFIG_BFIN_DCACHE
+	d_data |= CPLB_L1_CHBL;
+#ifdef CONFIG_BLKFIN_WT
+	d_data |= CPLB_L1_AOW | CPLB_WT;
+#endif
+#endif
+
+	disable_dcplb();
+	for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
+		dcplb_tbl[i].addr = addr;
+		dcplb_tbl[i].data = d_data;
+		bfin_write32(DCPLB_DATA0 + i * 4, d_data);
+		bfin_write32(DCPLB_ADDR0 + i * 4, addr);
+		addr += PAGE_SIZE;
+	}
+	enable_dcplb();
+}
+
+#endif
diff --git a/arch/blackfin/kernel/cplb-nompu/Makefile b/arch/blackfin/kernel/cplb-nompu/Makefile
new file mode 100644
index 0000000..d36ea9b
--- /dev/null
+++ b/arch/blackfin/kernel/cplb-nompu/Makefile
@@ -0,0 +1,8 @@
+#
+# arch/blackfin/kernel/cplb-nompu/Makefile
+#
+
+obj-y := cplbinit.o cacheinit.o cplbhdlr.o cplbmgr.o
+
+obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
+
diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
similarity index 98%
rename from arch/blackfin/kernel/cacheinit.c
rename to arch/blackfin/kernel/cplb-nompu/cacheinit.c
index 62cbba7..8a18399 100644
--- a/arch/blackfin/kernel/cacheinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cacheinit.c
@@ -42,6 +42,7 @@
 	ctrl = bfin_read_IMEM_CONTROL();
 	ctrl |= IMC | ENICPLB;
 	bfin_write_IMEM_CONTROL(ctrl);
+	SSYNC();
 }
 #endif
 
@@ -63,5 +64,6 @@
 	ctrl = bfin_read_DMEM_CONTROL();
 	ctrl |= DMEM_CNTR;
 	bfin_write_DMEM_CONTROL(ctrl);
+	SSYNC();
 }
 #endif
diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
similarity index 100%
rename from arch/blackfin/mach-common/cplbhdlr.S
rename to arch/blackfin/kernel/cplb-nompu/cplbhdlr.S
diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/kernel/cplb-nompu/cplbinfo.c
similarity index 100%
rename from arch/blackfin/mach-common/cplbinfo.c
rename to arch/blackfin/kernel/cplb-nompu/cplbinfo.c
diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
similarity index 100%
rename from arch/blackfin/kernel/cplbinit.c
rename to arch/blackfin/kernel/cplb-nompu/cplbinit.c
diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
similarity index 93%
rename from arch/blackfin/mach-common/cplbmgr.S
rename to arch/blackfin/kernel/cplb-nompu/cplbmgr.S
index 6f909cb..f5cf3ac 100644
--- a/arch/blackfin/mach-common/cplbmgr.S
+++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.S
@@ -75,6 +75,15 @@
 	* from the configuration table.
 	*/
 
+	/* A multi-word instruction can cross a page boundary. This means the
+	 * first part of the instruction can be in a valid page, but the
+	 * second part is not, and hence generates the instruction miss.
+	 * However, the fault address is for the start of the instruction,
+	 * not the part that's in the bad page. Therefore, we have to check
+	 * whether the fault address applies to a page that is already present
+	 * in the table.
+	 */
+
 	P4.L = LO(ICPLB_FAULT_ADDR);
 	P4.H = HI(ICPLB_FAULT_ADDR);
 
@@ -87,7 +96,7 @@
 	R4 = [P4];		/* Get faulting address*/
 	R6 = 64;		/* Advance past the fault address, which*/
 	R6 = R6 + R4;		/* we'll use if we find a match*/
-	R3 = ((16 << 8) | 2);	/* Extract mask, bits 16 and 17.*/
+	R3 = ((16 << 8) | 2);	/* Extract mask, two bits at posn 16 */
 
 	R5 = 0;
 .Lisearch:
@@ -125,7 +134,9 @@
 	P4.L = LO(IMEM_CONTROL);
 	P4.H = HI(IMEM_CONTROL);
 
-	/* disable cplbs */
+	/* Turn off CPLBs while we work, necessary according to HRM before
+	 * modifying CPLB descriptors
+	 */
 	R5 = [P4];		/* Control Register*/
 	BITCLR(R5,ENICPLB_P);
 	CLI R1;
@@ -179,7 +190,14 @@
 	[P0 - 4] = R0;
 	R0 = [P0 - 0x100];
 	[P0-0x104] = R0;
-.Lie_move:P0+=4;
+.Lie_move:
+	P0+=4;
+
+	/* Clear ICPLB_DATA15, in case we don't find a replacement
+	 * otherwise, we would have a duplicate entry, and will crash
+	 */
+	R0 = 0;
+	[P0 - 4] = R0;
 
 	/* We've made space in the ICPLB table, so that ICPLB15
 	 * is now free to be overwritten. Next, we have to determine
@@ -504,14 +522,23 @@
 	R0 = [P0++];	/* move data */
 	[P0 - 8] = R0;
 	R0 = [P0-0x104]	/* move address */
-.Lde_move: [P0-0x108] = R0;
+.Lde_move:
+	 [P0-0x108] = R0;
+
+.Lde_moved:
+	NOP;
+
+	/* Clear DCPLB_DATA15, in case we don't find a replacement
+	 * otherwise, we would have a duplicate entry, and will crash
+	 */
+	R0 = 0;
+	[P0 - 0x4] = R0;
 
 	/* We've now made space in DCPLB15 for the new CPLB to be
 	 * installed. The next stage is to locate a CPLB in the
 	 * config table that covers the faulting address.
 	 */
 
-.Lde_moved:NOP;
 	R0 = I0;		/* Our faulting address */
 
 	P2.L = _dpdt_table;
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 724f4a5..60f67f9 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -187,7 +187,7 @@
 	bfin_write_EVT15(early_trap);
 	CSYNC();
 
-	/* Set all the return from interupt, exception, NMI to a known place
+	/* Set all the return from interrupt, exception, NMI to a known place
 	 * so if we do a RETI, RETX or RETN by mistake - we go somewhere known
 	 * Note - don't change RETS - we are in a subroutine, or
 	 * RETE - since it might screw up if emulator is attached
@@ -205,7 +205,7 @@
 	if (likely(early_console == NULL))
 		setup_early_printk(DEFAULT_EARLY_PORT);
 
-	dump_bfin_mem((void *)fp->retx);
+	dump_bfin_mem(fp);
 	show_regs(fp);
 	dump_bfin_trace_buffer();
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 5bf1512..023dc80 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -39,9 +39,6 @@
 #include <asm/blackfin.h>
 #include <asm/fixed_code.h>
 
-#define	LED_ON	0
-#define	LED_OFF	1
-
 asmlinkage void ret_from_fork(void);
 
 /* Points to the SDRAM backup memory for the stack that is currently in
@@ -70,32 +67,6 @@
 EXPORT_SYMBOL(pm_power_off);
 
 /*
- * We are using a different LED from the one used to indicate timer interrupt.
- */
-#if defined(CONFIG_BFIN_IDLE_LED)
-static inline void leds_switch(int flag)
-{
-	unsigned short tmp = 0;
-
-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
-	SSYNC();
-
-	if (flag == LED_ON)
-		tmp &= ~CONFIG_BFIN_IDLE_LED_PIN;	/* light on */
-	else
-		tmp |= CONFIG_BFIN_IDLE_LED_PIN;	/* light off */
-
-	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
-	SSYNC();
-
-}
-#else
-static inline void leds_switch(int flag)
-{
-}
-#endif
-
-/*
  * The idle loop on BFIN
  */
 #ifdef CONFIG_IDLE_L1
@@ -106,12 +77,10 @@
 void default_idle(void)
 {
 	while (!need_resched()) {
-		leds_switch(LED_OFF);
 		local_irq_disable();
 		if (likely(!need_resched()))
 			idle_with_irq_disabled();
 		local_irq_enable();
-		leds_switch(LED_ON);
 	}
 }
 
@@ -327,6 +296,7 @@
 }
 
 #if defined(CONFIG_ACCESS_CHECK)
+/* Return 1 if access to memory range is OK, 0 otherwise */
 int _access_ok(unsigned long addr, unsigned long size)
 {
 	if (size == 0)
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index ae28aac..483f93d 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -19,6 +19,11 @@
 #define SYSCR_VAL 	0x10
 #endif
 
+/*
+ * Delay min 5 SCLK cycles using worst case CCLK/SCLK ratio (15)
+ */
+#define SWRST_DELAY	(5 * 15)
+
 /* A system soft reset makes external memory unusable
  * so force this function into L1.
  */
@@ -34,7 +39,13 @@
 	while (1) {
 		/* initiate system soft reset with magic 0x7 */
 		bfin_write_SWRST(0x7);
-		asm("ssync;");
+
+		/* Wait for System reset to actually reset, needs to be 5 SCLKs, */
+		/* Assume CCLK / SCLK ratio is worst case (15), and use 5*15     */
+
+		asm("LSETUP(.Lfoo,.Lfoo) LC0 = %0\n .Lfoo: NOP;\n"
+		 : : "a" (SWRST_DELAY) : "LC0", "LT0", "LB0");
+
 		/* clear system soft reset */
 		bfin_write_SWRST(0);
 		asm("ssync;");
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index d282201..462cae8 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -238,7 +238,13 @@
 	memory_end = _ramend - DMA_UNCACHED_REGION;
 
 	_ramstart = (unsigned long)__bss_stop;
+	_rambase = (unsigned long)_stext;
+#ifdef CONFIG_MPU
+	/* Round up to multiple of 4MB.  */
+	memory_start = (_ramstart + 0x3fffff) & ~0x3fffff;
+#else
 	memory_start = PAGE_ALIGN(_ramstart);
+#endif
 
 #if defined(CONFIG_MTD_UCLINUX)
 	/* generic memory mapped MTD driver */
@@ -307,6 +313,11 @@
 	printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
 #endif				/* ANOMALY_05000263 */
 
+#ifdef CONFIG_MPU
+	page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
+	page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
+#endif
+
 #if !defined(CONFIG_MTD_UCLINUX)
 	memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
 #endif
@@ -315,8 +326,6 @@
 	init_mm.end_data = (unsigned long)_edata;
 	init_mm.brk = (unsigned long)0;
 
-	init_leds();
-
 	_bfin_swrst = bfin_read_SWRST();
 
 	if (_bfin_swrst & RESET_DOUBLE)
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index beef057..5bd64e3 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -42,75 +42,6 @@
 static void time_sched_init(irqreturn_t(*timer_routine)
 			(int, void *));
 static unsigned long gettimeoffset(void);
-static inline void do_leds(void);
-
-#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
-void __init init_leds(void)
-{
-	unsigned int tmp = 0;
-
-#if defined(CONFIG_BFIN_ALIVE_LED)
-	/* config pins as output. */
-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
-	SSYNC();
-	bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
-	SSYNC();
-
-	/*      First set led be off */
-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
-	SSYNC();
-	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);	/* light off */
-	SSYNC();
-#endif
-
-#if defined(CONFIG_BFIN_IDLE_LED)
-	/* config pins as output. */
-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
-	SSYNC();
-	bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
-	SSYNC();
-
-	/*      First set led be off */
-	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
-	SSYNC();
-	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);	/* light off */
-	SSYNC();
-#endif
-}
-#else
-void __init init_leds(void)
-{
-}
-#endif
-
-#if defined(CONFIG_BFIN_ALIVE_LED)
-static inline void do_leds(void)
-{
-	static unsigned int count = 50;
-	static int flag;
-	unsigned short tmp = 0;
-
-	if (--count == 0) {
-		count = 50;
-		flag = ~flag;
-	}
-	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
-	SSYNC();
-
-	if (flag)
-		tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN;	/* light on */
-	else
-		tmp |= CONFIG_BFIN_ALIVE_LED_PIN;	/* light off */
-
-	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
-	SSYNC();
-
-}
-#else
-static inline void do_leds(void)
-{
-}
-#endif
 
 static struct irqaction bfin_timer_irq = {
 	.name = "BFIN Timer Tick",
@@ -205,7 +136,6 @@
 	write_seqlock(&xtime_lock);
 
 	do_timer(1);
-	do_leds();
 
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 21a55ef..66b5f3e 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -36,8 +36,10 @@
 #include <asm/cacheflush.h>
 #include <asm/blackfin.h>
 #include <asm/irq_handler.h>
+#include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
+#include <asm/dma.h>
 
 #ifdef CONFIG_KGDB
 # include <linux/debugger.h>
@@ -170,7 +172,7 @@
 	oops_in_progress = 1;
 	printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
 	dump_bfin_process(fp);
-	dump_bfin_mem((void *)fp->retx);
+	dump_bfin_mem(fp);
 	show_regs(fp);
 	panic("Double Fault - unrecoverable event\n");
 
@@ -195,9 +197,13 @@
 	 * we will kernel panic, so the system reboots.
 	 * If KGDB is enabled, don't set this for kernel breakpoints
 	*/
-	if ((bfin_read_IPEND() & 0xFFC0)
+
+	/* TODO: check to see if we are in some sort of deferred HWERR
+	 * that we should be able to recover from, not kernel panic
+	 */
+	if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
 #ifdef CONFIG_KGDB
-		&& trapnr != VEC_EXCPT02
+		&& (trapnr != VEC_EXCPT02)
 #endif
 	){
 		console_verbose();
@@ -433,6 +439,36 @@
 	/* 0x3D - Reserved, Caught by default */
 	/* 0x3E - Reserved, Caught by default */
 	/* 0x3F - Reserved, Caught by default */
+	case VEC_HWERR:
+		info.si_code = BUS_ADRALN;
+		sig = SIGBUS;
+		switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
+		/* System MMR Error */
+		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
+			info.si_code = BUS_ADRALN;
+			sig = SIGBUS;
+			printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+			break;
+		/* External Memory Addressing Error */
+		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
+			info.si_code = BUS_ADRERR;
+			sig = SIGBUS;
+			printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+			break;
+		/* Performance Monitor Overflow */
+		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
+			printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+			break;
+		/* RAISE 5 instruction */
+		case (SEQSTAT_HWERRCAUSE_RAISE_5):
+			printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
+			break;
+		default:        /* Reserved */
+			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
+			break;
+		}
+		CHK_DEBUGGER_TRAP();
+		break;
 	default:
 		info.si_code = TRAP_ILLTRAP;
 		sig = SIGTRAP;
@@ -447,7 +483,7 @@
 	if (sig != SIGTRAP) {
 		unsigned long stack;
 		dump_bfin_process(fp);
-		dump_bfin_mem((void *)fp->retx);
+		dump_bfin_mem(fp);
 		show_regs(fp);
 
 		/* Print out the trace buffer if it makes sense */
@@ -461,6 +497,7 @@
 			dump_bfin_trace_buffer();
 		show_stack(current, &stack);
 		if (oops_in_progress) {
+			print_modules();
 #ifndef CONFIG_ACCESS_CHECK
 			printk(KERN_EMERG "Please turn on "
 			       "CONFIG_ACCESS_CHECK\n");
@@ -474,13 +511,6 @@
 	info.si_addr = (void *)fp->pc;
 	force_sig_info(sig, &info, current);
 
-	/* Ensure that bad return addresses don't end up in an infinite
-	 * loop, due to speculative loads/reads. This needs to be done after
-	 * the signal has been sent.
-	 */
-	if (trapnr == VEC_CPLB_I_M && sig != SIGTRAP)
-		fp->pc = SAFE_USER_INSTRUCTION;
-
 	trace_buffer_restore(j);
 	return;
 }
@@ -616,8 +646,10 @@
 	if (oops_in_progress)
 		printk(KERN_EMERG "Kernel OOPS in progress\n");
 
-	if (context & 0x0020)
-		printk(KERN_NOTICE "Deferred excecption or HW Error context\n");
+	if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
+		printk(KERN_NOTICE "HW Error context\n");
+	else if (context & 0x0020)
+		printk(KERN_NOTICE "Defered Exception context\n");
 	else if (context & 0x3FC0)
 		printk(KERN_NOTICE "Interrupt context\n");
 	else if (context & 0x4000)
@@ -645,59 +677,124 @@
 		     "No Valid process in current context\n");
 }
 
-void dump_bfin_mem(void *retaddr)
+void dump_bfin_mem(struct pt_regs *fp)
 {
+	unsigned short *addr, *erraddr, val = 0, err = 0;
+	char sti = 0, buf[6];
 
-	if (retaddr >= (void *)FIXED_CODE_START  && retaddr < (void *)physical_mem_end
-#if L1_CODE_LENGTH != 0
-	    /* FIXME: Copy the code out of L1 Instruction SRAM through dma
-	       memcpy.  */
-	    && !(retaddr >= (void *)L1_CODE_START
-	         && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
-#endif
-	) {
-		int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32;
-		unsigned short x = 0;
-		printk(KERN_NOTICE "return address: [0x%p]; contents of:", retaddr);
-		for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
-			if (!(i & 0xF))
-				printk("\n" KERN_NOTICE "0x%08x: ", i);
+	if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
+		erraddr = (void *)fp->pc;
+	else
+		erraddr = (void *)fp->retx;
 
-			if (get_user(x, (unsigned short *)i))
-				break;
+	printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
+
+	for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
+	     addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
+	     addr++) {
+		if (!((unsigned long)addr & 0xF))
+			printk("\n" KERN_NOTICE "0x%p: ", addr);
+
+		if (get_user(val, addr)) {
+			if (addr >= (unsigned short *)L1_CODE_START &&
+			    addr < (unsigned short *)(L1_CODE_START + L1_CODE_LENGTH)) {
+				dma_memcpy(&val, addr, sizeof(val));
+				sprintf(buf, "%04x", val);
+			} else if (addr >= (unsigned short *)FIXED_CODE_START &&
+				addr <= (unsigned short *)memory_start) {
+				val = bfin_read16(addr);
+				sprintf(buf, "%04x", val);
+			} else {
+				val = 0;
+				sprintf(buf, "????");
+			}
+		} else
+			sprintf(buf, "%04x", val);
+
+		if (addr == erraddr) {
+			printk("[%s]", buf);
+			err = val;
+		} else
+			printk(" %s ", buf);
+
+		/* Do any previous instructions turn on interrupts? */
+		if (addr <= erraddr &&				/* in the past */
+		    ((val >= 0x0040 && val <= 0x0047) ||	/* STI instruction */
+		      val == 0x017b))				/* [SP++] = RETI */
+			sti = 1;
+	}
+
+	printk("\n");
+
+	/* Hardware error interrupts can be deferred */
+	if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
+	    oops_in_progress)){
+		printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
 #ifndef CONFIG_DEBUG_HWERR
-			/* If one of the last few instructions was a STI
-			 * it is likely that the error occured awhile ago
-			 * and we just noticed. This only happens in kernel
-			 * context, which should mean an oops is happening
-			 */
-			if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0)
-				panic("\n\nWARNING : You should reconfigure"
-					" the kernel to turn on\n"
-					" 'Hardware error interrupt"
-					" debugging'\n"
-					" The rest of this error"
-					" is meanless\n");
-#endif
-			if (i == (unsigned int)retaddr)
-				printk("[%04x]", x);
-			else
-				printk(" %04x ", x);
+		printk(KERN_NOTICE "The remaining message may be meaningless\n"
+			KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
+			 " better idea where it came from\n");
+#else
+		/* If we are handling only one peripheral interrupt
+		 * and current mm and pid are valid, and the last error
+		 * was in that user space process's text area
+		 * print it out - because that is where the problem exists
+		 */
+		if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
+		     (current->pid && current->mm)) {
+			/* And the last RETI points to the current userspace context */
+			if ((fp + 1)->pc >= current->mm->start_code &&
+			    (fp + 1)->pc <= current->mm->end_code) {
+				printk(KERN_NOTICE "It might be better to look around here : \n");
+				printk(KERN_NOTICE "-------------------------------------------\n");
+				show_regs(fp + 1);
+				printk(KERN_NOTICE "-------------------------------------------\n");
+			}
 		}
-		printk("\n");
-	} else
-		printk("\n" KERN_NOTICE
-			"Cannot look at the [PC] <%p> for it is"
-			" in unreadable memory - sorry\n", retaddr);
+#endif
+	}
 }
 
 void show_regs(struct pt_regs *fp)
 {
 	char buf [150];
+	struct irqaction *action;
+	unsigned int i;
+	unsigned long flags;
 
-	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n");
+	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted());
 	printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
 		(long)fp->seqstat, fp->ipend, fp->syscfg);
+	printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
+		(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+	printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
+		fp->seqstat & SEQSTAT_EXCAUSE);
+	for (i = 6; i <= 15 ; i++) {
+		if (fp->ipend & (1 << i)) {
+			decode_address(buf, bfin_read32(EVT0 + 4*i));
+			printk(KERN_NOTICE "  physical IVG%i asserted : %s\n", i, buf);
+		}
+	}
+
+	/* if no interrupts are going off, don't print this out */
+	if (fp->ipend & ~0x3F) {
+		for (i = 0; i < (NR_IRQS - 1); i++) {
+			spin_lock_irqsave(&irq_desc[i].lock, flags);
+			action = irq_desc[i].action;
+			if (!action)
+				goto unlock;
+
+			decode_address(buf, (unsigned int)action->handler);
+			printk(KERN_NOTICE "  logical irq %3d mapped  : %s", i, buf);
+			for (action = action->next; action; action = action->next) {
+				decode_address(buf, (unsigned int)action->handler);
+				printk(", %s", buf);
+			}
+			printk("\n");
+unlock:
+			spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+		}
+	}
 
 	decode_address(buf, fp->rete);
 	printk(KERN_NOTICE " RETE: %s\n", buf);
@@ -708,9 +805,10 @@
 	decode_address(buf, fp->rets);
 	printk(KERN_NOTICE " RETS: %s\n", buf);
 	decode_address(buf, fp->pc);
-	printk(KERN_NOTICE " PC: %s\n", buf);
+	printk(KERN_NOTICE " PC  : %s\n", buf);
 
-	if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
+	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
+	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
 		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
 		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
 		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
@@ -824,7 +922,7 @@
 	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
 	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
 	dump_bfin_process(fp);
-	dump_bfin_mem((void *)fp->retx);
+	dump_bfin_mem(fp);
 	show_regs(fp);
 	dump_stack();
 	panic("Unrecoverable event\n");
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
index 2e63364..e654a18 100644
--- a/arch/blackfin/lib/memcpy.S
+++ b/arch/blackfin/lib/memcpy.S
@@ -70,8 +70,8 @@
 	/* Check for aligned data.*/
 
 	R3 = R1 | R0;
-	R0 = 0x3;
-	R3 = R3 & R0;
+	R1 = 0x3;
+	R3 = R3 & R1;
 	CC = R3;	/* low bits set on either address? */
 	IF CC JUMP .Lnot_aligned;
 
@@ -83,7 +83,6 @@
 	/* less than eight bytes... */
 	P2 = R2;
 	LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
-	R0 = R1;	/* setup src address for return */
 .Lthree_start:
 	R3 = B[P1++] (X);
 .Lthree_end:
@@ -95,7 +94,6 @@
 	/* There's at least eight bytes to copy. */
 	P2 += -1;	/* because we unroll one iteration */
 	LSETUP(.Lword_loops, .Lword_loope) LC0=P2;
-	R0 = R1;
 	I1 = P1;
 	R3 = [I1++];
 #if ANOMALY_05000202
@@ -120,7 +118,6 @@
 .Lnot_aligned:
 	/* From here, we're copying byte-by-byte. */
 	LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
-	R0 = R1;	/* Save src address for return */
 .Lbyte_start:
 	R1 = B[P1++] (X);
 .Lbyte_end:
@@ -135,7 +132,6 @@
 	 * Don't bother to work out alignment for
 	 * the reverse case.
 	 */
-	R0 = R1;	/* save src for later. */
 	P0 = P0 + P2;
 	P0 += -1;
 	P1 = P1 + P2;
diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig
index 5c73683..3cde4be 100644
--- a/arch/blackfin/mach-bf527/Kconfig
+++ b/arch/blackfin/mach-bf527/Kconfig
@@ -43,7 +43,7 @@
 
 choice
 	prompt "UART1"
-	default BF527_UART1_PORTG
+	default BF527_UART1_PORTF
 	help
 	  Select PORT used for UART1. See Hardware Reference Manual
 
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 003e2ac..f8c411a 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -8,7 +8,7 @@
  *
  * Modified:
  *               Copyright 2005 National ICT Australia (NICTA)
- *               Copyright 2004-2007 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -41,6 +41,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/usb/sl811.h>
+#include <linux/usb/musb.h>
 #include <asm/cplb.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
@@ -105,6 +106,69 @@
 arch_initcall(bfin_isp1761_init);
 #endif
 
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+	[0] = {
+		.start	= 0xffc03800,
+		.end	= 0xffc03cff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* general IRQ */
+		.start	= IRQ_USB_INT0,
+		.end	= IRQ_USB_INT0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+	[2] = {	/* DMA IRQ */
+		.start	= IRQ_USB_DMA,
+		.end	= IRQ_USB_DMA,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	.mode		= MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+	.mode		= MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.multipoint	= 0,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+	.name		= "musb_hdrc",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= &musb_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &musb_plat,
+	},
+	.num_resources	= ARRAY_SIZE(musb_resources),
+	.resource	= musb_resources,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
+
+static struct resource bf52x_t350mcqb_resources[] = {
+	{
+		.start = IRQ_PPI_ERROR,
+		.end = IRQ_PPI_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf52x_t350mcqb_device = {
+	.name		= "bfin-t350mcqb",
+	.id		= -1,
+	.num_resources 	= ARRAY_SIZE(bf52x_t350mcqb_resources),
+	.resource 	= bf52x_t350mcqb_resources,
+};
+#endif
+
 #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
 static struct mtd_partition partition_info[] = {
 	{
@@ -253,12 +317,7 @@
 void sl811_port_power(struct device *dev, int is_on)
 {
 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
-
-	if (is_on)
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
-	else
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
 }
 #endif
 
@@ -718,6 +777,28 @@
 };
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PG0, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PG13, 1, "gpio-keys: BTN1"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
 static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
 	&bf5xx_nand_device,
@@ -739,6 +820,10 @@
 	&isp1362_hcd_device,
 #endif
 
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+	&musb_device,
+#endif
+
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 	&smc91x_device,
 #endif
@@ -763,6 +848,10 @@
 	&bfin_fb_device,
 #endif
 
+#if defined(CONFIG_FB_BFIN_T350MCQB) || defined(CONFIG_FB_BFIN_T350MCQB_MODULE)
+	&bf52x_t350mcqb_device,
+#endif
+
 #if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
 	&bfin_fb_adv7393_device,
 #endif
@@ -783,6 +872,10 @@
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
 };
 
 static int __init stamp_init(void)
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index 6bcf404..a72c7a6 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -40,6 +40,7 @@
 #endif
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
+
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
@@ -303,7 +304,77 @@
 };
 #endif
 
-static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+
+#include <linux/serial_8250.h>
+#include <linux/serial.h>
+
+/*
+ * Configuration for two 16550 UARTS in FPGA at addresses 0x20200000 and 0x202000010.
+ * running at half system clock, both with interrupt output or-ed to PF8. Change to
+ * suit different FPGA configuration, or to suit real 16550 UARTS connected to the bus
+ */
+
+static struct plat_serial8250_port serial8250_platform_data [] = {
+	{
+		.membase = 0x20200000,
+		.mapbase = 0x20200000,
+		.irq = IRQ_PF8,
+		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
+		.iotype = UPIO_MEM,
+		.regshift = 1,
+		.uartclk = 66666667,
+	}, {
+		.membase = 0x20200010,
+		.mapbase = 0x20200010,
+		.irq = IRQ_PF8,
+		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
+		.iotype = UPIO_MEM,
+		.regshift = 1,
+		.uartclk = 66666667,
+	}, {
+	}
+};
+
+static struct platform_device serial8250_device = {
+	.id		= PLAT8250_DEV_PLATFORM,
+	.name		= "serial8250",
+	.dev		= {
+		.platform_data = serial8250_platform_data,
+	},
+};
+
+#endif
+
+#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
+
+/*
+ * Configuration for one OpenCores keyboard controller in FPGA at address 0x20200030,
+ * interrupt output wired to PF9. Change to suit different FPGA configuration
+ */
+
+static struct resource opencores_kbd_resources[] = {
+	[0] = {
+		.start	= 0x20200030,
+		.end	= 0x20300030 + 2,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_PF9,
+		.end	= IRQ_PF9,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+	},
+};
+
+static struct platform_device opencores_kbd_device = {
+	.id		= -1,
+	.name		= "opencores-kbd",
+	.resource	= opencores_kbd_resources,
+	.num_resources	= ARRAY_SIZE(opencores_kbd_resources),
+};
+#endif
+
+static struct platform_device *h8606_devices[] __initdata = {
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 	&rtc_device,
 #endif
@@ -327,13 +398,21 @@
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 	&bfin_uart_device,
 #endif
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+	&serial8250_device,
+#endif
+
+#if defined(CONFIG_KEYBOARD_OPENCORES) || defined(CONFIG_KEYBOARD_OPENCORES_MODULE)
+	&opencores_kbd_device,
+#endif
 };
 
 static int __init H8606_init(void)
 {
 	printk(KERN_INFO "HV Sistemas H8606 board support by http://www.hvsistemas.com\n");
 	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
-	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+	platform_add_devices(h8606_devices, ARRAY_SIZE(h8606_devices));
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index be85203..c37dd45 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -256,6 +256,50 @@
 };
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PF7, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PF8, 1, "gpio-keys: BTN1"},
+	{BTN_2, GPIO_PF9, 1, "gpio-keys: BTN2"},
+	{BTN_3, GPIO_PF10, 1, "gpio-keys: BTN3"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+#include <linux/i2c-gpio.h>
+
+static struct i2c_gpio_platform_data i2c_gpio_data = {
+	.sda_pin		= 1,
+	.scl_pin		= 0,
+	.sda_is_open_drain	= 0,
+	.scl_is_open_drain	= 0,
+	.udelay			= 40,
+};
+
+static struct platform_device i2c_gpio_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &i2c_gpio_data,
+	},
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 	&smc91x_device,
@@ -280,6 +324,14 @@
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+	&i2c_gpio_device,
+#endif
 };
 
 static int __init ezkit_init(void)
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index 8fde8d8..ac52b04 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
@@ -108,6 +109,50 @@
 };
 #endif
 
+static struct mtd_partition stamp_partitions[] = {
+	{
+		.name   = "Bootloader",
+		.size   = 0x20000,
+		.offset = 0,
+	}, {
+		.name   = "Kernel",
+		.size   = 0xE0000,
+		.offset = MTDPART_OFS_APPEND,
+	}, {
+		.name   = "RootFS",
+		.size   = MTDPART_SIZ_FULL,
+		.offset = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data stamp_flash_data = {
+	.width    = 2,
+	.parts    = stamp_partitions,
+	.nr_parts = ARRAY_SIZE(stamp_partitions),
+};
+
+static struct resource stamp_flash_resource[] = {
+	{
+		.name  = "cfi_probe",
+		.start = 0x20000000,
+		.end   = 0x203fffff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = CONFIG_ENET_FLASH_PIN,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device stamp_flash_device = {
+	.name          = "BF5xx-Flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &stamp_flash_data,
+	},
+	.num_resources = ARRAY_SIZE(stamp_flash_resource),
+	.resource      = stamp_flash_resource,
+};
+
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
 
@@ -373,6 +418,49 @@
 };
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PF5, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
+	{BTN_2, GPIO_PF8, 1, "gpio-keys: BTN2"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+#include <linux/i2c-gpio.h>
+
+static struct i2c_gpio_platform_data i2c_gpio_data = {
+	.sda_pin		= 2,
+	.scl_pin		= 3,
+	.sda_is_open_drain	= 0,
+	.scl_is_open_drain	= 0,
+	.udelay			= 40,
+};
+
+static struct platform_device i2c_gpio_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &i2c_gpio_data,
+	},
+};
+#endif
+
 static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 	&rtc_device,
@@ -406,6 +494,15 @@
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+	&i2c_gpio_device,
+#endif
+	&stamp_flash_device,
 };
 
 static int __init stamp_init(void)
@@ -418,12 +515,10 @@
 		return ret;
 
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
-# if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
 	/* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
 	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
 	bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
 	SSYNC();
-# endif
 #endif
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
@@ -440,10 +535,8 @@
 
 void native_machine_restart(char *cmd)
 {
-#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
-# define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
+#define BIT_TO_SET (1 << CONFIG_ENET_FLASH_PIN)
 	bfin_write_FIO_INEN(~BIT_TO_SET);
 	bfin_write_FIO_DIR(BIT_TO_SET);
 	bfin_write_FIO_FLAG_C(BIT_TO_SET);
-#endif
 }
diff --git a/arch/blackfin/mach-bf537/boards/Kconfig b/arch/blackfin/mach-bf537/boards/Kconfig
index 96a1519..7e789db 100644
--- a/arch/blackfin/mach-bf537/boards/Kconfig
+++ b/arch/blackfin/mach-bf537/boards/Kconfig
@@ -21,6 +21,12 @@
 	help
 	  PNAV board support.
 
+config CAMSIG_MINOTAUR
+	bool "Cambridge Signal Processing LTD Minotaur"
+	depends on (BF537)
+	help
+	  Board supply package for CSP Minotaur
+
 config GENERIC_BF537_BOARD
 	bool "Generic"
 	help
diff --git a/arch/blackfin/mach-bf537/boards/Makefile b/arch/blackfin/mach-bf537/boards/Makefile
index 94a8517..87e450f 100644
--- a/arch/blackfin/mach-bf537/boards/Makefile
+++ b/arch/blackfin/mach-bf537/boards/Makefile
@@ -6,3 +6,4 @@
 obj-$(CONFIG_BFIN537_STAMP)            += stamp.o led.o
 obj-$(CONFIG_BFIN537_BLUETECHNIX_CM)   += cm_bf537.o
 obj-$(CONFIG_PNAV10)                   += pnav10.o
+obj-$(CONFIG_CAMSIG_MINOTAUR)          += minotaur.o
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
index c0fb06d..8703b67 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -29,6 +29,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -216,6 +217,12 @@
 };
 #endif
 
+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
+static struct platform_device hitachi_fb_device = {
+	.name = "hitachi-tx09",
+};
+#endif
+
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 static struct resource smc91x_resources[] = {
 	{
@@ -374,6 +381,10 @@
 #endif
 
 static struct platform_device *cm_bf537_devices[] __initdata = {
+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
+	&hitachi_fb_device,
+#endif
+
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 	&rtc_device,
 #endif
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index 09f4bfb..3e52f3f 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -8,7 +8,7 @@
  *
  * Modified:
  *               Copyright 2005 National ICT Australia (NICTA)
- *               Copyright 2004-2007 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -29,6 +29,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -204,12 +205,8 @@
 void sl811_port_power(struct device *dev, int is_on)
 {
 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
 
-	if (is_on)
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
-	else
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
 }
 #endif
 
@@ -733,9 +730,11 @@
 		bfin_gpio_reset_spi0_ssel1();
 }
 
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 void bfin_get_ether_addr(char *addr)
 {
 	random_ether_addr(addr);
 	printk(KERN_WARNING "%s:%s: Setting Ethernet MAC to a random one\n", __FILE__, __func__);
 }
 EXPORT_SYMBOL(bfin_get_ether_addr);
+#endif
diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
new file mode 100644
index 0000000..b8bbba8
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
@@ -0,0 +1,317 @@
+/*
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <linux/pata_platform.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb_sl811.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "CamSig Minotaur BF537";
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+	{
+		.start = 0x20310000, /* IO PORT */
+		.end = 0x20312000,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = 0x20311000, /* Attribute Memory */
+		.end = 0x20311FFF,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = IRQ_PF4,
+		.end = IRQ_PF4,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	}, {
+		.start = IRQ_PF6, /* Card Detect PF6 */
+		.end = IRQ_PF6,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+	.name = "bfin_cf_pcmcia",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+	.resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20300000,
+		.end = 0x20300000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+
+/* Partition sizes */
+#define FLASH_SIZE       0x00400000
+#define PSIZE_UBOOT      0x00030000
+#define PSIZE_INITRAMFS  0x00240000
+
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name       = "uboot",
+		.size       = PSIZE_UBOOT,
+		.offset     = 0x000000,
+		.mask_flags = MTD_CAP_ROM
+	}, {
+		.name       = "initramfs",
+		.size       = PSIZE_INITRAMFS,
+		.offset     = PSIZE_UBOOT
+	}, {
+		.name       = "opt",
+		.size       = FLASH_SIZE - (PSIZE_UBOOT + PSIZE_INITRAMFS),
+		.offset     = PSIZE_UBOOT + PSIZE_INITRAMFS,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc_dummy",
+		.max_speed_hz = 5000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 0,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 5000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+	[0] = {
+		.start = SPI0_REGBASE,
+		.end   = SPI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+		},
+	[1] = {
+		.start = CH_SPI,
+		.end   = CH_SPI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_spi0_device = {
+	.name = "bfin-spi",
+	.id = 0, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi0_resource),
+	.resource = bfin_spi0_resource,
+	.dev = {
+		.platform_data = &bfin_spi0_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI,
+		.end   = IRQ_TWI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+static struct platform_device *minotaur_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+	&bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+
+};
+
+static int __init minotaur_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(minotaur_devices, ARRAY_SIZE(minotaur_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info,
+				ARRAY_SIZE(bfin_spi_board_info));
+#endif
+
+	return 0;
+}
+
+arch_initcall(minotaur_init);
+
+void native_machine_restart(char *cmd)
+{
+	/* workaround reboot hang when booting from SPI */
+	if ((bfin_read_SYSCR() & 0x7) == 0x3)
+		bfin_gpio_reset_spi0_ssel1();
+}
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index fd5f4a6..509a8a2 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -8,7 +8,7 @@
  *
  * Modified:
  *               Copyright 2005 National ICT Australia (NICTA)
- *               Copyright 2004-2006 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -29,6 +29,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -133,12 +134,8 @@
 void sl811_port_power(struct device *dev, int is_on)
 {
 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
 
-	if (is_on)
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
-	else
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
 }
 #endif
 
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 07b0dc2..7725415 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
@@ -103,6 +104,30 @@
 arch_initcall(bfin_isp1761_init);
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PF2, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PF3, 1, "gpio-keys: BTN1"},
+	{BTN_2, GPIO_PF4, 1, "gpio-keys: BTN2"},
+	{BTN_3, GPIO_PF5, 1, "gpio-keys: BTN3"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
 #if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
 static struct resource bfin_pcmcia_cf_resources[] = {
 	{
@@ -226,12 +251,7 @@
 void sl811_port_power(struct device *dev, int is_on)
 {
 	gpio_request(CONFIG_USB_SL811_BFIN_GPIO_VBUS, "usb:SL811_VBUS");
-	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS);
-
-	if (is_on)
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 1);
-	else
-		gpio_set_value(CONFIG_USB_SL811_BFIN_GPIO_VBUS, 0);
+	gpio_direction_output(CONFIG_USB_SL811_BFIN_GPIO_VBUS, is_on);
 }
 #endif
 
@@ -320,6 +340,49 @@
 };
 #endif
 
+static struct mtd_partition stamp_partitions[] = {
+	{
+		.name       = "Bootloader",
+		.size       = 0x20000,
+		.offset     = 0,
+	}, {
+		.name       = "Kernel",
+		.size       = 0xE0000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "RootFS",
+		.size       = 0x400000 - 0x20000 - 0xE0000 - 0x10000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "MAC Address",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = 0x3F0000,
+		.mask_flags = MTD_WRITEABLE,
+	}
+};
+
+static struct physmap_flash_data stamp_flash_data = {
+	.width      = 2,
+	.parts      = stamp_partitions,
+	.nr_parts   = ARRAY_SIZE(stamp_partitions),
+};
+
+static struct resource stamp_flash_resource = {
+	.start = 0x20000000,
+	.end   = 0x203fffff,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device stamp_flash_device = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &stamp_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &stamp_flash_resource,
+};
+
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
 
@@ -738,6 +801,11 @@
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+	&stamp_flash_device,
 };
 
 static int __init stamp_init(void)
diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig
index d8bd3b49..1bfcd8f 100644
--- a/arch/blackfin/mach-bf548/Kconfig
+++ b/arch/blackfin/mach-bf548/Kconfig
@@ -7,7 +7,7 @@
 config DEB_DMA_URGENT
 	bool "DMA has priority over core for ext. accesses"
 	depends on BF54x
-	default n
+	default y
 	help
 	  Treat any DEB1, DEB2 and DEB3 request as Urgent
 
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index d37d665..14860f0 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
 #include <linux/irq.h>
@@ -206,23 +207,6 @@
 };
 #endif
 
-#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
-static struct resource bf54x_hcd_resources[] = {
-	{
-		.start = 0xFFC03C00,
-		.end = 0xFFC040FF,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device bf54x_hcd = {
-	.name = "bf54x-hcd",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(bf54x_hcd_resources),
-	.resource = bf54x_hcd_resources,
-};
-#endif
-
 #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 static struct resource musb_resources[] = {
 	[0] = {
@@ -243,14 +227,14 @@
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
-#ifdef CONFIG_USB_MUSB_OTG
+#if defined(CONFIG_USB_MUSB_OTG)
 	.mode		= MUSB_OTG,
-#elif CONFIG_USB_MUSB_HDRC_HCD
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
 	.mode		= MUSB_HOST,
-#elif CONFIG_USB_GADGET_MUSB_HDRC
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
 	.mode		= MUSB_PERIPHERAL,
 #endif
-	.multipoint	= 1,
+	.multipoint	= 0,
 };
 
 static u64 musb_dmamask = ~(u32)0;
@@ -344,6 +328,44 @@
 };
 #endif
 
+static struct mtd_partition ezkit_partitions[] = {
+	{
+		.name       = "Bootloader",
+		.size       = 0x20000,
+		.offset     = 0,
+	}, {
+		.name       = "Kernel",
+		.size       = 0xE0000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "RootFS",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data ezkit_flash_data = {
+	.width      = 2,
+	.parts      = ezkit_partitions,
+	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
+};
+
+static struct resource ezkit_flash_resource = {
+	.start = 0x20000000,
+	.end   = 0x20ffffff,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ezkit_flash_device = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &ezkit_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &ezkit_flash_resource,
+};
+
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* all SPI peripherals info goes here */
 #if defined(CONFIG_MTD_M25P80) \
@@ -531,6 +553,29 @@
 #endif
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PB8, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PB9, 1, "gpio-keys: BTN1"},
+	{BTN_2, GPIO_PB10, 1, "gpio-keys: BTN2"},
+	{BTN_3, GPIO_PB11, 1, "gpio-keys: BTN3"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
 	&rtc_device,
@@ -548,10 +593,6 @@
 	&smsc911x_device,
 #endif
 
-#if defined(CONFIG_USB_BF54x_HCD) || defined(CONFIG_USB_BF54x_HCD_MODULE)
-	&bf54x_hcd,
-#endif
-
 #if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
 	&musb_device,
 #endif
@@ -583,6 +624,11 @@
 	&i2c_bfin_twi1_device,
 #endif
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+	&ezkit_flash_device,
 };
 
 static int __init stamp_init(void)
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
index 74b34c7..74fe258 100644
--- a/arch/blackfin/mach-bf548/head.S
+++ b/arch/blackfin/mach-bf548/head.S
@@ -298,8 +298,8 @@
 	w[p0] = r0.l;
 	ssync;
 
-	p0.h = hi(SIC_IWR);
-	p0.l = lo(SIC_IWR);
+	p0.h = hi(SIC_IWR0);
+	p0.l = lo(SIC_IWR0);
 	r0.l = 0x1;
 	r0.h = 0x0;
 	[p0] = r0;
@@ -324,12 +324,25 @@
 	w[p0] = r0.l;
 	ssync;
 
+#if defined(CONFIG_BF54x)
+	P2.H = hi(EBIU_RSTCTL);
+	P2.L = lo(EBIU_RSTCTL);
+	R0 = [P2];
+	BITSET (R0, 3);
+#else
 	P2.H = hi(EBIU_SDGCTL);
 	P2.L = lo(EBIU_SDGCTL);
 	R0 = [P2];
 	BITSET (R0, 24);
+#endif
 	[P2] = R0;
 	SSYNC;
+#if defined(CONFIG_BF54x)
+.LSRR_MODE:
+	R0 = [P2];
+	CC = BITTST(R0, 4);
+	if !CC JUMP .LSRR_MODE;
+#endif
 
 	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
 	r0 = r0 << 9;                    /* Shift it over,                  */
@@ -361,6 +374,39 @@
 	w[p0] = r0.l;
 	ssync;
 
+#if defined(CONFIG_BF54x)
+	P2.H = hi(EBIU_RSTCTL);
+	P2.L = lo(EBIU_RSTCTL);
+	R0 = [P2];
+	CC = BITTST(R0, 0);
+	if CC jump .Lskipddrrst;
+	BITSET (R0, 0);
+.Lskipddrrst:
+	BITCLR (R0, 3);
+	[P2] = R0;
+	SSYNC;
+
+	p0.l = lo(EBIU_DDRCTL0);
+	p0.h = hi(EBIU_DDRCTL0);
+	r0.l = lo(mem_DDRCTL0);
+	r0.h = hi(mem_DDRCTL0);
+	[p0] = r0;
+	ssync;
+
+	p0.l = lo(EBIU_DDRCTL1);
+	p0.h = hi(EBIU_DDRCTL1);
+	r0.l = lo(mem_DDRCTL1);
+	r0.h = hi(mem_DDRCTL1);
+	[p0] = r0;
+	ssync;
+
+	p0.l = lo(EBIU_DDRCTL2);
+	p0.h = hi(EBIU_DDRCTL2);
+	r0.l = lo(mem_DDRCTL2);
+	r0.h = hi(mem_DDRCTL2);
+	[p0] = r0;
+	ssync;
+#else
 	p0.l = lo(EBIU_SDRRC);
 	p0.h = hi(EBIU_SDRRC);
 	r0 = mem_SDRRC;
@@ -394,9 +440,10 @@
 	R1 = R1 | R0;
 	[P2] = R1;
 	SSYNC;
+#endif
 
-	p0.h = hi(SIC_IWR);
-	p0.l = lo(SIC_IWR);
+	p0.h = hi(SIC_IWR0);
+	p0.l = lo(SIC_IWR0);
 	r0.l = lo(IWR_ENABLE_ALL);
 	r0.h = hi(IWR_ENABLE_ALL);
 	[p0] = r0;
diff --git a/arch/blackfin/mach-bf548/ints-priority.c b/arch/blackfin/mach-bf548/ints-priority.c
index cb0ebac..2665653 100644
--- a/arch/blackfin/mach-bf548/ints-priority.c
+++ b/arch/blackfin/mach-bf548/ints-priority.c
@@ -4,7 +4,7 @@
  * Author:       Michael Hennerich
  *
  * Created:
- * Description:  Set up the interupt priorities
+ * Description:  Set up the interrupt priorities
  *
  * Modified:
  *               Copyright 2004-2006 Analog Devices Inc.
@@ -58,7 +58,7 @@
 			    ((CONFIG_IRQ_PINT1 - 7) << IRQ_PINT1_POS) |
 			    ((CONFIG_IRQ_MDMAS0 - 7) << IRQ_MDMAS0_POS) |
 			    ((CONFIG_IRQ_MDMAS1 - 7) << IRQ_MDMAS1_POS) |
-			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCHDOG_POS));
+			    ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCH_POS));
 
 	bfin_write_SIC_IAR3(((CONFIG_IRQ_DMAC1_ERR - 7) << IRQ_DMAC1_ERR_POS) |
 			    ((CONFIG_IRQ_SPORT2_ERR - 7) << IRQ_SPORT2_ERR_POS) |
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index c19cd29..3a79a90 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -198,6 +198,13 @@
 #endif  /* spi master and devices */
 
 
+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
+static struct platform_device hitachi_fb_device = {
+	.name = "hitachi-tx09",
+};
+#endif
+
+
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 
 static struct resource smc91x_resources[] = {
@@ -315,6 +322,10 @@
 
 static struct platform_device *cm_bf561_devices[] __initdata = {
 
+#if defined(CONFIG_FB_HITACHI_TX09) || defined(CONFIG_FB_HITACHI_TX09_MODULE)
+	&hitachi_fb_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 	&bfin_uart_device,
 #endif
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 4ff8f6e..7601c3b 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -29,6 +29,9 @@
 
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/spi/spi.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
@@ -155,6 +158,44 @@
 };
 #endif
 
+static struct mtd_partition ezkit_partitions[] = {
+	{
+		.name       = "Bootloader",
+		.size       = 0x20000,
+		.offset     = 0,
+	}, {
+		.name       = "Kernel",
+		.size       = 0xE0000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "RootFS",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data ezkit_flash_data = {
+	.width      = 2,
+	.parts      = ezkit_partitions,
+	.nr_parts   = ARRAY_SIZE(ezkit_partitions),
+};
+
+static struct resource ezkit_flash_resource = {
+	.start = 0x20000000,
+	.end   = 0x207fffff,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ezkit_flash_device = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &ezkit_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &ezkit_flash_resource,
+};
+
 #ifdef CONFIG_SPI_BFIN
 #if defined(CONFIG_SND_BLACKFIN_AD1836) \
 	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
@@ -246,6 +287,50 @@
 };
 #endif
 
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button bfin_gpio_keys_table[] = {
+	{BTN_0, GPIO_PF5, 1, "gpio-keys: BTN0"},
+	{BTN_1, GPIO_PF6, 1, "gpio-keys: BTN1"},
+	{BTN_2, GPIO_PF7, 1, "gpio-keys: BTN2"},
+	{BTN_3, GPIO_PF8, 1, "gpio-keys: BTN3"},
+};
+
+static struct gpio_keys_platform_data bfin_gpio_keys_data = {
+	.buttons        = bfin_gpio_keys_table,
+	.nbuttons       = ARRAY_SIZE(bfin_gpio_keys_table),
+};
+
+static struct platform_device bfin_device_gpiokeys = {
+	.name      = "gpio-keys",
+	.dev = {
+		.platform_data = &bfin_gpio_keys_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+#include <linux/i2c-gpio.h>
+
+static struct i2c_gpio_platform_data i2c_gpio_data = {
+	.sda_pin		= 1,
+	.scl_pin		= 0,
+	.sda_is_open_drain	= 0,
+	.scl_is_open_drain	= 0,
+	.udelay			= 40,
+};
+
+static struct platform_device i2c_gpio_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &i2c_gpio_data,
+	},
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
 	&smc91x_device,
@@ -258,12 +343,23 @@
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	&bfin_spi0_device,
 #endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 	&bfin_uart_device,
 #endif
+
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
 	&bfin_pata_device,
 #endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+	&bfin_device_gpiokeys,
+#endif
+
+#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
+	&i2c_gpio_device,
+#endif
+	&ezkit_flash_device,
 };
 
 static int __init ezkit_init(void)
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
index 5d1d21b..1b44e9e 100644
--- a/arch/blackfin/mach-bf561/coreb.c
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -33,7 +33,9 @@
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/fs.h>
 #include <asm/dma.h>
+#include <asm/cacheflush.h>
 
 #define MODULE_VER		"v0.1"
 
@@ -90,11 +92,12 @@
 
 		coreb_dma_done = 0;
 
+		flush_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
 		/* Source Channel */
 		set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+		set_dma_config(CH_MEM_STREAM2_SRC, 0);
 		/* Destination Channel */
 		set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
@@ -135,11 +138,12 @@
 
 		coreb_dma_done = 0;
 
+		invalidate_dcache_range((unsigned long)buf, (unsigned long)(buf+len));
 		/* Source Channel */
 		set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
 		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
 		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
-		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+		set_dma_config(CH_MEM_STREAM2_SRC, 0);
 		/* Destination Channel */
 		set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
 		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
@@ -266,7 +270,7 @@
 		coreb_status |= COREB_IS_RUNNING;
 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
 		SSYNC();
-		spin_lock_irq(&coreb_lock);
+		spin_unlock_irq(&coreb_lock);
 		break;
 #if defined(CONFIG_BF561_COREB_RESET)
 	case CMD_COREB_STOP:
@@ -275,7 +279,7 @@
 		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
 		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
 		coreb_status &= ~COREB_IS_RUNNING;
-		spin_lock_irq(&coreb_lock);
+		spin_unlock_irq(&coreb_lock);
 		break;
 	case CMD_COREB_RESET:
 		printk(KERN_INFO "Resetting Core B\n");
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index 4d7733d..8636d42 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -3,10 +3,9 @@
 #
 
 obj-y := \
-	cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
+	cache.o cacheinit.o entry.o \
 	interrupt.o lock.o irqpanic.o arch_checks.o
 
-obj-$(CONFIG_CPLB_INFO)          += cplbinfo.o
 obj-$(CONFIG_BFIN_SINGLE_CORE)   += ints-priority-sc.o
 obj-$(CONFIG_BFIN_DUAL_CORE)     += ints-priority-dc.o
 obj-$(CONFIG_PM)                 += pm.o dpmc.o
diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
index 39fbc28..b82c096e 100644
--- a/arch/blackfin/mach-common/dpmc.S
+++ b/arch/blackfin/mach-common/dpmc.S
@@ -38,6 +38,9 @@
 #if defined(CONFIG_BF561)
 	P0.H = hi(SICA_IWR1);
 	P0.L = lo(SICA_IWR1);
+#elif defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+	P0.h = HI(SIC_IWR0);
+	P0.l = LO(SIC_IWR0);
 #else
 	P0.h = HI(SIC_IWR);
 	P0.l = LO(SIC_IWR);
@@ -172,7 +175,7 @@
 	call _set_sic_iwr;
 
 	R0 = 0xFFFF (Z);
-	call _set_rtc_istat
+	call _set_rtc_istat;
 
 	P0.H = hi(PLL_CTL);
 	P0.L = lo(PLL_CTL);
@@ -210,7 +213,7 @@
 	call _set_sic_iwr;
 
 	R0 = 0xFFFF (Z);
-	call _set_rtc_istat
+	call _set_rtc_istat;
 
 	P0.H = hi(VR_CTL);
 	P0.L = lo(VR_CTL);
@@ -236,7 +239,7 @@
 
 	call _set_sic_iwr;
 
-	call _set_sdram_srfs;
+	call _set_dram_srfs;
 
 	/* Clear all the interrupts,bits sticky */
 	R0 = 0xFFFF (Z);
@@ -253,7 +256,7 @@
 	SSYNC;
 	IDLE;
 
-	call _unset_sdram_srfs;
+	call _unset_dram_srfs;
 
 	call _test_pll_locked;
 
@@ -285,23 +288,22 @@
 	P3 = R0;
 	R0 = IWR_ENABLE(0);
 	call _set_sic_iwr;
-	call _set_sdram_srfs;
+	call _set_dram_srfs;	/* Set SDRAM Self Refresh */
 
 	/* Clear all the interrupts,bits sticky */
 	R0 = 0xFFFF (Z);
-	call _set_rtc_istat
-
+	call _set_rtc_istat;
 	P0.H = hi(PLL_DIV);
 	P0.L = lo(PLL_DIV);
 	R6 = W[P0](z);
 	R0.L = 0xF;
-	W[P0] = R0.l;
+	W[P0] = R0.l;		/* Set Max VCO to SCLK divider */
 
 	P0.H = hi(PLL_CTL);
 	P0.L = lo(PLL_CTL);
 	R5 = W[P0](z);
 	R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9;
-	W[P0] = R0.l;
+	W[P0] = R0.l;		/* Set Min CLKIN to VCO multiplier */
 
 	SSYNC;
 	IDLE;
@@ -317,29 +319,28 @@
 	R1 = R1|R2;
 
 	R2 = DEPOSIT(R7, R1);
-	W[P0] = R2;
+	W[P0] = R2;		/* Set Min Core Voltage */
 
 	SSYNC;
 	IDLE;
 
 	call _test_pll_locked;
 
+	R0 = P3;
+	call _set_sic_iwr;	/* Set Awake from IDLE */
+
 	P0.H = hi(PLL_CTL);
 	P0.L = lo(PLL_CTL);
 	R0 = W[P0](z);
 	BITSET (R0, 3);
-	W[P0] = R0.L;
-
-	R0 = P3;
-	call _set_sic_iwr;
-
+	W[P0] = R0.L;		/* Turn CCLK OFF */
 	SSYNC;
 	IDLE;
 
 	call _test_pll_locked;
 
 	R0 = IWR_ENABLE(0);
-	call _set_sic_iwr;
+	call _set_sic_iwr;	/* Set Awake from IDLE PLL */
 
 	P0.H = hi(VR_CTL);
 	P0.L = lo(VR_CTL);
@@ -352,15 +353,15 @@
 
 	P0.H = hi(PLL_DIV);
 	P0.L = lo(PLL_DIV);
-	W[P0]= R6;
+	W[P0]= R6;		/* Restore CCLK and SCLK divider */
 
 	P0.H = hi(PLL_CTL);
 	P0.L = lo(PLL_CTL);
-	w[p0] = R5;
+	w[p0] = R5;		/* Restore VCO multiplier */
 	IDLE;
 	call _test_pll_locked;
 
-	call _unset_sdram_srfs;
+	call _unset_dram_srfs;	/* SDRAM Self Refresh Off */
 
 	STI R4;
 
@@ -368,25 +369,47 @@
 	( R7:0, P5:0 ) = [SP++];
 	RTS;
 
-ENTRY(_set_sdram_srfs)
-	/*  set the sdram to self refresh mode */
+ENTRY(_set_dram_srfs)
+	/*  set the dram to self refresh mode */
+#if defined(CONFIG_BF54x)
+	P0.H = hi(EBIU_RSTCTL);
+	P0.L = lo(EBIU_RSTCTL);
+	R2 = [P0];
+	R3.H = hi(SRREQ);
+	R3.L = lo(SRREQ);
+#else
 	P0.H = hi(EBIU_SDGCTL);
 	P0.L = lo(EBIU_SDGCTL);
 	R2 = [P0];
 	R3.H = hi(SRFS);
 	R3.L = lo(SRFS);
+#endif
 	R2 = R2|R3;
 	[P0] = R2;
 	ssync;
+#if defined(CONFIG_BF54x)
+.LSRR_MODE:
+	R2 = [P0];
+	CC = BITTST(R2, 4);
+	if !CC JUMP .LSRR_MODE;
+#endif
 	RTS;
 
-ENTRY(_unset_sdram_srfs)
-	/*  set the sdram out of self refresh mode */
+ENTRY(_unset_dram_srfs)
+	/*  set the dram out of self refresh mode */
+#if defined(CONFIG_BF54x)
+	P0.H = hi(EBIU_RSTCTL);
+	P0.L = lo(EBIU_RSTCTL);
+	R2 = [P0];
+	R3.H = hi(SRREQ);
+	R3.L = lo(SRREQ);
+#else
 	P0.H = hi(EBIU_SDGCTL);
 	P0.L = lo(EBIU_SDGCTL);
 	R2 = [P0];
 	R3.H = hi(SRFS);
 	R3.L = lo(SRFS);
+#endif
 	R3 = ~R3;
 	R2 = R2&R3;
 	[P0] = R2;
@@ -394,8 +417,13 @@
 	RTS;
 
 ENTRY(_set_sic_iwr)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+	P0.H = hi(SIC_IWR0);
+	P0.L = lo(SIC_IWR0);
+#else
 	P0.H = hi(SIC_IWR);
 	P0.L = lo(SIC_IWR);
+#endif
 	[P0] = R0;
 	SSYNC;
 	RTS;
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index dc9d3ee..56ff51b 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -95,6 +95,9 @@
 	R6 = 0x26;	/* Data CPLB Miss */
 	cc = R6 == R7;
 	if cc jump _ex_dcplb_miss (BP);
+	R6 = 0x23;	/* Data CPLB Miss */
+	cc = R6 == R7;
+	if cc jump _ex_dcplb_viol (BP);
 	/* Handle 0x23 Data CPLB Protection Violation
 	 * and Data CPLB Multiple Hits - Linux Trap Zero
 	 */
@@ -102,17 +105,33 @@
 ENDPROC(_ex_workaround_261)
 
 #else
+#ifdef CONFIG_MPU
+#define _ex_dviol _ex_dcplb_viol
+#else
 #define _ex_dviol _ex_trap_c
+#endif
 #define _ex_dmiss _ex_dcplb_miss
 #define _ex_dmult _ex_trap_c
 #endif
 
+
+ENTRY(_ex_dcplb_viol)
 ENTRY(_ex_dcplb_miss)
 ENTRY(_ex_icplb_miss)
 	(R7:6,P5:4) = [sp++];
 	ASTAT = [sp++];
 	SAVE_ALL_SYS
+#ifdef CONFIG_MPU
+	R0 = SEQSTAT;
+	R1 = SP;
+	sp += -12;
+	call _cplb_hdr;
+	sp += 12;
+	CC = R0 == 0;
+	IF !CC JUMP _handle_bad_cplb;
+#else
 	call __cplb_hdr;
+#endif
 	DEBUG_START_HWTRACE(p5, r7)
 	RESTORE_ALL_SYS
 	SP = EX_SCRATCH_REG;
@@ -329,7 +348,7 @@
 	R7 = R7 + R6;
 	P5 = R7;
 	R1 = [P5];
-	[SP + 8] = r1;
+	[SP + PT_SEQSTAT] = r1;
 
 	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */
 	SP += -12;
@@ -633,9 +652,7 @@
 	[sp + PT_IPEND] = r0;
 
 1:
-	r1 = 0x37(Z);
-	r2 = ~r1;
-	r2.h = 0;
+	r2 = LO(~0x37) (Z);
 	r0 = r2 & r0;
 	cc = r0 == 0;
 	if !cc jump 4f;	/* if not return to user mode, get out */
@@ -1364,6 +1381,7 @@
 	.long _sys_set_robust_list
 	.long _sys_get_robust_list	/* 355 */
 	.long _sys_fallocate
+	.long _sys_semtimedop
 	.rept NR_syscalls-(.-_sys_call_table)/4
 	.long _sys_ni_syscall
 	.endr
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 4de3764..7f752c8 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -34,9 +34,13 @@
 #include <asm/entry.h>
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
+#include <asm/traps.h>
+#include <asm/thread_info.h>
 
 #include <asm/mach-common/context.S>
 
+.extern _ret_from_exception
+
 #ifdef CONFIG_I_ENTRY_L1
 .section .l1.text
 #else
@@ -117,8 +121,8 @@
 
 #if ANOMALY_05000283 || ANOMALY_05000315
 	cc = r7 == r7;
-	p5.h = 0xffc0;
-	p5.l = 0x0014;
+	p5.h = HI(CHIPID);
+	p5.l = LO(CHIPID);
 	if cc jump 1f;
 	r7.l = W[p5];
 1:
@@ -134,26 +138,22 @@
 
 /* interrupt routine for ivhw - 5 */
 ENTRY(_evt_ivhw)
-	SAVE_CONTEXT
+	SAVE_ALL_SYS
 #ifdef CONFIG_FRAME_POINTER
 	fp = 0;
 #endif
+
 #if ANOMALY_05000283
 	cc = r7 == r7;
-	p5.h = 0xffc0;
-	p5.l = 0x0014;
+	p5.h = HI(CHIPID);
+	p5.l = LO(CHIPID);
 	if cc jump 1f;
 	r7.l = W[p5];
 1:
 #endif
 
-	trace_buffer_stop(p0, r0);
-
-	r0 = IRQ_HWERR;
-	r1 = sp;
-
 #ifdef CONFIG_HARDWARE_PM
-	r7 = SEQSTAT;
+	r7 = [sp + PT_SEQSTAT];
 	r7 = r7 >>> 0xe;
 	r6 = 0x1F;
 	r7 = r7 & r6;
@@ -161,11 +161,29 @@
 	cc = r7 == r5;
 	if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
 #endif
+	# We are going to dump something out, so make sure we print IPEND properly
+	p2.l = lo(IPEND);
+	p2.h = hi(IPEND);
+	r0 = [p2];
+	[sp + PT_IPEND] = r0;
 
+	/* set the EXCAUSE to HWERR for trap_c */
+	r0 = [sp + PT_SEQSTAT];
+	R1.L = LO(VEC_HWERR);
+	R1.H = HI(VEC_HWERR);
+	R0 = R0 | R1;
+	[sp + PT_SEQSTAT] = R0;
+
+	r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
 	SP += -12;
-	call _irq_panic;
+	call _trap_c;
 	SP += 12;
+
+	call _ret_from_exception;
+.Lcommon_restore_all_sys:
+	RESTORE_ALL_SYS
 	rti;
+
 #ifdef CONFIG_HARDWARE_PM
 .Lcall_do_ovf:
 
@@ -173,9 +191,11 @@
 	call _pm_overflow;
 	SP += 12;
 
-	jump .Lcommon_restore_context;
+	jump .Lcommon_restore_all_sys;
 #endif
 
+ENDPROC(_evt_ivhw)
+
 /* Interrupt routine for evt2 (NMI).
  * We don't actually use this, so just return.
  * For inner circle type details, please see:
diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
index 4882f0e..8d18d6b 100644
--- a/arch/blackfin/mach-common/ints-priority-dc.c
+++ b/arch/blackfin/mach-common/ints-priority-dc.c
@@ -222,11 +222,12 @@
 static unsigned int bf561_gpio_irq_startup(unsigned int irq)
 {
 	unsigned int ret;
+	char buf[8];
 	u16 gpionr = irq - IRQ_PF0;
 
 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-
-		ret = gpio_request(gpionr, "IRQ");
+		snprintf(buf, sizeof buf, "IRQ %d", irq);
+		ret = gpio_request(gpionr, buf);
 		if (ret)
 			return ret;
 
@@ -250,6 +251,7 @@
 {
 
 	unsigned int ret;
+	char buf[8];
 	u16 gpionr = irq - IRQ_PF0;
 
 
@@ -265,8 +267,8 @@
 			    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
 
 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-
-			ret = gpio_request(gpionr, "IRQ");
+			snprintf(buf, sizeof buf, "IRQ %d", irq);
+			ret = gpio_request(gpionr, buf);
 			if (ret)
 				return ret;
 
diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
index 147f073..dec42ac 100644
--- a/arch/blackfin/mach-common/ints-priority-sc.c
+++ b/arch/blackfin/mach-common/ints-priority-sc.c
@@ -313,6 +313,7 @@
 static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
 static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
 
+
 static void bfin_gpio_ack_irq(unsigned int irq)
 {
 	u16 gpionr = irq - IRQ_PF0;
@@ -352,9 +353,11 @@
 {
 	unsigned int ret;
 	u16 gpionr = irq - IRQ_PF0;
+	char buf[8];
 
 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-		ret = gpio_request(gpionr, "IRQ");
+		snprintf(buf, sizeof buf, "IRQ %d", irq);
+		ret = gpio_request(gpionr, buf);
 		if (ret)
 			return ret;
 	}
@@ -376,6 +379,7 @@
 {
 
 	unsigned int ret;
+	char buf[8];
 	u16 gpionr = irq - IRQ_PF0;
 
 	if (type == IRQ_TYPE_PROBE) {
@@ -388,7 +392,8 @@
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-			ret = gpio_request(gpionr, "IRQ");
+			snprintf(buf, sizeof buf, "IRQ %d", irq);
+			ret = gpio_request(gpionr, buf);
 			if (ret)
 				return ret;
 		}
@@ -478,6 +483,10 @@
 static unsigned char irq2pint_lut[NR_PINTS];
 static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
 
+static unsigned int gpio_both_edge_triggered[NR_PINT_SYS_IRQS];
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+
 struct pin_int_t {
 	unsigned int mask_set;
 	unsigned int mask_clear;
@@ -544,13 +553,20 @@
 
 }
 
-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-
 static void bfin_gpio_ack_irq(unsigned int irq)
 {
 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+	u32 pintbit = PINT_BIT(pint_val);
+	u8 bank = PINT_2_BANK(pint_val);
 
-	pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
+	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+		if (pint[bank]->invert_set & pintbit)
+			pint[bank]->invert_clear = pintbit;
+		else
+			pint[bank]->invert_set = pintbit;
+	}
+	pint[bank]->request = pintbit;
+
 	SSYNC();
 }
 
@@ -560,6 +576,13 @@
 	u32 pintbit = PINT_BIT(pint_val);
 	u8 bank = PINT_2_BANK(pint_val);
 
+	if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+		if (pint[bank]->invert_set & pintbit)
+			pint[bank]->invert_clear = pintbit;
+		else
+			pint[bank]->invert_set = pintbit;
+	}
+
 	pint[bank]->request = pintbit;
 	pint[bank]->mask_clear = pintbit;
 	SSYNC();
@@ -587,7 +610,8 @@
 static unsigned int bfin_gpio_irq_startup(unsigned int irq)
 {
 	unsigned int ret;
-	u16 gpionr = irq - IRQ_PA0;
+	char buf[8];
+	u16 gpionr = irq_to_gpio(irq);
 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
 
 	if (pint_val == IRQ_NOT_AVAIL) {
@@ -598,7 +622,8 @@
 	}
 
 	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-		ret = gpio_request(gpionr, "IRQ");
+		snprintf(buf, sizeof buf, "IRQ %d", irq);
+		ret = gpio_request(gpionr, buf);
 		if (ret)
 			return ret;
 	}
@@ -611,16 +636,19 @@
 
 static void bfin_gpio_irq_shutdown(unsigned int irq)
 {
+	u16 gpionr = irq_to_gpio(irq);
+
 	bfin_gpio_mask_irq(irq);
-	gpio_free(irq - IRQ_PA0);
-	gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
+	gpio_free(gpionr);
+	gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
 }
 
 static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 {
 
 	unsigned int ret;
-	u16 gpionr = irq - IRQ_PA0;
+	char buf[8];
+	u16 gpionr = irq_to_gpio(irq);
 	u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
 	u32 pintbit = PINT_BIT(pint_val);
 	u8 bank = PINT_2_BANK(pint_val);
@@ -638,7 +666,8 @@
 	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
 		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
 		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-			ret = gpio_request(gpionr, "IRQ");
+			snprintf(buf, sizeof buf, "IRQ %d", irq);
+			ret = gpio_request(gpionr, buf);
 			if (ret)
 				return ret;
 		}
@@ -651,29 +680,34 @@
 
 	gpio_direction_input(gpionr);
 
-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-		pint[bank]->edge_set = pintbit;
-	} else {
-		pint[bank]->edge_clear = pintbit;
-	}
-
 	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
 		pint[bank]->invert_set = pintbit;	/* low or falling edge denoted by one */
 	else
-		pint[bank]->invert_set = pintbit;	/* high or rising edge denoted by zero */
+		pint[bank]->invert_clear = pintbit;	/* high or rising edge denoted by zero */
 
-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-		pint[bank]->invert_set = pintbit;
-	else
-		pint[bank]->invert_set = pintbit;
+	if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+	    == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+
+		gpio_both_edge_triggered[bank] |= pintbit;
+
+		if (gpio_get_value(gpionr))
+			pint[bank]->invert_set = pintbit;
+		else
+			pint[bank]->invert_clear = pintbit;
+	} else {
+		gpio_both_edge_triggered[bank] &= ~pintbit;
+	}
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+		pint[bank]->edge_set = pintbit;
+		set_irq_handler(irq, handle_edge_irq);
+	} else {
+		pint[bank]->edge_clear = pintbit;
+		set_irq_handler(irq, handle_level_irq);
+	}
 
 	SSYNC();
 
-	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-		set_irq_handler(irq, handle_edge_irq);
-	else
-		set_irq_handler(irq, handle_level_irq);
-
 	return 0;
 }
 
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
index b22959b..606ded9 100644
--- a/arch/blackfin/mach-common/irqpanic.c
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -46,9 +46,6 @@
  */
 asmlinkage void irq_panic(int reason, struct pt_regs *regs)
 {
-	int sig = 0;
-	siginfo_t info;
-
 #ifdef CONFIG_DEBUG_ICACHE_CHECK
 	unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
 	unsigned short i, j, die;
@@ -136,53 +133,6 @@
 	}
 #endif
 
-	printk(KERN_EMERG "\n");
-	printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
-	printk(KERN_EMERG " code=[0x%08lx],   stack frame=0x%08lx,  "
-	    " bad PC=0x%08lx\n",
-	    (unsigned long)regs->seqstat,
-	    (unsigned long)regs,
-	    (unsigned long)regs->pc);
-	if (reason == 0x5) {
-		printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
-
-		/* There is only need to check for Hardware Errors, since other
-		 * EXCEPTIONS are handled in TRAPS.c (MH)
-		 */
-		switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
-		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):	/* System MMR Error */
-			info.si_code = BUS_ADRALN;
-			sig = SIGBUS;
-			printk(KERN_EMERG HWC_x2(KERN_EMERG));
-			break;
-		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):	/* External Memory Addressing Error */
-			info.si_code = BUS_ADRERR;
-			sig = SIGBUS;
-			printk(KERN_EMERG HWC_x3(KERN_EMERG));
-			break;
-		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):	/* Performance Monitor Overflow */
-			printk(KERN_EMERG HWC_x12(KERN_EMERG));
-			break;
-		case (SEQSTAT_HWERRCAUSE_RAISE_5):	/* RAISE 5 instruction */
-			printk(KERN_EMERG HWC_x18(KERN_EMERG));
-			break;
-		default:	/* Reserved */
-			printk(KERN_EMERG HWC_default(KERN_EMERG));
-			break;
-		}
-	}
-
-	regs->ipend = bfin_read_IPEND();
-	dump_bfin_process(regs);
-	dump_bfin_mem((void *)regs->pc);
-	show_regs(regs);
-	if (0 == (info.si_signo = sig) || 0 == user_mode(regs))	/* in kernelspace */
-		panic("Unhandled IRQ or exceptions!\n");
-	else {			/* in userspace */
-		info.si_errno = 0;
-		info.si_addr = (void *)regs->pc;
-		force_sig_info(sig, &info, current);
-	}
 }
 
 #ifdef CONFIG_HARDWARE_PM
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index dac51fb..81930f7 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -77,7 +77,15 @@
 
 		gpio_pm_restore();
 
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+		bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
+		bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
+# ifdef CONFIG_BF54x
+		bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
+# endif
+#else
 		bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+#endif
 
 		local_irq_restore(flags);
 	}
@@ -85,7 +93,15 @@
 
 #if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
 	sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
+# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+	bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
+	bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
+#  ifdef CONFIG_BF54x
+	bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
+#  endif
+# else
 	bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+# endif
 #endif				/* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
 }
 
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index e97ea8f..eb1a12a 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -128,8 +128,8 @@
 void __init mem_init(void)
 {
 	unsigned int codek = 0, datak = 0, initk = 0;
+	unsigned int reservedpages = 0, freepages = 0;
 	unsigned long tmp;
-	unsigned int len = _ramend - _rambase;
 	unsigned long start_mem = memory_start;
 	unsigned long end_mem = memory_end;
 
@@ -138,19 +138,36 @@
 
 	start_mem = PAGE_ALIGN(start_mem);
 	max_mapnr = num_physpages = MAP_NR(high_memory);
-	printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
+	printk(KERN_INFO "Kernel managed physical pages: %lu\n",
+		num_physpages);
 
 	/* This will put all memory onto the freelists. */
 	totalram_pages = free_all_bootmem();
 
-	codek = (_etext - _stext) >> 10;
-	datak = (__bss_stop - __bss_start) >> 10;
-	initk = (__init_end - __init_begin) >> 10;
+	reservedpages = 0;
+	for (tmp = 0; tmp < max_mapnr; tmp++)
+		if (PageReserved(pfn_to_page(tmp)))
+			reservedpages++;
+	freepages =  max_mapnr - reservedpages;
 
-	tmp = nr_free_pages() << PAGE_SHIFT;
+	/* do not count in kernel image between _rambase and _ramstart */
+	reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
+#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
+	reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >>
+				PAGE_SHIFT;
+#endif
+
+	codek = (_etext - _stext) >> 10;
+	initk = (__init_end - __init_begin) >> 10;
+	datak = ((_ramstart - _rambase) >> 10) - codek - initk;
+
 	printk(KERN_INFO
-	     "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
-	     tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
+	     "Memory available: %luk/%luk RAM, "
+		"(%uk init code, %uk kernel code, "
+		"%uk data, %uk dma, %uk reserved)\n",
+		(unsigned long) freepages << (PAGE_SHIFT-10), _ramend >> 10,
+		initk, codek, datak, DMA_UNCACHED_REGION >> 10,
+		(reservedpages << (PAGE_SHIFT-10)));
 
 	/* Initialize the blackfin L1 Memory. */
 	l1sram_init();
@@ -184,13 +201,15 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
+#ifndef CONFIG_MPU
 	free_init_pages("initrd memory", start, end);
+#endif
 }
 #endif
 
 void __init free_initmem(void)
 {
-#ifdef CONFIG_RAMKERNEL
+#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
 	free_init_pages("unused kernel memory",
 			(unsigned long)(&__init_begin),
 			(unsigned long)(&__init_end));
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index d51e18f..841904c 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -270,6 +270,24 @@
 
 #endif
 
+/* All Alchemy demoboards with I2C have this #define in their headers */
+#ifdef SMBUS_PSC_BASE
+static struct resource pbdb_smbus_resources[] = {
+	{
+		.start	= SMBUS_PSC_BASE,
+		.end	= SMBUS_PSC_BASE + 0x24 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device pbdb_smbus_device = {
+	.name		= "au1xpsc_smbus",
+	.id		= 0,	/* bus number */
+	.num_resources	= ARRAY_SIZE(pbdb_smbus_resources),
+	.resource	= pbdb_smbus_resources,
+};
+#endif
+
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1xxx_usb_ohci_device,
 	&au1x00_pcmcia_device,
@@ -287,6 +305,9 @@
 #ifdef CONFIG_MIPS_DB1200
 	&smc91x_device,
 #endif
+#ifdef SMBUS_PSC_BASE
+	&pbdb_smbus_device,
+#endif
 };
 
 int __init au1xxx_platform_init(void)
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index b84f8df..cb0a749 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -224,26 +224,6 @@
 	ipic_set_default_priority();
 }
 
-#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
-extern ulong	ds1374_get_rtc_time(void);
-extern int	ds1374_set_rtc_time(ulong);
-
-static int __init
-mpc834x_rtc_hookup(void)
-{
-	struct timespec	tv;
-
-	ppc_md.get_rtc_time = ds1374_get_rtc_time;
-	ppc_md.set_rtc_time = ds1374_set_rtc_time;
-
-	tv.tv_nsec = 0;
-	tv.tv_sec = (ppc_md.get_rtc_time)();
-	do_settimeofday(&tv);
-
-	return 0;
-}
-late_initcall(mpc834x_rtc_hookup);
-#endif
 static __inline__ void
 mpc834x_sys_set_bat(void)
 {
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
index 4ee2bd1..27ce389 100644
--- a/arch/ppc/platforms/85xx/tqm85xx.c
+++ b/arch/ppc/platforms/85xx/tqm85xx.c
@@ -258,27 +258,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337)
-extern ulong ds1337_get_rtc_time(void);
-extern int ds1337_set_rtc_time(unsigned long nowtime);
-
-static int __init
-tqm85xx_rtc_hookup(void)
-{
-	struct timespec	tv;
-
-        ppc_md.set_rtc_time = ds1337_set_rtc_time;
-        ppc_md.get_rtc_time = ds1337_get_rtc_time;
-
-	tv.tv_nsec = 0;
-	tv.tv_sec = (ppc_md.get_rtc_time)();
-	do_settimeofday(&tv);
-
-	return 0;
-}
-late_initcall(tqm85xx_rtc_hookup);
-#endif
-
 #ifdef CONFIG_PCI
 /*
  * interrupt routing
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
index 52f63e6..fe6e88c 100644
--- a/arch/ppc/platforms/katana.c
+++ b/arch/ppc/platforms/katana.c
@@ -838,27 +838,6 @@
 	return bdp->bi_memsize;
 }
 
-#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
-extern ulong	m41t00_get_rtc_time(void);
-extern int	m41t00_set_rtc_time(ulong);
-
-static int __init
-katana_rtc_hookup(void)
-{
-	struct timespec	tv;
-
-	ppc_md.get_rtc_time = m41t00_get_rtc_time;
-	ppc_md.set_rtc_time = m41t00_set_rtc_time;
-
-	tv.tv_nsec = 0;
-	tv.tv_sec = (ppc_md.get_rtc_time)();
-	do_settimeofday(&tv);
-
-	return 0;
-}
-late_initcall(katana_rtc_hookup);
-#endif
-
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
 static void __init
 katana_map_io(void)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1330061..6ef54d2 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -276,9 +276,6 @@
 
 source "mm/Kconfig"
 
-config HOLES_IN_ZONE
-	def_bool y
-
 comment "I/O subsystem configuration"
 
 config MACHCHK_WARNING
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
deleted file mode 100644
index d1defbb..0000000
--- a/arch/s390/crypto/Kconfig
+++ /dev/null
@@ -1,60 +0,0 @@
-config CRYPTO_SHA1_S390
-	tristate "SHA1 digest algorithm"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
-config CRYPTO_SHA256_S390
-	tristate "SHA256 digest algorithm"
-	depends on S390
-	select CRYPTO_ALGAPI
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  SHA256 secure hash standard (DFIPS 180-2).
-
-	  This version of SHA implements a 256 bit hash with 128 bits of
-	  security against collision attacks.
-
-config CRYPTO_DES_S390
-	tristate "DES and Triple DES cipher algorithms"
-	depends on S390
-	select CRYPTO_ALGAPI
-	select CRYPTO_BLKCIPHER
-	help
-	  This us the s390 hardware accelerated implementation of the
-	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
-config CRYPTO_AES_S390
-	tristate "AES cipher algorithms"
-	depends on S390
-	select CRYPTO_ALGAPI
-	select CRYPTO_BLKCIPHER
-	help
-	  This is the s390 hardware accelerated implementation of the
-	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
-	  algorithm.
-
-	  Rijndael appears to be consistently a very good performer in
-	  both hardware and software across a wide range of computing
-	  environments regardless of its use in feedback or non-feedback
-	  modes. Its key setup time is excellent, and its key agility is
-	  good. Rijndael's very low memory requirements make it very well
-	  suited for restricted-space environments, in which it also
-	  demonstrates excellent performance. Rijndael's operations are
-	  among the easiest to defend against power and timing attacks.
-
-	  On s390 the System z9-109 currently only supports the key size
-	  of 128 bit.
-
-config S390_PRNG
-	tristate "Pseudo random number generator device driver"
-	depends on S390
-	default "m"
-	help
-	  Select this option if you want to use the s390 pseudo random number
-	  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/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 46c97058..a3f67f8 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -516,7 +516,7 @@
 	/* z9 109 and z9 BC/EC only support 128 bit key length */
 	if (keylen_flag == AES_KEYLEN_128)
 		printk(KERN_INFO
-		       "aes_s390: hardware acceleration only available for"
+		       "aes_s390: hardware acceleration only available for "
 		       "128 bit keys\n");
 
 	ret = crypto_register_alg(&aes_alg);
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
index 8eb3a1a..0cfefdd 100644
--- a/arch/s390/crypto/prng.c
+++ b/arch/s390/crypto/prng.c
@@ -90,7 +90,7 @@
 	int ret = 0;
 	int tmp;
 
-	/* nbytes can be arbitrary long, we spilt it into chunks */
+	/* nbytes can be arbitrary length, we split it into chunks */
 	while (nbytes) {
 		/* same as in extract_entropy_user in random.c */
 		if (need_resched()) {
@@ -146,7 +146,7 @@
 	return ret;
 }
 
-static struct file_operations prng_fops = {
+static const struct file_operations prng_fops = {
 	.owner		= THIS_MODULE,
 	.open		= &prng_open,
 	.release	= NULL,
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 56cb710..b3b650a 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -31,7 +31,3 @@
 S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
 obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
 
-#
-# This is just to get the dependencies...
-#
-binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 1b3af7d..9f7b73b 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -276,7 +276,7 @@
 	create_kernel_nss();
 	sort_main_extable();
 	setup_lowcore_early();
-	sclp_readinfo_early();
+	sclp_read_info_early();
 	sclp_facilities_detect();
 	memsize = sclp_memory_detect();
 #ifndef CONFIG_64BIT
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index a87b197..79dccd2 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -157,7 +157,7 @@
 	.long	0xb2b10000		# store facility list
 	tm	0xc8,0x08		# check bit for clearing-by-ASCE
 	bno	0f-.LPG1(%r13)
-	lhi	%r1,2094
+	lhi	%r1,2048
 	lhi	%r2,0
 	.long	0xb98e2001
 	oi	7(%r12),0x80		# set IDTE flag
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index b97694f..db28cca 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/ipl.c
  *    ipl/reipl/dump support for Linux on s390.
  *
- *    Copyright (C) IBM Corp. 2005,2006
+ *    Copyright IBM Corp. 2005,2007
  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  *		 Heiko Carstens <heiko.carstens@de.ibm.com>
  *		 Volker Sameske <sameske@de.ibm.com>
@@ -31,6 +31,43 @@
 #define IPL_FCP_DUMP_STR	"fcp_dump"
 #define IPL_NSS_STR		"nss"
 
+#define DUMP_CCW_STR		"ccw"
+#define DUMP_FCP_STR		"fcp"
+#define DUMP_NONE_STR		"none"
+
+/*
+ * Four shutdown trigger types are supported:
+ * - panic
+ * - halt
+ * - power off
+ * - reipl
+ */
+#define ON_PANIC_STR		"on_panic"
+#define ON_HALT_STR		"on_halt"
+#define ON_POFF_STR		"on_poff"
+#define ON_REIPL_STR		"on_reboot"
+
+struct shutdown_action;
+struct shutdown_trigger {
+	char *name;
+	struct shutdown_action *action;
+};
+
+/*
+ * Five shutdown action types are supported:
+ */
+#define SHUTDOWN_ACTION_IPL_STR		"ipl"
+#define SHUTDOWN_ACTION_REIPL_STR	"reipl"
+#define SHUTDOWN_ACTION_DUMP_STR	"dump"
+#define SHUTDOWN_ACTION_VMCMD_STR	"vmcmd"
+#define SHUTDOWN_ACTION_STOP_STR	"stop"
+
+struct shutdown_action {
+	char *name;
+	void (*fn) (struct shutdown_trigger *trigger);
+	int (*init) (void);
+};
+
 static char *ipl_type_str(enum ipl_type type)
 {
 	switch (type) {
@@ -54,10 +91,6 @@
 	DUMP_TYPE_FCP	= 4,
 };
 
-#define DUMP_NONE_STR	 "none"
-#define DUMP_CCW_STR	 "ccw"
-#define DUMP_FCP_STR	 "fcp"
-
 static char *dump_type_str(enum dump_type type)
 {
 	switch (type) {
@@ -99,30 +132,6 @@
 	DUMP_METHOD_FCP_DIAG,
 };
 
-enum shutdown_action {
-	SHUTDOWN_REIPL,
-	SHUTDOWN_DUMP,
-	SHUTDOWN_STOP,
-};
-
-#define SHUTDOWN_REIPL_STR "reipl"
-#define SHUTDOWN_DUMP_STR  "dump"
-#define SHUTDOWN_STOP_STR  "stop"
-
-static char *shutdown_action_str(enum shutdown_action action)
-{
-	switch (action) {
-	case SHUTDOWN_REIPL:
-		return SHUTDOWN_REIPL_STR;
-	case SHUTDOWN_DUMP:
-		return SHUTDOWN_DUMP_STR;
-	case SHUTDOWN_STOP:
-		return SHUTDOWN_STOP_STR;
-	default:
-		return NULL;
-	}
-}
-
 static int diag308_set_works = 0;
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
@@ -140,8 +149,6 @@
 static struct ipl_parameter_block *dump_block_fcp;
 static struct ipl_parameter_block *dump_block_ccw;
 
-static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
-
 static struct sclp_ipl_info sclp_ipl_info;
 
 int diag308(unsigned long subcode, void *addr)
@@ -205,8 +212,8 @@
 		struct kobj_attribute *attr,				\
 		const char *buf, size_t len)				\
 {									\
-	if (sscanf(buf, _fmt_in, _value) != 1)				\
-		return -EINVAL;						\
+	strncpy(_value, buf, sizeof(_value) - 1);			\
+	strstrip(_value);						\
 	return len;							\
 }									\
 static struct kobj_attribute sys_##_prefix##_##_name##_attr =		\
@@ -245,33 +252,6 @@
 	return IPL_TYPE_FCP;
 }
 
-void __init setup_ipl_info(void)
-{
-	ipl_info.type = get_ipl_type();
-	switch (ipl_info.type) {
-	case IPL_TYPE_CCW:
-		ipl_info.data.ccw.dev_id.devno = ipl_devno;
-		ipl_info.data.ccw.dev_id.ssid = 0;
-		break;
-	case IPL_TYPE_FCP:
-	case IPL_TYPE_FCP_DUMP:
-		ipl_info.data.fcp.dev_id.devno =
-			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
-		ipl_info.data.fcp.dev_id.ssid = 0;
-		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
-		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
-		break;
-	case IPL_TYPE_NSS:
-		strncpy(ipl_info.data.nss.name, kernel_nss_name,
-			sizeof(ipl_info.data.nss.name));
-		break;
-	case IPL_TYPE_UNKNOWN:
-	default:
-		/* We have no info to copy */
-		break;
-	}
-}
-
 struct ipl_info ipl_info;
 EXPORT_SYMBOL_GPL(ipl_info);
 
@@ -428,8 +408,74 @@
 
 static struct kset *ipl_kset;
 
+static int __init ipl_register_fcp_files(void)
+{
+	int rc;
+
+	rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+	if (rc)
+		goto out;
+	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+	if (rc)
+		goto out_ipl_parm;
+	rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
+	if (!rc)
+		goto out;
+
+	sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+
+out_ipl_parm:
+	sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+out:
+	return rc;
+}
+
+static void ipl_run(struct shutdown_trigger *trigger)
+{
+	diag308(DIAG308_IPL, NULL);
+	if (MACHINE_IS_VM)
+		__cpcmd("IPL", NULL, 0, NULL);
+	else if (ipl_info.type == IPL_TYPE_CCW)
+		reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
+}
+
+static int ipl_init(void)
+{
+	int rc;
+
+	ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
+	if (!ipl_kset) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	switch (ipl_info.type) {
+	case IPL_TYPE_CCW:
+		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
+		break;
+	case IPL_TYPE_FCP:
+	case IPL_TYPE_FCP_DUMP:
+		rc = ipl_register_fcp_files();
+		break;
+	case IPL_TYPE_NSS:
+		rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
+		break;
+	default:
+		rc = sysfs_create_group(&ipl_kset->kobj,
+					&ipl_unknown_attr_group);
+		break;
+	}
+out:
+	if (rc)
+		panic("ipl_init failed: rc = %i\n", rc);
+
+	return 0;
+}
+
+static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
+					    ipl_init};
+
 /*
- * reipl section
+ * reipl shutdown action: Reboot Linux on shutdown.
  */
 
 /* FCP reipl device attributes */
@@ -549,7 +595,9 @@
 
 	switch(type) {
 	case IPL_TYPE_CCW:
-		if (MACHINE_IS_VM)
+		if (diag308_set_works)
+			reipl_method = REIPL_METHOD_CCW_DIAG;
+		else if (MACHINE_IS_VM)
 			reipl_method = REIPL_METHOD_CCW_VM;
 		else
 			reipl_method = REIPL_METHOD_CCW_CIO;
@@ -600,12 +648,182 @@
 }
 
 static struct kobj_attribute reipl_type_attr =
-		__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
+	__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
 
 static struct kset *reipl_kset;
 
+void reipl_run(struct shutdown_trigger *trigger)
+{
+	struct ccw_dev_id devid;
+	static char buf[100];
+	char loadparm[LOADPARM_LEN + 1];
+
+	switch (reipl_method) {
+	case REIPL_METHOD_CCW_CIO:
+		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
+		devid.ssid  = 0;
+		reipl_ccw_dev(&devid);
+		break;
+	case REIPL_METHOD_CCW_VM:
+		reipl_get_ascii_loadparm(loadparm);
+		if (strlen(loadparm) == 0)
+			sprintf(buf, "IPL %X CLEAR",
+				reipl_block_ccw->ipl_info.ccw.devno);
+		else
+			sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
+				reipl_block_ccw->ipl_info.ccw.devno, loadparm);
+		__cpcmd(buf, NULL, 0, NULL);
+		break;
+	case REIPL_METHOD_CCW_DIAG:
+		diag308(DIAG308_SET, reipl_block_ccw);
+		diag308(DIAG308_IPL, NULL);
+		break;
+	case REIPL_METHOD_FCP_RW_DIAG:
+		diag308(DIAG308_SET, reipl_block_fcp);
+		diag308(DIAG308_IPL, NULL);
+		break;
+	case REIPL_METHOD_FCP_RO_DIAG:
+		diag308(DIAG308_IPL, NULL);
+		break;
+	case REIPL_METHOD_FCP_RO_VM:
+		__cpcmd("IPL", NULL, 0, NULL);
+		break;
+	case REIPL_METHOD_NSS:
+		sprintf(buf, "IPL %s", reipl_nss_name);
+		__cpcmd(buf, NULL, 0, NULL);
+		break;
+	case REIPL_METHOD_DEFAULT:
+		if (MACHINE_IS_VM)
+			__cpcmd("IPL", NULL, 0, NULL);
+		diag308(DIAG308_IPL, NULL);
+		break;
+	case REIPL_METHOD_FCP_DUMP:
+	default:
+		break;
+	}
+}
+
+static void __init reipl_probe(void)
+{
+	void *buffer;
+
+	buffer = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!buffer)
+		return;
+	if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
+		diag308_set_works = 1;
+	free_page((unsigned long)buffer);
+}
+
+static int __init reipl_nss_init(void)
+{
+	int rc;
+
+	if (!MACHINE_IS_VM)
+		return 0;
+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
+	if (rc)
+		return rc;
+	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+	reipl_capabilities |= IPL_TYPE_NSS;
+	return 0;
+}
+
+static int __init reipl_ccw_init(void)
+{
+	int rc;
+
+	reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!reipl_block_ccw)
+		return -ENOMEM;
+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
+	if (rc) {
+		free_page((unsigned long)reipl_block_ccw);
+		return rc;
+	}
+	reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
+	reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
+	reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
+	reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
+	reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
+	/* check if read scp info worked and set loadparm */
+	if (sclp_ipl_info.is_valid)
+		memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
+		       &sclp_ipl_info.loadparm, LOADPARM_LEN);
+	else
+		/* read scp info failed: set empty loadparm (EBCDIC blanks) */
+		memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
+		       LOADPARM_LEN);
+	if (!MACHINE_IS_VM && !diag308_set_works)
+		sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
+	if (ipl_info.type == IPL_TYPE_CCW)
+		reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
+	reipl_capabilities |= IPL_TYPE_CCW;
+	return 0;
+}
+
+static int __init reipl_fcp_init(void)
+{
+	int rc;
+
+	if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP))
+		return 0;
+	if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP))
+		make_attrs_ro(reipl_fcp_attrs);
+
+	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!reipl_block_fcp)
+		return -ENOMEM;
+	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
+	if (rc) {
+		free_page((unsigned long)reipl_block_fcp);
+		return rc;
+	}
+	if (ipl_info.type == IPL_TYPE_FCP) {
+		memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
+	} else {
+		reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
+		reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
+		reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
+		reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
+		reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
+	}
+	reipl_capabilities |= IPL_TYPE_FCP;
+	return 0;
+}
+
+static int reipl_init(void)
+{
+	int rc;
+
+	reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
+	if (!reipl_kset)
+		return -ENOMEM;
+	rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
+	if (rc) {
+		kset_unregister(reipl_kset);
+		return rc;
+	}
+	rc = reipl_ccw_init();
+	if (rc)
+		return rc;
+	rc = reipl_fcp_init();
+	if (rc)
+		return rc;
+	rc = reipl_nss_init();
+	if (rc)
+		return rc;
+	rc = reipl_set_type(ipl_info.type);
+	if (rc)
+		return rc;
+	return 0;
+}
+
+static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
+					      reipl_run, reipl_init};
+
 /*
- * dump section
+ * dump shutdown action: Dump Linux on shutdown.
  */
 
 /* FCP dump device attributes */
@@ -656,12 +874,12 @@
 {
 	if (!(dump_capabilities & type))
 		return -EINVAL;
-	switch(type) {
+	switch (type) {
 	case DUMP_TYPE_CCW:
-		if (MACHINE_IS_VM)
-			dump_method = DUMP_METHOD_CCW_VM;
-		else if (diag308_set_works)
+		if (diag308_set_works)
 			dump_method = DUMP_METHOD_CCW_DIAG;
+		else if (MACHINE_IS_VM)
+			dump_method = DUMP_METHOD_CCW_VM;
 		else
 			dump_method = DUMP_METHOD_CCW_CIO;
 		break;
@@ -697,100 +915,11 @@
 }
 
 static struct kobj_attribute dump_type_attr =
-		__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
+	__ATTR(dump_type, 0644, dump_type_show, dump_type_store);
 
 static struct kset *dump_kset;
 
-/*
- * Shutdown actions section
- */
-
-static struct kset *shutdown_actions_kset;
-
-/* on panic */
-
-static ssize_t on_panic_show(struct kobject *kobj,
-			     struct kobj_attribute *attr, char *page)
-{
-	return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
-}
-
-static ssize_t on_panic_store(struct kobject *kobj,
-			      struct kobj_attribute *attr,
-			      const char *buf, size_t len)
-{
-	if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
-		on_panic_action = SHUTDOWN_REIPL;
-	else if (strncmp(buf, SHUTDOWN_DUMP_STR,
-			 strlen(SHUTDOWN_DUMP_STR)) == 0)
-		on_panic_action = SHUTDOWN_DUMP;
-	else if (strncmp(buf, SHUTDOWN_STOP_STR,
-			 strlen(SHUTDOWN_STOP_STR)) == 0)
-		on_panic_action = SHUTDOWN_STOP;
-	else
-		return -EINVAL;
-
-	return len;
-}
-
-static struct kobj_attribute on_panic_attr =
-		__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
-
-void do_reipl(void)
-{
-	struct ccw_dev_id devid;
-	static char buf[100];
-	char loadparm[LOADPARM_LEN + 1];
-
-	switch (reipl_method) {
-	case REIPL_METHOD_CCW_CIO:
-		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
-		if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno)
-			diag308(DIAG308_IPL, NULL);
-		devid.ssid  = 0;
-		reipl_ccw_dev(&devid);
-		break;
-	case REIPL_METHOD_CCW_VM:
-		reipl_get_ascii_loadparm(loadparm);
-		if (strlen(loadparm) == 0)
-			sprintf(buf, "IPL %X CLEAR",
-				reipl_block_ccw->ipl_info.ccw.devno);
-		else
-			sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
-				reipl_block_ccw->ipl_info.ccw.devno, loadparm);
-		__cpcmd(buf, NULL, 0, NULL);
-		break;
-	case REIPL_METHOD_CCW_DIAG:
-		diag308(DIAG308_SET, reipl_block_ccw);
-		diag308(DIAG308_IPL, NULL);
-		break;
-	case REIPL_METHOD_FCP_RW_DIAG:
-		diag308(DIAG308_SET, reipl_block_fcp);
-		diag308(DIAG308_IPL, NULL);
-		break;
-	case REIPL_METHOD_FCP_RO_DIAG:
-		diag308(DIAG308_IPL, NULL);
-		break;
-	case REIPL_METHOD_FCP_RO_VM:
-		__cpcmd("IPL", NULL, 0, NULL);
-		break;
-	case REIPL_METHOD_NSS:
-		sprintf(buf, "IPL %s", reipl_nss_name);
-		__cpcmd(buf, NULL, 0, NULL);
-		break;
-	case REIPL_METHOD_DEFAULT:
-		if (MACHINE_IS_VM)
-			__cpcmd("IPL", NULL, 0, NULL);
-		diag308(DIAG308_IPL, NULL);
-		break;
-	case REIPL_METHOD_FCP_DUMP:
-	default:
-		break;
-	}
-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-}
-
-static void do_dump(void)
+static void dump_run(struct shutdown_trigger *trigger)
 {
 	struct ccw_dev_id devid;
 	static char buf[100];
@@ -824,179 +953,6 @@
 	printk(KERN_EMERG "Dump failed!\n");
 }
 
-/* init functions */
-
-static int __init ipl_register_fcp_files(void)
-{
-	int rc;
-
-	rc = sysfs_create_group(&ipl_kset->kobj,
-				&ipl_fcp_attr_group);
-	if (rc)
-		goto out;
-	rc = sysfs_create_bin_file(&ipl_kset->kobj,
-				   &ipl_parameter_attr);
-	if (rc)
-		goto out_ipl_parm;
-	rc = sysfs_create_bin_file(&ipl_kset->kobj,
-				   &ipl_scp_data_attr);
-	if (!rc)
-		goto out;
-
-	sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
-
-out_ipl_parm:
-	sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
-out:
-	return rc;
-}
-
-static int __init ipl_init(void)
-{
-	int rc;
-
-	ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
-	if (!ipl_kset)
-		return -ENOMEM;
-	switch (ipl_info.type) {
-	case IPL_TYPE_CCW:
-		rc = sysfs_create_group(&ipl_kset->kobj,
-					&ipl_ccw_attr_group);
-		break;
-	case IPL_TYPE_FCP:
-	case IPL_TYPE_FCP_DUMP:
-		rc = ipl_register_fcp_files();
-		break;
-	case IPL_TYPE_NSS:
-		rc = sysfs_create_group(&ipl_kset->kobj,
-					&ipl_nss_attr_group);
-		break;
-	default:
-		rc = sysfs_create_group(&ipl_kset->kobj,
-					&ipl_unknown_attr_group);
-		break;
-	}
-	if (rc)
-		kset_unregister(ipl_kset);
-	return rc;
-}
-
-static void __init reipl_probe(void)
-{
-	void *buffer;
-
-	buffer = (void *) get_zeroed_page(GFP_KERNEL);
-	if (!buffer)
-		return;
-	if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
-		diag308_set_works = 1;
-	free_page((unsigned long)buffer);
-}
-
-static int __init reipl_nss_init(void)
-{
-	int rc;
-
-	if (!MACHINE_IS_VM)
-		return 0;
-	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
-	if (rc)
-		return rc;
-	strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
-	reipl_capabilities |= IPL_TYPE_NSS;
-	return 0;
-}
-
-static int __init reipl_ccw_init(void)
-{
-	int rc;
-
-	reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
-	if (!reipl_block_ccw)
-		return -ENOMEM;
-	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
-	if (rc) {
-		free_page((unsigned long)reipl_block_ccw);
-		return rc;
-	}
-	reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
-	reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
-	reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
-	reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
-	/* check if read scp info worked and set loadparm */
-	if (sclp_ipl_info.is_valid)
-		memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
-		       &sclp_ipl_info.loadparm, LOADPARM_LEN);
-	else
-		/* read scp info failed: set empty loadparm (EBCDIC blanks) */
-		memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
-		       LOADPARM_LEN);
-	/* FIXME: check for diag308_set_works when enabling diag ccw reipl */
-	if (!MACHINE_IS_VM)
-		sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
-	if (ipl_info.type == IPL_TYPE_CCW)
-		reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
-	reipl_capabilities |= IPL_TYPE_CCW;
-	return 0;
-}
-
-static int __init reipl_fcp_init(void)
-{
-	int rc;
-
-	if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP))
-		return 0;
-	if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP))
-		make_attrs_ro(reipl_fcp_attrs);
-
-	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
-	if (!reipl_block_fcp)
-		return -ENOMEM;
-	rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
-	if (rc) {
-		free_page((unsigned long)reipl_block_fcp);
-		return rc;
-	}
-	if (ipl_info.type == IPL_TYPE_FCP) {
-		memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
-	} else {
-		reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
-		reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
-		reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
-		reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
-		reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
-	}
-	reipl_capabilities |= IPL_TYPE_FCP;
-	return 0;
-}
-
-static int __init reipl_init(void)
-{
-	int rc;
-
-	reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
-	if (!reipl_kset)
-		return -ENOMEM;
-	rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
-	if (rc) {
-		kset_unregister(reipl_kset);
-		return rc;
-	}
-	rc = reipl_ccw_init();
-	if (rc)
-		return rc;
-	rc = reipl_fcp_init();
-	if (rc)
-		return rc;
-	rc = reipl_nss_init();
-	if (rc)
-		return rc;
-	rc = reipl_set_type(ipl_info.type);
-	if (rc)
-		return rc;
-	return 0;
-}
-
 static int __init dump_ccw_init(void)
 {
 	int rc;
@@ -1042,31 +998,14 @@
 	return 0;
 }
 
-#define SHUTDOWN_ON_PANIC_PRIO 0
-
-static int shutdown_on_panic_notify(struct notifier_block *self,
-				    unsigned long event, void *data)
-{
-	if (on_panic_action == SHUTDOWN_DUMP)
-		do_dump();
-	else if (on_panic_action == SHUTDOWN_REIPL)
-		do_reipl();
-	return NOTIFY_OK;
-}
-
-static struct notifier_block shutdown_on_panic_nb = {
-	.notifier_call = shutdown_on_panic_notify,
-	.priority = SHUTDOWN_ON_PANIC_PRIO
-};
-
-static int __init dump_init(void)
+static int dump_init(void)
 {
 	int rc;
 
 	dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
 	if (!dump_kset)
 		return -ENOMEM;
-	rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr);
+	rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
 	if (rc) {
 		kset_unregister(dump_kset);
 		return rc;
@@ -1081,47 +1020,381 @@
 	return 0;
 }
 
-static int __init shutdown_actions_init(void)
-{
-	int rc;
+static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
+					     dump_run, dump_init};
 
+/*
+ * vmcmd shutdown action: Trigger vm command on shutdown.
+ */
+
+static char vmcmd_on_reboot[128];
+static char vmcmd_on_panic[128];
+static char vmcmd_on_halt[128];
+static char vmcmd_on_poff[128];
+
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
+
+static struct attribute *vmcmd_attrs[] = {
+	&sys_vmcmd_on_reboot_attr.attr,
+	&sys_vmcmd_on_panic_attr.attr,
+	&sys_vmcmd_on_halt_attr.attr,
+	&sys_vmcmd_on_poff_attr.attr,
+	NULL,
+};
+
+static struct attribute_group vmcmd_attr_group = {
+	.attrs = vmcmd_attrs,
+};
+
+static struct kset *vmcmd_kset;
+
+static void vmcmd_run(struct shutdown_trigger *trigger)
+{
+	char *cmd, *next_cmd;
+
+	if (strcmp(trigger->name, ON_REIPL_STR) == 0)
+		cmd = vmcmd_on_reboot;
+	else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+		cmd = vmcmd_on_panic;
+	else if (strcmp(trigger->name, ON_HALT_STR) == 0)
+		cmd = vmcmd_on_halt;
+	else if (strcmp(trigger->name, ON_POFF_STR) == 0)
+		cmd = vmcmd_on_poff;
+	else
+		return;
+
+	if (strlen(cmd) == 0)
+		return;
+	do {
+		next_cmd = strchr(cmd, '\n');
+		if (next_cmd) {
+			next_cmd[0] = 0;
+			next_cmd += 1;
+		}
+		__cpcmd(cmd, NULL, 0, NULL);
+		cmd = next_cmd;
+	} while (cmd != NULL);
+}
+
+static int vmcmd_init(void)
+{
+	if (!MACHINE_IS_VM)
+		return -ENOTSUPP;
+	vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
+	if (!vmcmd_kset)
+		return -ENOMEM;
+	return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
+}
+
+static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
+					      vmcmd_run, vmcmd_init};
+
+/*
+ * stop shutdown action: Stop Linux on shutdown.
+ */
+
+static void stop_run(struct shutdown_trigger *trigger)
+{
+	if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+		disabled_wait((unsigned long) __builtin_return_address(0));
+	else {
+		signal_processor(smp_processor_id(), sigp_stop);
+		for (;;);
+	}
+}
+
+static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
+					     stop_run, NULL};
+
+/* action list */
+
+static struct shutdown_action *shutdown_actions_list[] = {
+	&ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
+#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
+
+/*
+ * Trigger section
+ */
+
+static struct kset *shutdown_actions_kset;
+
+static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
+		       size_t len)
+{
+	int i;
+	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+		if (!shutdown_actions_list[i])
+			continue;
+		if (strncmp(buf, shutdown_actions_list[i]->name,
+			    strlen(shutdown_actions_list[i]->name)) == 0) {
+			trigger->action = shutdown_actions_list[i];
+			return len;
+		}
+	}
+	return -EINVAL;
+}
+
+/* on reipl */
+
+static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
+						    &reipl_action};
+
+static ssize_t on_reboot_show(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *page)
+{
+	return sprintf(page, "%s\n", on_reboot_trigger.action->name);
+}
+
+static ssize_t on_reboot_store(struct kobject *kobj,
+			       struct kobj_attribute *attr,
+			       const char *buf, size_t len)
+{
+	return set_trigger(buf, &on_reboot_trigger, len);
+}
+
+static struct kobj_attribute on_reboot_attr =
+	__ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
+
+static void do_machine_restart(char *__unused)
+{
+	smp_send_stop();
+	on_reboot_trigger.action->fn(&on_reboot_trigger);
+	reipl_run(NULL);
+}
+void (*_machine_restart)(char *command) = do_machine_restart;
+
+/* on panic */
+
+static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
+
+static ssize_t on_panic_show(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *page)
+{
+	return sprintf(page, "%s\n", on_panic_trigger.action->name);
+}
+
+static ssize_t on_panic_store(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      const char *buf, size_t len)
+{
+	return set_trigger(buf, &on_panic_trigger, len);
+}
+
+static struct kobj_attribute on_panic_attr =
+	__ATTR(on_panic, 0644, on_panic_show, on_panic_store);
+
+static void do_panic(void)
+{
+	on_panic_trigger.action->fn(&on_panic_trigger);
+	stop_run(&on_panic_trigger);
+}
+
+/* on halt */
+
+static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
+
+static ssize_t on_halt_show(struct kobject *kobj,
+			    struct kobj_attribute *attr, char *page)
+{
+	return sprintf(page, "%s\n", on_halt_trigger.action->name);
+}
+
+static ssize_t on_halt_store(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     const char *buf, size_t len)
+{
+	return set_trigger(buf, &on_halt_trigger, len);
+}
+
+static struct kobj_attribute on_halt_attr =
+	__ATTR(on_halt, 0644, on_halt_show, on_halt_store);
+
+
+static void do_machine_halt(void)
+{
+	smp_send_stop();
+	on_halt_trigger.action->fn(&on_halt_trigger);
+	stop_run(&on_halt_trigger);
+}
+void (*_machine_halt)(void) = do_machine_halt;
+
+/* on power off */
+
+static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
+
+static ssize_t on_poff_show(struct kobject *kobj,
+			    struct kobj_attribute *attr, char *page)
+{
+	return sprintf(page, "%s\n", on_poff_trigger.action->name);
+}
+
+static ssize_t on_poff_store(struct kobject *kobj,
+			     struct kobj_attribute *attr,
+			     const char *buf, size_t len)
+{
+	return set_trigger(buf, &on_poff_trigger, len);
+}
+
+static struct kobj_attribute on_poff_attr =
+	__ATTR(on_poff, 0644, on_poff_show, on_poff_store);
+
+
+static void do_machine_power_off(void)
+{
+	smp_send_stop();
+	on_poff_trigger.action->fn(&on_poff_trigger);
+	stop_run(&on_poff_trigger);
+}
+void (*_machine_power_off)(void) = do_machine_power_off;
+
+static void __init shutdown_triggers_init(void)
+{
 	shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
 						    firmware_kobj);
 	if (!shutdown_actions_kset)
-		return -ENOMEM;
-	rc = sysfs_create_file(&shutdown_actions_kset->kobj, &on_panic_attr);
-	if (rc) {
-		kset_unregister(shutdown_actions_kset);
-		return rc;
+		goto fail;
+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
+			      &on_reboot_attr.attr))
+		goto fail;
+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
+			      &on_panic_attr.attr))
+		goto fail;
+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
+			      &on_halt_attr.attr))
+		goto fail;
+	if (sysfs_create_file(&shutdown_actions_kset->kobj,
+			      &on_poff_attr.attr))
+		goto fail;
+
+	return;
+fail:
+	panic("shutdown_triggers_init failed\n");
+}
+
+static void __init shutdown_actions_init(void)
+{
+	int i;
+
+	for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+		if (!shutdown_actions_list[i]->init)
+			continue;
+		if (shutdown_actions_list[i]->init())
+			shutdown_actions_list[i] = NULL;
 	}
-	atomic_notifier_chain_register(&panic_notifier_list,
-				       &shutdown_on_panic_nb);
-	return 0;
 }
 
 static int __init s390_ipl_init(void)
 {
-	int rc;
-
-	sclp_get_ipl_info(&sclp_ipl_info);
 	reipl_probe();
-	rc = ipl_init();
-	if (rc)
-		return rc;
-	rc = reipl_init();
-	if (rc)
-		return rc;
-	rc = dump_init();
-	if (rc)
-		return rc;
-	rc = shutdown_actions_init();
-	if (rc)
-		return rc;
+	sclp_get_ipl_info(&sclp_ipl_info);
+	shutdown_actions_init();
+	shutdown_triggers_init();
 	return 0;
 }
 
 __initcall(s390_ipl_init);
 
+static void __init strncpy_skip_quote(char *dst, char *src, int n)
+{
+	int sx, dx;
+
+	dx = 0;
+	for (sx = 0; src[sx] != 0; sx++) {
+		if (src[sx] == '"')
+			continue;
+		dst[dx++] = src[sx];
+		if (dx >= n)
+			break;
+	}
+}
+
+static int __init vmcmd_on_reboot_setup(char *str)
+{
+	if (!MACHINE_IS_VM)
+		return 1;
+	strncpy_skip_quote(vmcmd_on_reboot, str, 127);
+	vmcmd_on_reboot[127] = 0;
+	on_reboot_trigger.action = &vmcmd_action;
+	return 1;
+}
+__setup("vmreboot=", vmcmd_on_reboot_setup);
+
+static int __init vmcmd_on_panic_setup(char *str)
+{
+	if (!MACHINE_IS_VM)
+		return 1;
+	strncpy_skip_quote(vmcmd_on_panic, str, 127);
+	vmcmd_on_panic[127] = 0;
+	on_panic_trigger.action = &vmcmd_action;
+	return 1;
+}
+__setup("vmpanic=", vmcmd_on_panic_setup);
+
+static int __init vmcmd_on_halt_setup(char *str)
+{
+	if (!MACHINE_IS_VM)
+		return 1;
+	strncpy_skip_quote(vmcmd_on_halt, str, 127);
+	vmcmd_on_halt[127] = 0;
+	on_halt_trigger.action = &vmcmd_action;
+	return 1;
+}
+__setup("vmhalt=", vmcmd_on_halt_setup);
+
+static int __init vmcmd_on_poff_setup(char *str)
+{
+	if (!MACHINE_IS_VM)
+		return 1;
+	strncpy_skip_quote(vmcmd_on_poff, str, 127);
+	vmcmd_on_poff[127] = 0;
+	on_poff_trigger.action = &vmcmd_action;
+	return 1;
+}
+__setup("vmpoff=", vmcmd_on_poff_setup);
+
+static int on_panic_notify(struct notifier_block *self,
+			   unsigned long event, void *data)
+{
+	do_panic();
+	return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+	.notifier_call = on_panic_notify,
+	.priority = 0,
+};
+
+void __init setup_ipl(void)
+{
+	ipl_info.type = get_ipl_type();
+	switch (ipl_info.type) {
+	case IPL_TYPE_CCW:
+		ipl_info.data.ccw.dev_id.devno = ipl_devno;
+		ipl_info.data.ccw.dev_id.ssid = 0;
+		break;
+	case IPL_TYPE_FCP:
+	case IPL_TYPE_FCP_DUMP:
+		ipl_info.data.fcp.dev_id.devno =
+			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
+		ipl_info.data.fcp.dev_id.ssid = 0;
+		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
+		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
+		break;
+	case IPL_TYPE_NSS:
+		strncpy(ipl_info.data.nss.name, kernel_nss_name,
+			sizeof(ipl_info.data.nss.name));
+		break;
+	case IPL_TYPE_UNKNOWN:
+	default:
+		/* We have no info to copy */
+		break;
+	}
+	atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+}
+
 void __init ipl_save_parameters(void)
 {
 	struct cio_iplinfo iplinfo;
@@ -1202,3 +1475,4 @@
 
 	do_reset_calls();
 }
+
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 29f7884..0e7aca0 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -36,7 +36,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
-
+#include <linux/utsname.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -182,13 +182,15 @@
 
 void show_regs(struct pt_regs *regs)
 {
-	struct task_struct *tsk = current;
-
-        printk("CPU:    %d    %s\n", task_thread_info(tsk)->cpu, print_tainted());
-        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
-	       current->comm, task_pid_nr(current), (void *) tsk,
-	       (void *) tsk->thread.ksp);
-
+	print_modules();
+	printk("CPU: %d %s %s %.*s\n",
+	       task_thread_info(current)->cpu, print_tainted(),
+	       init_utsname()->release,
+	       (int)strcspn(init_utsname()->version, " "),
+	       init_utsname()->version);
+	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+	       current->comm, current->pid, current,
+	       (void *) current->thread.ksp);
 	show_registers(regs);
 	/* Show stack backtrace if pt_regs is from kernel mode */
 	if (!(regs->psw.mask & PSW_MASK_PSTATE))
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 1d81bf9..6e036ba 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -86,13 +86,13 @@
 		per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }
 
-static void set_single_step(struct task_struct *task)
+void user_enable_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 1;
 	FixPerRegisters(task);
 }
 
-static void clear_single_step(struct task_struct *task)
+void user_disable_single_step(struct task_struct *task)
 {
 	task->thread.per_info.single_step = 0;
 	FixPerRegisters(task);
@@ -107,7 +107,7 @@
 ptrace_disable(struct task_struct *child)
 {
 	/* make sure the single step bit is not set. */
-	clear_single_step(child);
+	user_disable_single_step(child);
 }
 
 #ifndef CONFIG_64BIT
@@ -651,7 +651,7 @@
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		/* make sure the single step bit is not set. */
-		clear_single_step(child);
+		user_disable_single_step(child);
 		wake_up_process(child);
 		return 0;
 
@@ -665,7 +665,7 @@
 			return 0;
 		child->exit_code = SIGKILL;
 		/* make sure the single step bit is not set. */
-		clear_single_step(child);
+		user_disable_single_step(child);
 		wake_up_process(child);
 		return 0;
 
@@ -675,10 +675,7 @@
 			return -EIO;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
-		if (data)
-			set_tsk_thread_flag(child, TIF_SINGLE_STEP);
-		else
-			set_single_step(child);
+		user_enable_single_step(child);
 		/* give it a chance to run. */
 		wake_up_process(child);
 		return 0;
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 577aa7d..766c783 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -126,75 +126,6 @@
 }
 
 /*
- * VM halt and poweroff setup routines
- */
-char vmhalt_cmd[128] = "";
-char vmpoff_cmd[128] = "";
-static char vmpanic_cmd[128] = "";
-
-static void strncpy_skip_quote(char *dst, char *src, int n)
-{
-        int sx, dx;
-
-        dx = 0;
-        for (sx = 0; src[sx] != 0; sx++) {
-                if (src[sx] == '"') continue;
-                dst[dx++] = src[sx];
-                if (dx >= n) break;
-        }
-}
-
-static int __init vmhalt_setup(char *str)
-{
-        strncpy_skip_quote(vmhalt_cmd, str, 127);
-        vmhalt_cmd[127] = 0;
-        return 1;
-}
-
-__setup("vmhalt=", vmhalt_setup);
-
-static int __init vmpoff_setup(char *str)
-{
-        strncpy_skip_quote(vmpoff_cmd, str, 127);
-        vmpoff_cmd[127] = 0;
-        return 1;
-}
-
-__setup("vmpoff=", vmpoff_setup);
-
-static int vmpanic_notify(struct notifier_block *self, unsigned long event,
-			  void *data)
-{
-	if (MACHINE_IS_VM && strlen(vmpanic_cmd) > 0)
-		cpcmd(vmpanic_cmd, NULL, 0, NULL);
-
-	return NOTIFY_OK;
-}
-
-#define PANIC_PRI_VMPANIC	0
-
-static struct notifier_block vmpanic_nb = {
-	.notifier_call = vmpanic_notify,
-	.priority = PANIC_PRI_VMPANIC
-};
-
-static int __init vmpanic_setup(char *str)
-{
-	static int register_done __initdata = 0;
-
-	strncpy_skip_quote(vmpanic_cmd, str, 127);
-	vmpanic_cmd[127] = 0;
-	if (!register_done) {
-		register_done = 1;
-		atomic_notifier_chain_register(&panic_notifier_list,
-					       &vmpanic_nb);
-	}
-	return 1;
-}
-
-__setup("vmpanic=", vmpanic_setup);
-
-/*
  * condev= and conmode= setup parameter.
  */
 
@@ -308,38 +239,6 @@
 static inline void setup_zfcpdump(unsigned int console_devno) {}
 #endif /* CONFIG_ZFCPDUMP */
 
-#ifdef CONFIG_SMP
-void (*_machine_restart)(char *command) = machine_restart_smp;
-void (*_machine_halt)(void) = machine_halt_smp;
-void (*_machine_power_off)(void) = machine_power_off_smp;
-#else
-/*
- * Reboot, halt and power_off routines for non SMP.
- */
-static void do_machine_restart_nonsmp(char * __unused)
-{
-	do_reipl();
-}
-
-static void do_machine_halt_nonsmp(void)
-{
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-}
-
-static void do_machine_power_off_nonsmp(void)
-{
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-}
-
-void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
-void (*_machine_halt)(void) = do_machine_halt_nonsmp;
-void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
-#endif
-
  /*
  * Reboot, halt and power_off stubs. They just call _machine_restart,
  * _machine_halt or _machine_power_off. 
@@ -559,7 +458,9 @@
 	data_resource.start = (unsigned long) &_etext;
 	data_resource.end = (unsigned long) &_edata - 1;
 
-	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+	for (i = 0; i < MEMORY_CHUNKS; i++) {
+		if (!memory_chunk[i].size)
+			continue;
 		res = alloc_bootmem_low(sizeof(struct resource));
 		res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
 		switch (memory_chunk[i].type) {
@@ -617,7 +518,7 @@
 static void __init setup_memory_end(void)
 {
 	unsigned long memory_size;
-	unsigned long max_mem, max_phys;
+	unsigned long max_mem;
 	int i;
 
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
@@ -625,10 +526,31 @@
 		memory_end = ZFCPDUMP_HSA_SIZE;
 #endif
 	memory_size = 0;
-	max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
 	memory_end &= PAGE_MASK;
 
-	max_mem = memory_end ? min(max_phys, memory_end) : max_phys;
+	max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
+	memory_end = min(max_mem, memory_end);
+
+	/*
+	 * Make sure all chunks are MAX_ORDER aligned so we don't need the
+	 * extra checks that HOLES_IN_ZONE would require.
+	 */
+	for (i = 0; i < MEMORY_CHUNKS; i++) {
+		unsigned long start, end;
+		struct mem_chunk *chunk;
+		unsigned long align;
+
+		chunk = &memory_chunk[i];
+		align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
+		start = (chunk->addr + align - 1) & ~(align - 1);
+		end = (chunk->addr + chunk->size) & ~(align - 1);
+		if (start >= end)
+			memset(chunk, 0, sizeof(*chunk));
+		else {
+			chunk->addr = start;
+			chunk->size = end - start;
+		}
+	}
 
 	for (i = 0; i < MEMORY_CHUNKS; i++) {
 		struct mem_chunk *chunk = &memory_chunk[i];
@@ -890,7 +812,7 @@
 
 	parse_early_param();
 
-	setup_ipl_info();
+	setup_ipl();
 	setup_memory_end();
 	setup_addressing_mode();
 	setup_memory();
@@ -899,7 +821,6 @@
 
         cpu_init();
         __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
-	smp_setup_cpu_possible_map();
 
 	/*
 	 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
@@ -920,7 +841,7 @@
 
 void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
 {
-   printk("cpu %d "
+   printk(KERN_INFO "cpu %d "
 #ifdef CONFIG_SMP
            "phys_idx=%d "
 #endif
@@ -996,7 +917,7 @@
 static void c_stop(struct seq_file *m, void *v)
 {
 }
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
 	.start	= c_start,
 	.next	= c_next,
 	.stop	= c_stop,
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index d264671..4449bf3 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -471,6 +471,7 @@
 
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
+		int ret;
 #ifdef CONFIG_COMPAT
 		if (test_thread_flag(TIF_31BIT)) {
 			extern int handle_signal32(unsigned long sig,
@@ -478,15 +479,12 @@
 						   siginfo_t *info,
 						   sigset_t *oldset,
 						   struct pt_regs *regs);
-			if (handle_signal32(
-				    signr, &ka, &info, oldset, regs) == 0) {
-				if (test_thread_flag(TIF_RESTORE_SIGMASK))
-					clear_thread_flag(TIF_RESTORE_SIGMASK);
-			}
-			return;
+			ret = handle_signal32(signr, &ka, &info, oldset, regs);
 	        }
+		else
 #endif
-		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+			ret = handle_signal(signr, &ka, &info, oldset, regs);
+		if (!ret) {
 			/*
 			 * A signal was successfully delivered; the saved
 			 * sigmask will have been stored in the signal frame,
@@ -495,6 +493,14 @@
 			 */
 			if (test_thread_flag(TIF_RESTORE_SIGMASK))
 				clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+			/*
+			 * If we would have taken a single-step trap
+			 * for a normal instruction, act like we took
+			 * one for the handler setup.
+			 */
+			if (current->thread.per_info.single_step)
+				set_thread_flag(TIF_SINGLE_STEP);
 		}
 		return;
 	}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 264ea90..aa37fa1 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -42,6 +42,7 @@
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
 #include <asm/lowcore.h>
+#include <asm/sclp.h>
 #include <asm/cpu.h>
 
 /*
@@ -53,11 +54,27 @@
 cpumask_t cpu_online_map = CPU_MASK_NONE;
 EXPORT_SYMBOL(cpu_online_map);
 
-cpumask_t cpu_possible_map = CPU_MASK_NONE;
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
 EXPORT_SYMBOL(cpu_possible_map);
 
 static struct task_struct *current_set[NR_CPUS];
 
+static u8 smp_cpu_type;
+static int smp_use_sigp_detection;
+
+enum s390_cpu_state {
+	CPU_STATE_STANDBY,
+	CPU_STATE_CONFIGURED,
+};
+
+#ifdef CONFIG_HOTPLUG_CPU
+static DEFINE_MUTEX(smp_cpu_state_mutex);
+#endif
+static int smp_cpu_state[NR_CPUS];
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+
 static void smp_ext_bitcall(int, ec_bit_sig);
 
 /*
@@ -193,6 +210,33 @@
 }
 EXPORT_SYMBOL(smp_call_function_single);
 
+/**
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
+ * @mask: The set of cpus to run on.  Must not include the current cpu.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int
+smp_call_function_mask(cpumask_t mask,
+			void (*func)(void *), void *info,
+			int wait)
+{
+	preempt_disable();
+	__smp_call_function_map(func, info, 0, wait, mask);
+	preempt_enable();
+	return 0;
+}
+EXPORT_SYMBOL(smp_call_function_mask);
+
 void smp_send_stop(void)
 {
 	int cpu, rc;
@@ -217,33 +261,6 @@
 }
 
 /*
- * Reboot, halt and power_off routines for SMP.
- */
-void machine_restart_smp(char *__unused)
-{
-	smp_send_stop();
-	do_reipl();
-}
-
-void machine_halt_smp(void)
-{
-	smp_send_stop();
-	if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-		__cpcmd(vmhalt_cmd, NULL, 0, NULL);
-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-	for (;;);
-}
-
-void machine_power_off_smp(void)
-{
-	smp_send_stop();
-	if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-		__cpcmd(vmpoff_cmd, NULL, 0, NULL);
-	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-	for (;;);
-}
-
-/*
  * This is the main routine where commands issued by other
  * cpus are handled.
  */
@@ -355,6 +372,13 @@
 }
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 
+/*
+ * In early ipl state a temp. logically cpu number is needed, so the sigp
+ * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on
+ * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1.
+ */
+#define CPU_INIT_NO	1
+
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
 
 /*
@@ -375,9 +399,10 @@
 		       "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
 		return;
 	}
-	zfcpdump_save_areas[cpu] = alloc_bootmem(sizeof(union save_area));
-	__cpu_logical_map[1] = (__u16) phy_cpu;
-	while (signal_processor(1, sigp_stop_and_store_status) == sigp_busy)
+	zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
+	__cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu;
+	while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) ==
+	       sigp_busy)
 		cpu_relax();
 	memcpy(zfcpdump_save_areas[cpu],
 	       (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
@@ -397,32 +422,155 @@
 
 #endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
 
-/*
- * Lets check how many CPUs we have.
- */
-static unsigned int __init smp_count_cpus(void)
+static int cpu_stopped(int cpu)
 {
-	unsigned int cpu, num_cpus;
-	__u16 boot_cpu_addr;
+	__u32 status;
 
-	/*
-	 * cpu 0 is the boot cpu. See smp_prepare_boot_cpu.
-	 */
-	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
-	current_thread_info()->cpu = 0;
-	num_cpus = 1;
-	for (cpu = 0; cpu <= 65535; cpu++) {
-		if ((__u16) cpu == boot_cpu_addr)
-			continue;
-		__cpu_logical_map[1] = (__u16) cpu;
-		if (signal_processor(1, sigp_sense) == sigp_not_operational)
-			continue;
-		smp_get_save_area(num_cpus, cpu);
-		num_cpus++;
+	/* Check for stopped state */
+	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
+	    sigp_status_stored) {
+		if (status & 0x40)
+			return 1;
 	}
-	printk("Detected %d CPU's\n", (int) num_cpus);
-	printk("Boot cpu address %2X\n", boot_cpu_addr);
-	return num_cpus;
+	return 0;
+}
+
+static int cpu_known(int cpu_id)
+{
+	int cpu;
+
+	for_each_present_cpu(cpu) {
+		if (__cpu_logical_map[cpu] == cpu_id)
+			return 1;
+	}
+	return 0;
+}
+
+static int smp_rescan_cpus_sigp(cpumask_t avail)
+{
+	int cpu_id, logical_cpu;
+
+	logical_cpu = first_cpu(avail);
+	if (logical_cpu == NR_CPUS)
+		return 0;
+	for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
+		if (cpu_known(cpu_id))
+			continue;
+		__cpu_logical_map[logical_cpu] = cpu_id;
+		if (!cpu_stopped(logical_cpu))
+			continue;
+		cpu_set(logical_cpu, cpu_present_map);
+		smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+		logical_cpu = next_cpu(logical_cpu, avail);
+		if (logical_cpu == NR_CPUS)
+			break;
+	}
+	return 0;
+}
+
+static int smp_rescan_cpus_sclp(cpumask_t avail)
+{
+	struct sclp_cpu_info *info;
+	int cpu_id, logical_cpu, cpu;
+	int rc;
+
+	logical_cpu = first_cpu(avail);
+	if (logical_cpu == NR_CPUS)
+		return 0;
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	rc = sclp_get_cpu_info(info);
+	if (rc)
+		goto out;
+	for (cpu = 0; cpu < info->combined; cpu++) {
+		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+			continue;
+		cpu_id = info->cpu[cpu].address;
+		if (cpu_known(cpu_id))
+			continue;
+		__cpu_logical_map[logical_cpu] = cpu_id;
+		cpu_set(logical_cpu, cpu_present_map);
+		if (cpu >= info->configured)
+			smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
+		else
+			smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+		logical_cpu = next_cpu(logical_cpu, avail);
+		if (logical_cpu == NR_CPUS)
+			break;
+	}
+out:
+	kfree(info);
+	return rc;
+}
+
+static int smp_rescan_cpus(void)
+{
+	cpumask_t avail;
+
+	cpus_xor(avail, cpu_possible_map, cpu_present_map);
+	if (smp_use_sigp_detection)
+		return smp_rescan_cpus_sigp(avail);
+	else
+		return smp_rescan_cpus_sclp(avail);
+}
+
+static void __init smp_detect_cpus(void)
+{
+	unsigned int cpu, c_cpus, s_cpus;
+	struct sclp_cpu_info *info;
+	u16 boot_cpu_addr, cpu_addr;
+
+	c_cpus = 1;
+	s_cpus = 0;
+	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		panic("smp_detect_cpus failed to allocate memory\n");
+	/* Use sigp detection algorithm if sclp doesn't work. */
+	if (sclp_get_cpu_info(info)) {
+		smp_use_sigp_detection = 1;
+		for (cpu = 0; cpu <= 65535; cpu++) {
+			if (cpu == boot_cpu_addr)
+				continue;
+			__cpu_logical_map[CPU_INIT_NO] = cpu;
+			if (!cpu_stopped(CPU_INIT_NO))
+				continue;
+			smp_get_save_area(c_cpus, cpu);
+			c_cpus++;
+		}
+		goto out;
+	}
+
+	if (info->has_cpu_type) {
+		for (cpu = 0; cpu < info->combined; cpu++) {
+			if (info->cpu[cpu].address == boot_cpu_addr) {
+				smp_cpu_type = info->cpu[cpu].type;
+				break;
+			}
+		}
+	}
+
+	for (cpu = 0; cpu < info->combined; cpu++) {
+		if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+			continue;
+		cpu_addr = info->cpu[cpu].address;
+		if (cpu_addr == boot_cpu_addr)
+			continue;
+		__cpu_logical_map[CPU_INIT_NO] = cpu_addr;
+		if (!cpu_stopped(CPU_INIT_NO)) {
+			s_cpus++;
+			continue;
+		}
+		smp_get_save_area(c_cpus, cpu_addr);
+		c_cpus++;
+	}
+out:
+	kfree(info);
+	printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
+	get_online_cpus();
+	smp_rescan_cpus();
+	put_online_cpus();
 }
 
 /*
@@ -453,8 +601,6 @@
 	return 0;
 }
 
-DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
-
 static void __init smp_create_idle(unsigned int cpu)
 {
 	struct task_struct *p;
@@ -470,37 +616,82 @@
 	spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
 }
 
-static int cpu_stopped(int cpu)
+static int __cpuinit smp_alloc_lowcore(int cpu)
 {
-	__u32 status;
+	unsigned long async_stack, panic_stack;
+	struct _lowcore *lowcore;
+	int lc_order;
 
-	/* Check for stopped state */
-	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
-	    sigp_status_stored) {
-		if (status & 0x40)
-			return 1;
+	lc_order = sizeof(long) == 8 ? 1 : 0;
+	lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
+	if (!lowcore)
+		return -ENOMEM;
+	async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+	if (!async_stack)
+		goto out_async_stack;
+	panic_stack = __get_free_page(GFP_KERNEL);
+	if (!panic_stack)
+		goto out_panic_stack;
+
+	*lowcore = S390_lowcore;
+	lowcore->async_stack = async_stack + ASYNC_SIZE;
+	lowcore->panic_stack = panic_stack + PAGE_SIZE;
+
+#ifndef CONFIG_64BIT
+	if (MACHINE_HAS_IEEE) {
+		unsigned long save_area;
+
+		save_area = get_zeroed_page(GFP_KERNEL);
+		if (!save_area)
+			goto out_save_area;
+		lowcore->extended_save_area_addr = (u32) save_area;
 	}
+#endif
+	lowcore_ptr[cpu] = lowcore;
 	return 0;
+
+#ifndef CONFIG_64BIT
+out_save_area:
+	free_page(panic_stack);
+#endif
+out_panic_stack:
+	free_pages(async_stack, ASYNC_ORDER);
+out_async_stack:
+	free_pages((unsigned long) lowcore, lc_order);
+	return -ENOMEM;
 }
 
-/* Upping and downing of CPUs */
+#ifdef CONFIG_HOTPLUG_CPU
+static void smp_free_lowcore(int cpu)
+{
+	struct _lowcore *lowcore;
+	int lc_order;
 
-int __cpu_up(unsigned int cpu)
+	lc_order = sizeof(long) == 8 ? 1 : 0;
+	lowcore = lowcore_ptr[cpu];
+#ifndef CONFIG_64BIT
+	if (MACHINE_HAS_IEEE)
+		free_page((unsigned long) lowcore->extended_save_area_addr);
+#endif
+	free_page(lowcore->panic_stack - PAGE_SIZE);
+	free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
+	free_pages((unsigned long) lowcore, lc_order);
+	lowcore_ptr[cpu] = NULL;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/* Upping and downing of CPUs */
+int __cpuinit __cpu_up(unsigned int cpu)
 {
 	struct task_struct *idle;
 	struct _lowcore *cpu_lowcore;
 	struct stack_frame *sf;
 	sigp_ccode ccode;
-	int curr_cpu;
 
-	for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
-		__cpu_logical_map[cpu] = (__u16) curr_cpu;
-		if (cpu_stopped(cpu))
-			break;
-	}
-
-	if (!cpu_stopped(cpu))
-		return -ENODEV;
+	if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
+		return -EIO;
+	if (smp_alloc_lowcore(cpu))
+		return -ENOMEM;
 
 	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
 				   cpu, sigp_set_prefix);
@@ -515,6 +706,7 @@
 	cpu_lowcore = lowcore_ptr[cpu];
 	cpu_lowcore->kernel_stack = (unsigned long)
 		task_stack_page(idle) + THREAD_SIZE;
+	cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
 	sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
 				     - sizeof(struct pt_regs)
 				     - sizeof(struct stack_frame));
@@ -528,6 +720,8 @@
 	cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
 	cpu_lowcore->current_task = (unsigned long) idle;
 	cpu_lowcore->cpu_data.cpu_nr = cpu;
+	cpu_lowcore->softirq_pending = 0;
+	cpu_lowcore->ext_call_fast = 0;
 	eieio();
 
 	while (signal_processor(cpu, sigp_restart) == sigp_busy)
@@ -538,44 +732,20 @@
 	return 0;
 }
 
-static unsigned int __initdata additional_cpus;
-static unsigned int __initdata possible_cpus;
-
-void __init smp_setup_cpu_possible_map(void)
-{
-	unsigned int phy_cpus, pos_cpus, cpu;
-
-	phy_cpus = smp_count_cpus();
-	pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS);
-
-	if (possible_cpus)
-		pos_cpus = min(possible_cpus, (unsigned int) NR_CPUS);
-
-	for (cpu = 0; cpu < pos_cpus; cpu++)
-		cpu_set(cpu, cpu_possible_map);
-
-	phy_cpus = min(phy_cpus, pos_cpus);
-
-	for (cpu = 0; cpu < phy_cpus; cpu++)
-		cpu_set(cpu, cpu_present_map);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-static int __init setup_additional_cpus(char *s)
-{
-	additional_cpus = simple_strtoul(s, NULL, 0);
-	return 0;
-}
-early_param("additional_cpus", setup_additional_cpus);
-
 static int __init setup_possible_cpus(char *s)
 {
-	possible_cpus = simple_strtoul(s, NULL, 0);
+	int pcpus, cpu;
+
+	pcpus = simple_strtoul(s, NULL, 0);
+	cpu_possible_map = cpumask_of_cpu(0);
+	for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++)
+		cpu_set(cpu, cpu_possible_map);
 	return 0;
 }
 early_param("possible_cpus", setup_possible_cpus);
 
+#ifdef CONFIG_HOTPLUG_CPU
+
 int __cpu_disable(void)
 {
 	struct ec_creg_mask_parms cr_parms;
@@ -612,7 +782,8 @@
 	/* Wait until target cpu is down */
 	while (!smp_cpu_not_running(cpu))
 		cpu_relax();
-	printk("Processor %d spun down\n", cpu);
+	smp_free_lowcore(cpu);
+	printk(KERN_INFO "Processor %d spun down\n", cpu);
 }
 
 void cpu_die(void)
@@ -625,49 +796,19 @@
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
-/*
- *	Cycle through the processors and setup structures.
- */
-
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-	unsigned long stack;
 	unsigned int cpu;
-	int i;
+
+	smp_detect_cpus();
 
 	/* request the 0x1201 emergency signal external interrupt */
 	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
 		panic("Couldn't request external interrupt 0x1201");
 	memset(lowcore_ptr, 0, sizeof(lowcore_ptr));
-	/*
-	 *  Initialize prefix pages and stacks for all possible cpus
-	 */
 	print_cpu_info(&S390_lowcore.cpu_data);
+	smp_alloc_lowcore(smp_processor_id());
 
-	for_each_possible_cpu(i) {
-		lowcore_ptr[i] = (struct _lowcore *)
-			__get_free_pages(GFP_KERNEL | GFP_DMA,
-					 sizeof(void*) == 8 ? 1 : 0);
-		stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
-		if (!lowcore_ptr[i] || !stack)
-			panic("smp_boot_cpus failed to allocate memory\n");
-
-		*(lowcore_ptr[i]) = S390_lowcore;
-		lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE;
-		stack = __get_free_pages(GFP_KERNEL, 0);
-		if (!stack)
-			panic("smp_boot_cpus failed to allocate memory\n");
-		lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE;
-#ifndef CONFIG_64BIT
-		if (MACHINE_HAS_IEEE) {
-			lowcore_ptr[i]->extended_save_area_addr =
-				(__u32) __get_free_pages(GFP_KERNEL, 0);
-			if (!lowcore_ptr[i]->extended_save_area_addr)
-				panic("smp_boot_cpus failed to "
-				      "allocate memory\n");
-		}
-#endif
-	}
 #ifndef CONFIG_64BIT
 	if (MACHINE_HAS_IEEE)
 		ctl_set_bit(14, 29); /* enable extended save area */
@@ -683,15 +824,17 @@
 {
 	BUG_ON(smp_processor_id() != 0);
 
+	current_thread_info()->cpu = 0;
+	cpu_set(0, cpu_present_map);
 	cpu_set(0, cpu_online_map);
 	S390_lowcore.percpu_offset = __per_cpu_offset[0];
 	current_set[0] = current;
+	smp_cpu_state[0] = CPU_STATE_CONFIGURED;
 	spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
-	cpu_present_map = cpu_possible_map;
 }
 
 /*
@@ -705,7 +848,79 @@
 	return 0;
 }
 
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t cpu_configure_show(struct sys_device *dev, char *buf)
+{
+	ssize_t count;
+
+	mutex_lock(&smp_cpu_state_mutex);
+	count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
+	mutex_unlock(&smp_cpu_state_mutex);
+	return count;
+}
+
+static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf,
+				   size_t count)
+{
+	int cpu = dev->id;
+	int val, rc;
+	char delim;
+
+	if (sscanf(buf, "%d %c", &val, &delim) != 1)
+		return -EINVAL;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&smp_cpu_state_mutex);
+	get_online_cpus();
+	rc = -EBUSY;
+	if (cpu_online(cpu))
+		goto out;
+	rc = 0;
+	switch (val) {
+	case 0:
+		if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
+			rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
+			if (!rc)
+				smp_cpu_state[cpu] = CPU_STATE_STANDBY;
+		}
+		break;
+	case 1:
+		if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
+			rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
+			if (!rc)
+				smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
+		}
+		break;
+	default:
+		break;
+	}
+out:
+	put_online_cpus();
+	mutex_unlock(&smp_cpu_state_mutex);
+	return rc ? rc : count;
+}
+static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static ssize_t show_cpu_address(struct sys_device *dev, char *buf)
+{
+	return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
+}
+static SYSDEV_ATTR(address, 0444, show_cpu_address, NULL);
+
+
+static struct attribute *cpu_common_attrs[] = {
+#ifdef CONFIG_HOTPLUG_CPU
+	&attr_configure.attr,
+#endif
+	&attr_address.attr,
+	NULL,
+};
+
+static struct attribute_group cpu_common_attr_group = {
+	.attrs = cpu_common_attrs,
+};
 
 static ssize_t show_capability(struct sys_device *dev, char *buf)
 {
@@ -750,15 +965,15 @@
 }
 static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
 
-static struct attribute *cpu_attrs[] = {
+static struct attribute *cpu_online_attrs[] = {
 	&attr_capability.attr,
 	&attr_idle_count.attr,
 	&attr_idle_time_us.attr,
 	NULL,
 };
 
-static struct attribute_group cpu_attr_group = {
-	.attrs = cpu_attrs,
+static struct attribute_group cpu_online_attr_group = {
+	.attrs = cpu_online_attrs,
 };
 
 static int __cpuinit smp_cpu_notify(struct notifier_block *self,
@@ -778,12 +993,12 @@
 		idle->idle_time = 0;
 		idle->idle_count = 0;
 		spin_unlock_irq(&idle->lock);
-		if (sysfs_create_group(&s->kobj, &cpu_attr_group))
+		if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
 			return NOTIFY_BAD;
 		break;
 	case CPU_DEAD:
 	case CPU_DEAD_FROZEN:
-		sysfs_remove_group(&s->kobj, &cpu_attr_group);
+		sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
 		break;
 	}
 	return NOTIFY_OK;
@@ -793,6 +1008,62 @@
 	.notifier_call = smp_cpu_notify,
 };
 
+static int smp_add_present_cpu(int cpu)
+{
+	struct cpu *c = &per_cpu(cpu_devices, cpu);
+	struct sys_device *s = &c->sysdev;
+	int rc;
+
+	c->hotpluggable = 1;
+	rc = register_cpu(c, cpu);
+	if (rc)
+		goto out;
+	rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
+	if (rc)
+		goto out_cpu;
+	if (!cpu_online(cpu))
+		goto out;
+	rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
+	if (!rc)
+		return 0;
+	sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
+out_cpu:
+#ifdef CONFIG_HOTPLUG_CPU
+	unregister_cpu(c);
+#endif
+out:
+	return rc;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t rescan_store(struct sys_device *dev, const char *buf,
+			    size_t count)
+{
+	cpumask_t newcpus;
+	int cpu;
+	int rc;
+
+	mutex_lock(&smp_cpu_state_mutex);
+	get_online_cpus();
+	newcpus = cpu_present_map;
+	rc = smp_rescan_cpus();
+	if (rc)
+		goto out;
+	cpus_andnot(newcpus, cpu_present_map, newcpus);
+	for_each_cpu_mask(cpu, newcpus) {
+		rc = smp_add_present_cpu(cpu);
+		if (rc)
+			cpu_clear(cpu, cpu_present_map);
+	}
+	rc = 0;
+out:
+	put_online_cpus();
+	mutex_unlock(&smp_cpu_state_mutex);
+	return rc ? rc : count;
+}
+static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init topology_init(void)
 {
 	int cpu;
@@ -800,16 +1071,14 @@
 
 	register_cpu_notifier(&smp_cpu_nb);
 
-	for_each_possible_cpu(cpu) {
-		struct cpu *c = &per_cpu(cpu_devices, cpu);
-		struct sys_device *s = &c->sysdev;
-
-		c->hotpluggable = 1;
-		register_cpu(c, cpu);
-		if (!cpu_online(cpu))
-			continue;
-		s = &c->sysdev;
-		rc = sysfs_create_group(&s->kobj, &cpu_attr_group);
+#ifdef CONFIG_HOTPLUG_CPU
+	rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+			       &attr_rescan.attr);
+	if (rc)
+		return rc;
+#endif
+	for_each_present_cpu(cpu) {
+		rc = smp_add_present_cpu(cpu);
 		if (rc)
 			return rc;
 	}
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 8ed16a8..52b8342 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -31,6 +31,7 @@
 #include <linux/reboot.h>
 #include <linux/kprobes.h>
 #include <linux/bug.h>
+#include <linux/utsname.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -168,9 +169,16 @@
  */
 void dump_stack(void)
 {
+	printk("CPU: %d %s %s %.*s\n",
+	       task_thread_info(current)->cpu, print_tainted(),
+	       init_utsname()->release,
+	       (int)strcspn(init_utsname()->version, " "),
+	       init_utsname()->version);
+	printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+	       current->comm, current->pid, current,
+	       (void *) current->thread.ksp);
 	show_stack(NULL, NULL);
 }
-
 EXPORT_SYMBOL(dump_stack);
 
 static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
@@ -258,8 +266,14 @@
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
-	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-	print_modules();
+	printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP");
+#endif
+	printk("\n");
 	notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
 	show_regs(regs);
 	bust_spinlocks(0);
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 849120e..9361591 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -17,6 +17,12 @@
 jiffies = jiffies_64;
 #endif
 
+PHDRS {
+	text PT_LOAD FLAGS(5);	/* R_E */
+	data PT_LOAD FLAGS(7);	/* RWE */
+	note PT_NOTE FLAGS(0);	/* ___ */
+}
+
 SECTIONS
 {
 	. = 0x00000000;
@@ -33,6 +39,9 @@
 
 	_etext = .;		/* End of text section */
 
+	NOTES :text :note
+	BUG_TABLE :text
+
 	RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
@@ -49,9 +58,6 @@
 		__stop___ex_table = .;
 	}
 
-	NOTES
-	BUG_TABLE
-
 	.data : {		/* Data */
 		DATA_DATA
 		CONSTRUCTORS
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 8d76403..e41f400 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -39,7 +39,7 @@
 		_raw_yield();
 }
 
-void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+void _raw_spin_lock_wait(raw_spinlock_t *lp)
 {
 	int count = spin_retry;
 	unsigned int cpu = ~smp_processor_id();
@@ -53,15 +53,36 @@
 		}
 		if (__raw_spin_is_locked(lp))
 			continue;
-		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
-			lp->owner_pc = pc;
+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
 			return;
-		}
 	}
 }
 EXPORT_SYMBOL(_raw_spin_lock_wait);
 
-int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+void _raw_spin_lock_wait_flags(raw_spinlock_t *lp, unsigned long flags)
+{
+	int count = spin_retry;
+	unsigned int cpu = ~smp_processor_id();
+
+	local_irq_restore(flags);
+	while (1) {
+		if (count-- <= 0) {
+			unsigned int owner = lp->owner_cpu;
+			if (owner != 0)
+				_raw_yield_cpu(~owner);
+			count = spin_retry;
+		}
+		if (__raw_spin_is_locked(lp))
+			continue;
+		local_irq_disable();
+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+			return;
+		local_irq_restore(flags);
+	}
+}
+EXPORT_SYMBOL(_raw_spin_lock_wait_flags);
+
+int _raw_spin_trylock_retry(raw_spinlock_t *lp)
 {
 	unsigned int cpu = ~smp_processor_id();
 	int count;
@@ -69,10 +90,8 @@
 	for (count = spin_retry; count > 0; count--) {
 		if (__raw_spin_is_locked(lp))
 			continue;
-		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
-			lp->owner_pc = pc;
+		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
 			return 1;
-		}
 	}
 	return 0;
 }
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 394980b..880b0eb 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -83,7 +83,7 @@
 };
 
 static DEFINE_MUTEX(dcss_lock);
-static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
+static LIST_HEAD(dcss_list);
 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
 					"EW/EN-MIXED" };
 
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index fb9c5a8..79d13a1 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -15,10 +15,6 @@
 #include <asm/setup.h>
 #include <asm/tlbflush.h>
 
-unsigned long vmalloc_end;
-EXPORT_SYMBOL(vmalloc_end);
-
-static struct page *vmem_map;
 static DEFINE_MUTEX(vmem_mutex);
 
 struct memory_segment {
@@ -188,8 +184,8 @@
 	pte_t  pte;
 	int ret = -ENOMEM;
 
-	map_start = vmem_map + PFN_DOWN(start);
-	map_end	= vmem_map + PFN_DOWN(start + size);
+	map_start = VMEM_MAP + PFN_DOWN(start);
+	map_end	= VMEM_MAP + PFN_DOWN(start + size);
 
 	start_addr = (unsigned long) map_start & PAGE_MASK;
 	end_addr = PFN_ALIGN((unsigned long) map_end);
@@ -240,10 +236,10 @@
 {
 	int ret;
 
-	ret = vmem_add_range(start, size);
+	ret = vmem_add_mem_map(start, size);
 	if (ret)
 		return ret;
-	return vmem_add_mem_map(start, size);
+	return vmem_add_range(start, size);
 }
 
 /*
@@ -254,7 +250,7 @@
 {
 	struct memory_segment *tmp;
 
-	if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
+	if (seg->start + seg->size >= VMALLOC_START ||
 	    seg->start + seg->size < seg->start)
 		return -ERANGE;
 
@@ -357,17 +353,15 @@
 
 /*
  * map whole physical memory to virtual memory (identity mapping)
+ * we reserve enough space in the vmalloc area for vmemmap to hotplug
+ * additional memory segments.
  */
 void __init vmem_map_init(void)
 {
-	unsigned long map_size;
 	int i;
 
-	map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
-	vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
-	vmem_map = (struct page *) vmalloc_end;
-	NODE_DATA(0)->node_mem_map = vmem_map;
-
+	BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
+	NODE_DATA(0)->node_mem_map = VMEM_MAP;
 	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
 		vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
 }
@@ -382,7 +376,7 @@
 	int i;
 
 	mutex_lock(&vmem_mutex);
-	for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+	for (i = 0; i < MEMORY_CHUNKS; i++) {
 		if (!memory_chunk[i].size)
 			continue;
 		seg = kzalloc(sizeof(*seg), GFP_KERNEL);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 8a70a9e..6b658d8 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -48,8 +48,6 @@
 	  If unsure say M. The compiled module will be
 	  called padlock-sha.ko
 
-source "arch/s390/crypto/Kconfig"
-
 config CRYPTO_DEV_GEODE
 	tristate "Support for the Geode LX AES engine"
 	depends on X86_32 && PCI
@@ -83,6 +81,67 @@
 	  that contains all parts of the crypto device driver (ap bus,
 	  request router and all the card drivers).
 
+config CRYPTO_SHA1_S390
+	tristate "SHA1 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+	tristate "SHA256 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA256 secure hash standard (DFIPS 180-2).
+
+	  This version of SHA implements a 256 bit hash with 128 bits of
+	  security against collision attacks.
+
+config CRYPTO_DES_S390
+	tristate "DES and Triple DES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This us the s390 hardware accelerated implementation of the
+	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+	tristate "AES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+	  algorithm.
+
+	  Rijndael appears to be consistently a very good performer in
+	  both hardware and software across a wide range of computing
+	  environments regardless of its use in feedback or non-feedback
+	  modes. Its key setup time is excellent, and its key agility is
+	  good. Rijndael's very low memory requirements make it very well
+	  suited for restricted-space environments, in which it also
+	  demonstrates excellent performance. Rijndael's operations are
+	  among the easiest to defend against power and timing attacks.
+
+	  On s390 the System z9-109 currently only supports the key size
+	  of 128 bit.
+
+config S390_PRNG
+	tristate "Pseudo random number generator device driver"
+	depends on S390
+	default "m"
+	help
+	  Select this option if you want to use the s390 pseudo random number
+	  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.
+
 config CRYPTO_DEV_HIFN_795X
 	tristate "Driver HIFN 795x crypto accelerator chips"
 	select CRYPTO_DES
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index a37cb6b..3581282 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -1,7 +1,7 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters		     */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-2000 Simon G. Vogl
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ *   Copyright (C) 1995-2000 Simon G. Vogl
 
     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
@@ -15,8 +15,8 @@
 
     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.		     */
-/* ------------------------------------------------------------------------- */
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------- */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
    <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
@@ -60,26 +60,26 @@
 
 /* --- setting states on the bus with the right timing: ---------------	*/
 
-#define setsda(adap,val) adap->setsda(adap->data, val)
-#define setscl(adap,val) adap->setscl(adap->data, val)
-#define getsda(adap) adap->getsda(adap->data)
-#define getscl(adap) adap->getscl(adap->data)
+#define setsda(adap, val)	adap->setsda(adap->data, val)
+#define setscl(adap, val)	adap->setscl(adap->data, val)
+#define getsda(adap)		adap->getsda(adap->data)
+#define getscl(adap)		adap->getscl(adap->data)
 
 static inline void sdalo(struct i2c_algo_bit_data *adap)
 {
-	setsda(adap,0);
+	setsda(adap, 0);
 	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void sdahi(struct i2c_algo_bit_data *adap)
 {
-	setsda(adap,1);
+	setsda(adap, 1);
 	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void scllo(struct i2c_algo_bit_data *adap)
 {
-	setscl(adap,0);
+	setscl(adap, 0);
 	udelay(adap->udelay / 2);
 }
 
@@ -91,22 +91,21 @@
 {
 	unsigned long start;
 
-	setscl(adap,1);
+	setscl(adap, 1);
 
 	/* Not all adapters have scl sense line... */
 	if (!adap->getscl)
 		goto done;
 
-	start=jiffies;
-	while (! getscl(adap) ) {	
- 		/* the hw knows how to read the clock line,
- 		 * so we wait until it actually gets high.
- 		 * This is safer as some chips may hold it low
- 		 * while they are processing data internally. 
- 		 */
-		if (time_after_eq(jiffies, start+adap->timeout)) {
+	start = jiffies;
+	while (!getscl(adap)) {
+		/* This hw knows how to read the clock line, so we wait
+		 * until it actually gets high.  This is safer as some
+		 * chips may hold it low ("clock stretching") while they
+		 * are processing data internally.
+		 */
+		if (time_after_eq(jiffies, start + adap->timeout))
 			return -ETIMEDOUT;
-		}
 		cond_resched();
 	}
 #ifdef DEBUG
@@ -118,11 +117,11 @@
 done:
 	udelay(adap->udelay);
 	return 0;
-} 
+}
 
 
 /* --- other auxiliary functions --------------------------------------	*/
-static void i2c_start(struct i2c_algo_bit_data *adap) 
+static void i2c_start(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl, sda are high */
 	setsda(adap, 0);
@@ -130,7 +129,7 @@
 	scllo(adap);
 }
 
-static void i2c_repstart(struct i2c_algo_bit_data *adap) 
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl is low */
 	sdahi(adap);
@@ -141,18 +140,18 @@
 }
 
 
-static void i2c_stop(struct i2c_algo_bit_data *adap) 
+static void i2c_stop(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl is low */
 	sdalo(adap);
-	sclhi(adap); 
+	sclhi(adap);
 	setsda(adap, 1);
 	udelay(adap->udelay);
 }
 
 
 
-/* send a byte without start cond., look for arbitration, 
+/* send a byte without start cond., look for arbitration,
    check ackn. from slave */
 /* returns:
  * 1 if the device acknowledged
@@ -167,27 +166,33 @@
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
-	for ( i=7 ; i>=0 ; i-- ) {
+	for (i = 7; i >= 0; i--) {
 		sb = (c >> i) & 1;
-		setsda(adap,sb);
+		setsda(adap, sb);
 		udelay((adap->udelay + 1) / 2);
-		if (sclhi(adap)<0) { /* timed out */
+		if (sclhi(adap) < 0) { /* timed out */
 			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
 				"timeout at bit #%d\n", (int)c, i);
 			return -ETIMEDOUT;
-		};
-		/* do arbitration here: 
-		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
+		}
+		/* FIXME do arbitration here:
+		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
+		 *
+		 * Report a unique code, so higher level code can retry
+		 * the whole (combined) message and *NOT* issue STOP.
 		 */
 		scllo(adap);
 	}
 	sdahi(adap);
-	if (sclhi(adap)<0){ /* timeout */
+	if (sclhi(adap) < 0) { /* timeout */
 		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
 			"timeout at ack\n", (int)c);
 		return -ETIMEDOUT;
-	};
-	/* read ack: SDA should be pulled down by slave */
+	}
+
+	/* read ack: SDA should be pulled down by slave, or it may
+	 * NAK (usually to report problems with the data we wrote).
+	 */
 	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
 	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
 		ack ? "A" : "NA");
@@ -198,24 +203,24 @@
 }
 
 
-static int i2c_inb(struct i2c_adapter *i2c_adap) 
+static int i2c_inb(struct i2c_adapter *i2c_adap)
 {
 	/* read byte via i2c port, without start/stop sequence	*/
 	/* acknowledge is sent in i2c_read.			*/
 	int i;
-	unsigned char indata=0;
+	unsigned char indata = 0;
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
 	sdahi(adap);
-	for (i=0;i<8;i++) {
-		if (sclhi(adap)<0) { /* timeout */
+	for (i = 0; i < 8; i++) {
+		if (sclhi(adap) < 0) { /* timeout */
 			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
 				"#%d\n", 7 - i);
 			return -ETIMEDOUT;
-		};
+		}
 		indata *= 2;
-		if ( getsda(adap) ) 
+		if (getsda(adap))
 			indata |= 0x01;
 		setscl(adap, 0);
 		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
@@ -228,66 +233,67 @@
  * Sanity check for the adapter hardware - check the reaction of
  * the bus lines only if it seems to be idle.
  */
-static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
-	int scl,sda;
+static int test_bus(struct i2c_algo_bit_data *adap, char *name)
+{
+	int scl, sda;
 
-	if (adap->getscl==NULL)
+	if (adap->getscl == NULL)
 		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
 
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if (!scl || !sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl || !sda) {
 		printk(KERN_WARNING "%s: bus seems to be busy\n", name);
 		goto bailout;
 	}
 
 	sdalo(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 != sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (sda) {
 		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
 		goto bailout;
 	}
-	if ( 0 == scl ) {
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL unexpected low "
 		       "while pulling SDA low!\n", name);
 		goto bailout;
-	}		
+	}
 
 	sdahi(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 == sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
 		goto bailout;
 	}
-	if ( 0 == scl ) {
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL unexpected low "
 		       "while pulling SDA high!\n", name);
 		goto bailout;
 	}
 
 	scllo(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?0:getscl(adap));
-	if ( 0 != scl ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+	if (scl) {
 		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
 		goto bailout;
 	}
-	if ( 0 == sda ) {
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA unexpected low "
 		       "while pulling SCL low!\n", name);
 		goto bailout;
 	}
-	
+
 	sclhi(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 == scl ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
 		goto bailout;
 	}
-	if ( 0 == sda ) {
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA unexpected low "
 		       "while pulling SCL high!\n", name);
 		goto bailout;
@@ -314,9 +320,10 @@
 		       unsigned char addr, int retries)
 {
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	int i,ret = -1;
-	for (i=0;i<=retries;i++) {
-		ret = i2c_outb(i2c_adap,addr);
+	int i, ret = -1;
+
+	for (i = 0; i <= retries; i++) {
+		ret = i2c_outb(i2c_adap, addr);
 		if (ret == 1 || i == retries)
 			break;
 		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
@@ -338,20 +345,38 @@
 {
 	const unsigned char *temp = msg->buf;
 	int count = msg->len;
-	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
 	int retval;
-	int wrcount=0;
+	int wrcount = 0;
 
 	while (count > 0) {
 		retval = i2c_outb(i2c_adap, *temp);
-		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
-			count--; 
+
+		/* OK/ACK; or ignored NAK */
+		if ((retval > 0) || (nak_ok && (retval == 0))) {
+			count--;
 			temp++;
 			wrcount++;
-		} else { /* arbitration or no acknowledge */
-			dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
-			return (retval<0)? retval : -EFAULT;
-			        /* got a better one ?? */
+
+		/* A slave NAKing the master means the slave didn't like
+		 * something about the data it saw.  For example, maybe
+		 * the SMBus PEC was wrong.
+		 */
+		} else if (retval == 0) {
+			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+			return -EIO;
+
+		/* Timeout; or (someday) lost arbitration
+		 *
+		 * FIXME Lost ARB implies retrying the transaction from
+		 * the first message, after the "winning" master issues
+		 * its STOP.  As a rule, upper layer code has no reason
+		 * to know or care about this ... it is *NOT* an error.
+		 */
+		} else {
+			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+					retval);
+			return retval;
 		}
 	}
 	return wrcount;
@@ -376,14 +401,14 @@
 static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
 	int inval;
-	int rdcount=0;   	/* counts bytes read */
+	int rdcount = 0;	/* counts bytes read */
 	unsigned char *temp = msg->buf;
 	int count = msg->len;
 	const unsigned flags = msg->flags;
 
 	while (count > 0) {
 		inval = i2c_inb(i2c_adap);
-		if (inval>=0) {
+		if (inval >= 0) {
 			*temp = inval;
 			rdcount++;
 		} else {   /* read timed out */
@@ -431,7 +456,7 @@
  * returns:
  *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
- *	-ETIMEDOUT, for example if the lines are stuck...) 
+ *	-ETIMEDOUT, for example if the lines are stuck...)
  */
 static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
@@ -443,10 +468,10 @@
 	int ret, retries;
 
 	retries = nak_ok ? 0 : i2c_adap->retries;
-	
-	if ( (flags & I2C_M_TEN)  ) { 
+
+	if (flags & I2C_M_TEN) {
 		/* a ten bit address */
-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+		addr = 0xf0 | ((msg->addr >> 7) & 0x03);
 		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
 		/* try extended address code...*/
 		ret = try_address(i2c_adap, addr, retries);
@@ -456,33 +481,33 @@
 			return -EREMOTEIO;
 		}
 		/* the remaining 8 bit address */
-		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
+		ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
 		if ((ret != 1) && !nak_ok) {
 			/* the chip did not ack / xmission error occurred */
 			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
 			return -EREMOTEIO;
 		}
-		if ( flags & I2C_M_RD ) {
+		if (flags & I2C_M_RD) {
 			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
 				"start condition\n");
 			i2c_repstart(adap);
 			/* okay, now switch into reading mode */
 			addr |= 0x01;
 			ret = try_address(i2c_adap, addr, retries);
-			if ((ret!=1) && !nak_ok) {
+			if ((ret != 1) && !nak_ok) {
 				dev_err(&i2c_adap->dev,
 					"died at repeated address code\n");
 				return -EREMOTEIO;
 			}
 		}
 	} else {		/* normal 7bit address	*/
-		addr = ( msg->addr << 1 );
-		if (flags & I2C_M_RD )
+		addr = msg->addr << 1;
+		if (flags & I2C_M_RD)
 			addr |= 1;
-		if (flags & I2C_M_REV_DIR_ADDR )
+		if (flags & I2C_M_REV_DIR_ADDR)
 			addr ^= 1;
 		ret = try_address(i2c_adap, addr, retries);
-		if ((ret!=1) && !nak_ok)
+		if ((ret != 1) && !nak_ok)
 			return -EREMOTEIO;
 	}
 
@@ -494,15 +519,14 @@
 {
 	struct i2c_msg *pmsg;
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	
-	int i,ret;
+	int i, ret;
 	unsigned short nak_ok;
 
 	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
 	i2c_start(adap);
-	for (i=0;i<num;i++) {
+	for (i = 0; i < num; i++) {
 		pmsg = &msgs[i];
-		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
 			if (i) {
 				bit_dbg(3, &i2c_adap->dev, "emitting "
@@ -517,7 +541,7 @@
 				goto bailout;
 			}
 		}
-		if (pmsg->flags & I2C_M_RD ) {
+		if (pmsg->flags & I2C_M_RD) {
 			/* read bytes into buffer*/
 			ret = readbytes(i2c_adap, pmsg);
 			if (ret >= 1)
@@ -551,7 +575,7 @@
 
 static u32 bit_func(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
 	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
 	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
@@ -565,8 +589,8 @@
 	.functionality	= bit_func,
 };
 
-/* 
- * registering functions to load algorithms at runtime 
+/*
+ * registering functions to load algorithms at runtime
  */
 static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
 {
@@ -574,7 +598,7 @@
 
 	if (bit_test) {
 		int ret = test_bus(bit_adap, adap->name);
-		if (ret<0)
+		if (ret < 0)
 			return -ENODEV;
 	}
 
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index ab2e6f3..8907b01 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -203,35 +203,6 @@
 /* ----- Utility functions
  */
 
-static inline int try_address(struct i2c_algo_pcf_data *adap,
-		       unsigned char addr, int retries)
-{
-	int i, status, ret = -1;
-	int wfp;
-	for (i=0;i<retries;i++) {
-		i2c_outb(adap, addr);
-		i2c_start(adap);
-		status = get_pcf(adap, 1);
-		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
-			if ((status & I2C_PCF_LRB) == 0) { 
-				i2c_stop(adap);
-				break;	/* success! */
-			}
-		}
-		if (wfp == -EINTR) {
-			/* arbitration lost */
-			udelay(adap->udelay);
-			return -EINTR;
-		}
-		i2c_stop(adap);
-		udelay(adap->udelay);
-	}
-	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
-	                   addr));
-	return ret;
-}
-
-
 static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
                          int count, int last)
 {
@@ -321,47 +292,19 @@
 }
 
 
-static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
-                                struct i2c_msg *msg, int retries) 
+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+			 struct i2c_msg *msg)
 {
 	unsigned short flags = msg->flags;
 	unsigned char addr;
-	int ret;
-	if ( (flags & I2C_M_TEN)  ) { 
-		/* a ten bit address */
-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
-		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
-		/* try extended address code...*/
-		ret = try_address(adap, addr, retries);
-		if (ret!=1) {
-			printk(KERN_ERR "died at extended address code.\n");
-			return -EREMOTEIO;
-		}
-		/* the remaining 8 bit address */
-		i2c_outb(adap,msg->addr & 0x7f);
-/* Status check comes here */
-		if (ret != 1) {
-			printk(KERN_ERR "died at 2nd address code.\n");
-			return -EREMOTEIO;
-		}
-		if ( flags & I2C_M_RD ) {
-			i2c_repstart(adap);
-			/* okay, now switch into reading mode */
-			addr |= 0x01;
-			ret = try_address(adap, addr, retries);
-			if (ret!=1) {
-				printk(KERN_ERR "died at extended address code.\n");
-				return -EREMOTEIO;
-			}
-		}
-	} else {		/* normal 7bit address	*/
-		addr = ( msg->addr << 1 );
-		if (flags & I2C_M_RD )
-			addr |= 1;
-		if (flags & I2C_M_REV_DIR_ADDR )
-			addr ^= 1;
-		i2c_outb(adap, addr);
-	}
+
+	addr = msg->addr << 1;
+	if (flags & I2C_M_RD)
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+	i2c_outb(adap, addr);
+
 	return 0;
 }
 
@@ -390,7 +333,7 @@
 		     pmsg->flags & I2C_M_RD ? "read" : "write",
                      pmsg->len, pmsg->addr, i + 1, num);)
     
-		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
+		ret = pcf_doAddress(adap, pmsg);
 
 		/* Send START */
 		if (i == 0) {
@@ -453,7 +396,7 @@
 static u32 pcf_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
-	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 
+	       I2C_FUNC_PROTOCOL_MANGLING;
 }
 
 /* -----exported algorithm data: -------------------------------------	*/
@@ -475,9 +418,7 @@
 
 	/* register new adapter to i2c module... */
 	adap->algo = &pcf_algo;
-
-	adap->timeout = 100;		/* default values, should	*/
-	adap->retries = 3;		/* be replaced by defines	*/
+	adap->timeout = 100;
 
 	if ((rval = pcf_init_8584(pcf_adap)))
 		return rval;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6c..8d12b26 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -182,7 +182,8 @@
 	  will be called i2c-i801.
 
 config I2C_I810
-	tristate "Intel 810/815"
+	tristate "Intel 810/815 (DEPRECATED)"
+	default n
 	depends on PCI
 	select I2C_ALGOBIT
 	help
@@ -195,6 +196,8 @@
 	    i815
 	    i845G
 
+	  This driver is deprecated in favor of the i810fb and intelfb drivers.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i810.
 
@@ -259,20 +262,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-iop3xx.
 
-config I2C_IXP4XX
-	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
-	depends on ARCH_IXP4XX
-	select I2C_ALGOBIT
-	help
-	  Say Y here if you have an Intel IXP4xx(420,421,422,425) based 
-	  system and are using GPIO lines for an I2C bus.
-
-	  This support is also available as a module. If so, the module
-	  will be called i2c-ixp4xx.
-
-	  This driver is deprecated and will be dropped soon. Use i2c-gpio
-	  instead.
-
 config I2C_IXP2000
 	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
 	depends on ARCH_IXP2000
@@ -396,7 +385,8 @@
 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
 
 config I2C_PROSAVAGE
-	tristate "S3/VIA (Pro)Savage"
+	tristate "S3/VIA (Pro)Savage (DEPRECATED)"
+	default n
 	depends on PCI
 	select I2C_ALGOBIT
 	help
@@ -407,6 +397,8 @@
 	    S3/VIA KM266/VT8375 aka ProSavage8
 	    S3/VIA KM133/VT8365 aka Savage4
 
+	  This driver is deprecated in favor of the savagefb driver.
+
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-prosavage.
 
@@ -418,13 +410,16 @@
 	  Samsung S3C2410 based System-on-Chip devices.
 
 config I2C_SAVAGE4
-	tristate "S3 Savage 4"
-	depends on PCI && EXPERIMENTAL
+	tristate "S3 Savage 4 (DEPRECATED)"
+	default n
+	depends on PCI
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the 
 	  S3 Savage 4 I2C interface.
 
+	  This driver is deprecated in favor of the savagefb driver.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-savage4.
 
@@ -611,7 +606,7 @@
 	    VT8231
 	    VT8233/A
 	    VT8235
-	    VT8237R/A
+	    VT8237R/A/S
 	    VT8251
 	    CX700
 
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c2..ea7068f 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -20,7 +20,6 @@
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
-obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
 obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 7490dc1..573abe4 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -334,6 +334,10 @@
 	int error;
 	u8 temp;
 	
+	/* driver_data might come from user-space, so check it */
+	if (id->driver_data > ARRAY_SIZE(chipname))
+		return -EINVAL;
+
 	if (amd756_ioport) {
 		dev_err(&pdev->dev, "Only one device supported "
 		       "(you have a strange motherboard, btw)\n");
@@ -405,6 +409,7 @@
 	.id_table	= amd756_ids,
 	.probe		= amd756_probe,
 	.remove		= __devexit_p(amd756_remove),
+	.dynids.use_driver_data = 1,
 };
 
 static int __init amd756_init(void)
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 2f68416..1953b26 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -30,14 +30,22 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
+#include <linux/slab.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 
-#include "i2c-au1550.h"
+struct i2c_au1550_data {
+	u32	psc_base;
+	int	xfer_timeout;
+	int	ack_timeout;
+	struct i2c_adapter adap;
+	struct resource *ioarea;
+};
 
 static int
 wait_xfer_done(struct i2c_au1550_data *adap)
@@ -105,7 +113,7 @@
 }
 
 static int
-do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
 {
 	volatile psc_smb_t	*sp;
 	u32			stat;
@@ -134,6 +142,10 @@
 	if (rd)
 		addr |= 1;
 
+	/* zero-byte xfers stop immediately */
+	if (q)
+		addr |= PSC_SMBTXRX_STP;
+
 	/* Put byte into fifo, start up master.
 	*/
 	sp->psc_smbtxrx = addr;
@@ -142,7 +154,7 @@
 	au_sync();
 	if (wait_ack(adap))
 		return -EIO;
-	return 0;
+	return (q) ? wait_master_done(adap) : 0;
 }
 
 static u32
@@ -262,7 +274,8 @@
 
 	for (i = 0; !err && i < num; i++) {
 		p = &msgs[i];
-		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+		err = do_address(adap, p->addr, p->flags & I2C_M_RD,
+				 (p->len == 0));
 		if (err || !p->len)
 			continue;
 		if (p->flags & I2C_M_RD)
@@ -294,18 +307,48 @@
  * Prior to calling us, the 50MHz clock frequency and routing
  * must have been set up for the PSC indicated by the adapter.
  */
-int
-i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
+static int __devinit
+i2c_au1550_probe(struct platform_device *pdev)
 {
-	struct i2c_au1550_data *adap = i2c_adap->algo_data;
-	volatile psc_smb_t	*sp;
-	u32	stat;
+	struct i2c_au1550_data *priv;
+	volatile psc_smb_t *sp;
+	struct resource *r;
+	u32 stat;
+	int ret;
 
-	i2c_adap->algo = &au1550_algo;
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+					  pdev->name);
+	if (!priv->ioarea) {
+		ret = -EBUSY;
+		goto out_mem;
+	}
+
+	priv->psc_base = r->start;
+	priv->xfer_timeout = 200;
+	priv->ack_timeout = 200;
+
+	priv->adap.id = I2C_HW_AU1550_PSC;
+	priv->adap.nr = pdev->id;
+	priv->adap.algo = &au1550_algo;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &pdev->dev;
+	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
 
 	/* Now, set up the PSC for SMBus PIO mode.
 	*/
-	sp = (volatile psc_smb_t *)(adap->psc_base);
+	sp = (volatile psc_smb_t *)priv->psc_base;
 	sp->psc_ctrl = PSC_CTRL_DISABLE;
 	au_sync();
 	sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
@@ -343,87 +386,87 @@
 		au_sync();
 	} while ((stat & PSC_SMBSTAT_DR) == 0);
 
-	return i2c_add_adapter(i2c_adap);
+	ret = i2c_add_numbered_adapter(&priv->adap);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, priv);
+		return 0;
+	}
+
+	/* disable the PSC */
+	sp->psc_smbcfg = 0;
+	sp->psc_ctrl = PSC_CTRL_DISABLE;
+	au_sync();
+
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+out_mem:
+	kfree(priv);
+out:
+	return ret;
 }
 
-
-int
-i2c_au1550_del_bus(struct i2c_adapter *adap)
+static int __devexit
+i2c_au1550_remove(struct platform_device *pdev)
 {
-	return i2c_del_adapter(adap);
-}
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
 
-static int
-pb1550_reg(struct i2c_client *client)
-{
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&priv->adap);
+	sp->psc_smbcfg = 0;
+	sp->psc_ctrl = PSC_CTRL_DISABLE;
+	au_sync();
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+	kfree(priv);
 	return 0;
 }
 
 static int
-pb1550_unreg(struct i2c_client *client)
+i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
 {
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+
+	sp->psc_ctrl = PSC_CTRL_SUSPEND;
+	au_sync();
 	return 0;
 }
 
-static struct i2c_au1550_data pb1550_i2c_info = {
-	SMBUS_PSC_BASE, 200, 200
-};
-
-static struct i2c_adapter pb1550_board_adapter = {
-	name:              "pb1550 adapter",
-	id:                I2C_HW_AU1550_PSC,
-	algo:              NULL,
-	algo_data:         &pb1550_i2c_info,
-	client_register:   pb1550_reg,
-	client_unregister: pb1550_unreg,
-};
-
-/* BIG hack to support the control interface on the Wolfson WM8731
- * audio codec on the Pb1550 board.  We get an address and two data
- * bytes to write, create an i2c message, and send it across the
- * i2c transfer function.  We do this here because we have access to
- * the i2c adapter structure.
- */
-static struct i2c_msg wm_i2c_msg;  /* We don't want this stuff on the stack */
-static	u8 i2cbuf[2];
-
-int
-pb1550_wm_codec_write(u8 addr, u8 reg, u8 val)
+static int
+i2c_au1550_resume(struct platform_device *pdev)
 {
-	wm_i2c_msg.addr = addr;
-	wm_i2c_msg.flags = 0;
-	wm_i2c_msg.buf = i2cbuf;
-	wm_i2c_msg.len = 2;
-	i2cbuf[0] = reg;
-	i2cbuf[1] = val;
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
 
-	return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1);
+	sp->psc_ctrl = PSC_CTRL_ENABLE;
+	au_sync();
+	while (!(sp->psc_smbstat & PSC_SMBSTAT_SR))
+		au_sync();
+	return 0;
 }
 
+static struct platform_driver au1xpsc_smbus_driver = {
+	.driver = {
+		.name	= "au1xpsc_smbus",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= i2c_au1550_probe,
+	.remove		= __devexit_p(i2c_au1550_remove),
+	.suspend	= i2c_au1550_suspend,
+	.resume		= i2c_au1550_resume,
+};
+
 static int __init
 i2c_au1550_init(void)
 {
-	printk(KERN_INFO "Au1550 I2C: ");
-
-	/* This is where we would set up a 50MHz clock source
-	 * and routing.  On the Pb1550, the SMBus is PSC2, which
-	 * uses a shared clock with USB.  This has been already
-	 * configured by Yamon as a 48MHz clock, close enough
-	 * for our work.
-	 */
-        if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) {
-		printk("failed to initialize.\n");
-                return -ENODEV;
-	}
-
-	printk("initialized.\n");
-	return 0;
+	return platform_driver_register(&au1xpsc_smbus_driver);
 }
 
 static void __exit
 i2c_au1550_exit(void)
 {
-	i2c_au1550_del_bus(&pb1550_board_adapter);
+	platform_driver_unregister(&au1xpsc_smbus_driver);
 }
 
 MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/i2c/busses/i2c-au1550.h
deleted file mode 100644
index fce15d1..0000000
--- a/drivers/i2c/busses/i2c-au1550.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
- * 2.6 port by Matt Porter <mporter@kernel.crashing.org>
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef I2C_AU1550_H
-#define I2C_AU1550_H
-
-struct i2c_au1550_data {
-	u32	psc_base;
-	int	xfer_timeout;
-	int	ack_timeout;
-};
-
-int i2c_au1550_add_bus(struct i2c_adapter *);
-int i2c_au1550_del_bus(struct i2c_adapter *);
-
-#endif /* I2C_AU1550_H */
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 67224a4..7dbdaeb 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -550,6 +550,7 @@
 
 	p_adap = &iface->adap;
 	p_adap->id = I2C_HW_BLACKFIN;
+	p_adap->nr = dev->id;
 	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
 	p_adap->algo = &bfin_twi_algorithm;
 	p_adap->algo_data = iface;
@@ -576,7 +577,7 @@
 	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
 	SSYNC();
 
-	rc = i2c_add_adapter(p_adap);
+	rc = i2c_add_numbered_adapter(p_adap);
 	if (rc < 0)
 		free_irq(iface->irq, iface);
 	else
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 6767988..cce5a61 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -510,7 +510,6 @@
 
 	/* FIXME */
 	adap->timeout = 1;
-	adap->retries = 1;
 
 	adap->nr = pdev->id;
 	r = i2c_add_numbered_adapter(adap);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ac27e5f..aa91579 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -4,6 +4,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
+    Copyright (C) 2007         Jean Delvare <khali@linux-fr.org>
 
     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
@@ -21,25 +22,34 @@
 */
 
 /*
-    SUPPORTED DEVICES	PCI ID
-    82801AA		2413
-    82801AB		2423
-    82801BA		2443
-    82801CA/CAM		2483
-    82801DB		24C3   (HW PEC supported)
-    82801EB		24D3   (HW PEC supported)
-    6300ESB		25A4
-    ICH6		266A
-    ICH7		27DA
-    ESB2		269B
-    ICH8		283E
-    ICH9		2930
-    Tolapai		5032
-    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
-    For SMBus support, they are similar to the PIIX4 and are part
-    of Intel's '810' and other chipsets.
-    See the file Documentation/i2c/busses/i2c-i801 for details.
-    I2C Block Read and Process Call are not supported.
+  Supports the following Intel I/O Controller Hubs (ICH):
+
+                                  I/O                     Block   I2C
+                                  region  SMBus   Block   proc.   block
+  Chip name             PCI ID    size    PEC     buffer  call    read
+  ----------------------------------------------------------------------
+  82801AA  (ICH)        0x2413     16      no      no      no      no
+  82801AB  (ICH0)       0x2423     16      no      no      no      no
+  82801BA  (ICH2)       0x2443     16      no      no      no      no
+  82801CA  (ICH3)       0x2483     32     soft     no      no      no
+  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
+  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
+  6300ESB               0x25a4     32     hard     yes     yes     yes
+  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
+  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
+  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
+  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
+  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
+  Tolapai               0x5032     32     hard     yes     ?       ?
+
+  Features supported by this driver:
+  Software PEC                     no
+  Hardware PEC                     yes
+  Block buffer                     yes
+  Block process call transaction   no
+  I2C block read transaction       yes  (doesn't use the block buffer)
+
+  See the file Documentation/i2c/busses/i2c-i801 for details.
 */
 
 /* Note: we assume there can only be one I801, with one SMBus interface */
@@ -62,9 +72,9 @@
 #define SMBHSTDAT0	(5 + i801_smba)
 #define SMBHSTDAT1	(6 + i801_smba)
 #define SMBBLKDAT	(7 + i801_smba)
-#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
-#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
-#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
+#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
 
 /* PCI Address Constants */
 #define SMBBAR		4
@@ -91,13 +101,13 @@
 #define I801_BYTE		0x04
 #define I801_BYTE_DATA		0x08
 #define I801_WORD_DATA		0x0C
-#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
+#define I801_PROC_CALL		0x10	/* unimplemented */
 #define I801_BLOCK_DATA		0x14
-#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
+#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
 #define I801_BLOCK_LAST		0x34
-#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
+#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
 #define I801_START		0x40
-#define I801_PEC_EN		0x80	/* ICH4 only */
+#define I801_PEC_EN		0x80	/* ICH3 and later */
 
 /* I801 Hosts Status register bits */
 #define SMBHSTSTS_BYTE_DONE	0x80
@@ -113,7 +123,12 @@
 static unsigned char i801_original_hstcfg;
 static struct pci_driver i801_driver;
 static struct pci_dev *I801_dev;
-static int isich4;
+
+#define FEATURE_SMBUS_PEC	(1 << 0)
+#define FEATURE_BLOCK_BUFFER	(1 << 1)
+#define FEATURE_BLOCK_PROC	(1 << 2)
+#define FEATURE_I2C_BLOCK_READ	(1 << 3)
+static unsigned int i801_features;
 
 static int i801_transaction(int xact)
 {
@@ -242,7 +257,8 @@
 }
 
 static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
-					       char read_write, int hwpec)
+					       char read_write, int command,
+					       int hwpec)
 {
 	int i, len;
 	int smbcmd;
@@ -259,16 +275,24 @@
 	}
 
 	for (i = 1; i <= len; i++) {
-		if (i == len && read_write == I2C_SMBUS_READ)
-			smbcmd = I801_BLOCK_LAST;
-		else
-			smbcmd = I801_BLOCK_DATA;
+		if (i == len && read_write == I2C_SMBUS_READ) {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+				smbcmd = I801_I2C_BLOCK_LAST;
+			else
+				smbcmd = I801_BLOCK_LAST;
+		} else {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA
+			 && read_write == I2C_SMBUS_READ)
+				smbcmd = I801_I2C_BLOCK_DATA;
+			else
+				smbcmd = I801_BLOCK_DATA;
+		}
 		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
 
 		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
 
 		/* Make sure the SMBus host is ready to start transmitting */
 		temp = inb_p(SMBHSTSTS);
@@ -332,7 +356,8 @@
 			dev_dbg(&I801_dev->dev, "Error: no response!\n");
 		}
 
-		if (i == 1 && read_write == I2C_SMBUS_READ) {
+		if (i == 1 && read_write == I2C_SMBUS_READ
+		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
 			len = inb_p(SMBHSTDAT0);
 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
 				return -1;
@@ -353,9 +378,9 @@
 				temp);
 		}
 		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
 
 		if (result < 0)
 			return result;
@@ -384,33 +409,38 @@
 			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
 			pci_write_config_byte(I801_dev, SMBHSTCFG,
 					      hostc | SMBHSTCFG_I2C_EN);
-		} else {
+		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
 			dev_err(&I801_dev->dev,
-				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+				"I2C block read is unsupported!\n");
 			return -1;
 		}
 	}
 
-	if (read_write == I2C_SMBUS_WRITE) {
+	if (read_write == I2C_SMBUS_WRITE
+	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
 		if (data->block[0] < 1)
 			data->block[0] = 1;
 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
 			data->block[0] = I2C_SMBUS_BLOCK_MAX;
 	} else {
-		data->block[0] = 32;	/* max for reads */
+		data->block[0] = 32;	/* max for SMBus block reads */
 	}
 
-	if (isich4 && i801_set_block_buffer_mode() == 0 )
+	if ((i801_features & FEATURE_BLOCK_BUFFER)
+	 && !(command == I2C_SMBUS_I2C_BLOCK_DATA
+	      && read_write == I2C_SMBUS_READ)
+	 && i801_set_block_buffer_mode() == 0)
 		result = i801_block_transaction_by_block(data, read_write,
 							 hwpec);
 	else
 		result = i801_block_transaction_byte_by_byte(data, read_write,
-							     hwpec);
+							     command, hwpec);
 
 	if (result == 0 && hwpec)
 		i801_wait_hwpec();
 
-	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA
+	 && read_write == I2C_SMBUS_WRITE) {
 		/* restore saved configuration register value */
 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
 	}
@@ -426,7 +456,7 @@
 	int block = 0;
 	int ret, xact = 0;
 
-	hwpec = isich4 && (flags & I2C_CLIENT_PEC)
+	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
 
@@ -462,12 +492,23 @@
 		xact = I801_WORD_DATA;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_I2C_BLOCK_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 		       SMBHSTADD);
 		outb_p(command, SMBHSTCMD);
 		block = 1;
 		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		/* NB: page 240 of ICH5 datasheet shows that the R/#W
+		 * bit should be cleared here, even when reading */
+		outb_p((addr & 0x7f) << 1, SMBHSTADD);
+		if (read_write == I2C_SMBUS_READ) {
+			/* NB: page 240 of ICH5 datasheet also shows
+			 * that DATA1 is the cmd field when reading */
+			outb_p(command, SMBHSTDAT1);
+		} else
+			outb_p(command, SMBHSTCMD);
+		block = 1;
+		break;
 	case I2C_SMBUS_PROC_CALL:
 	default:
 		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
@@ -487,7 +528,7 @@
 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
 	   time, so we forcibly disable it after every transaction. Turn off
 	   E32B for the same reason. */
-	if (hwpec)
+	if (hwpec || block)
 		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
 		       SMBAUXCTL);
 
@@ -514,9 +555,11 @@
 static u32 i801_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-	     | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
@@ -556,8 +599,8 @@
 	int err;
 
 	I801_dev = dev;
+	i801_features = 0;
 	switch (dev->device) {
-	case PCI_DEVICE_ID_INTEL_82801DB_3:
 	case PCI_DEVICE_ID_INTEL_82801EB_3:
 	case PCI_DEVICE_ID_INTEL_ESB_4:
 	case PCI_DEVICE_ID_INTEL_ICH6_16:
@@ -565,11 +608,13 @@
 	case PCI_DEVICE_ID_INTEL_ESB2_17:
 	case PCI_DEVICE_ID_INTEL_ICH8_5:
 	case PCI_DEVICE_ID_INTEL_ICH9_6:
+		i801_features |= FEATURE_I2C_BLOCK_READ;
+		/* fall through */
+	case PCI_DEVICE_ID_INTEL_82801DB_3:
 	case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
-		isich4 = 1;
+		i801_features |= FEATURE_SMBUS_PEC;
+		i801_features |= FEATURE_BLOCK_BUFFER;
 		break;
-	default:
-		isich4 = 0;
 	}
 
 	err = pci_enable_device(dev);
@@ -610,6 +655,11 @@
 	else
 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
+	/* Clear special mode bits */
+	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+		       SMBAUXCTL);
+
 	/* set up the sysfs linkage to our parent device */
 	i801_adapter.dev.parent = &dev->dev;
 
@@ -678,9 +728,8 @@
 	pci_unregister_driver(&i801_driver);
 }
 
-MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
-		"Philip Edelbrock <phil@netroedge.com>, "
-		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
+	      "Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("I801 SMBus driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 9b43ff72..7c7eb0c 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2003, 2004 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
- * Based on original work by 
+ * Based on original work by
  * 	Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
  * 	Matt Porter  <mporter@mvista.com>
@@ -86,8 +86,8 @@
 	       KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
 	       KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
 	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
-		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 
-		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 
+		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
+		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
 		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
 }
 #  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
@@ -125,7 +125,7 @@
 {
 	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
 }
- 
+
 /*
  * Initialize IIC interface.
  */
@@ -134,7 +134,7 @@
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 
 	DBG("%d: init\n", dev->idx);
-	
+
 	/* Clear master address */
 	out_8(&iic->lmadr, 0);
 	out_8(&iic->hmadr, 0);
@@ -160,7 +160,7 @@
 
 	/* Clear control register */
 	out_8(&iic->cntl, 0);
-	
+
 	/* Enable interrupts if possible */
 	iic_interrupt_mode(dev, dev->irq >= 0);
 
@@ -171,7 +171,7 @@
 	DUMP_REGS("iic_init", dev);
 }
 
-/* 
+/*
  * Reset IIC interface
  */
 static void iic_dev_reset(struct ibm_iic_private* dev)
@@ -179,42 +179,42 @@
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int i;
 	u8 dc;
-	
+
 	DBG("%d: soft reset\n", dev->idx);
 	DUMP_REGS("reset", dev);
-	
+
     	/* Place chip in the reset state */
 	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
-	
+
 	/* Check if bus is free */
-	dc = in_8(&iic->directcntl);	
+	dc = in_8(&iic->directcntl);
 	if (!DIRCTNL_FREE(dc)){
 		DBG("%d: trying to regain bus control\n", dev->idx);
-	
+
 		/* Try to set bus free state */
-		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);	
-	
+		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
 		/* Wait until we regain bus control */
 		for (i = 0; i < 100; ++i){
 			dc = in_8(&iic->directcntl);
 			if (DIRCTNL_FREE(dc))
 				break;
-			
+
 			/* Toggle SCL line */
 			dc ^= DIRCNTL_SCC;
 			out_8(&iic->directcntl, dc);
 			udelay(10);
 			dc ^= DIRCNTL_SCC;
 			out_8(&iic->directcntl, dc);
-			
+
 			/* be nice */
 			cond_resched();
 		}
 	}
-	
+
 	/* Remove reset */
 	out_8(&iic->xtcntlss, 0);
-	
+
 	/* Reinitialize interface */
 	iic_dev_init(dev);
 }
@@ -324,14 +324,14 @@
 {
 	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
-	
-	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 
+
+	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
 	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
-	
+
 	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
 	out_8(&iic->sts, STS_IRQA | STS_SCMP);
 	wake_up_interruptible(&dev->wq);
-	
+
 	return IRQ_HANDLED;
 }
 
@@ -341,19 +341,19 @@
  */
 static int iic_xfer_result(struct ibm_iic_private* dev)
 {
-	volatile struct iic_regs __iomem *iic = dev->vaddr;	
-	
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+
 	if (unlikely(in_8(&iic->sts) & STS_ERR)){
-		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, 
+		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
 			in_8(&iic->extsts));
-				
+
 		/* Clear errors and possible pending IRQs */
-		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | 
+		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
 			EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
-			
+
 		/* Flush master data buffer */
 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
-		
+
 		/* Is bus free?
 		 * If error happened during combined xfer
 		 * IIC interface is usually stuck in some strange
@@ -376,11 +376,11 @@
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	unsigned long x;
-	
+
 	DBG("%d: iic_abort_xfer\n", dev->idx);
-	
+
 	out_8(&iic->cntl, CNTL_HMT);
-	
+
 	/*
 	 * Wait for the abort command to complete.
 	 * It's not worth to be optimized, just poll (timeout >= 1 tick)
@@ -405,13 +405,13 @@
  * Returns the number of transferred bytes or error (<0)
  */
 static int iic_wait_for_tc(struct ibm_iic_private* dev){
-	
+
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int ret = 0;
-	
+
 	if (dev->irq >= 0){
 		/* Interrupt mode */
-		ret = wait_event_interruptible_timeout(dev->wq, 
+		ret = wait_event_interruptible_timeout(dev->wq,
 			!(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ);
 
 		if (unlikely(ret < 0))
@@ -424,37 +424,37 @@
 	else {
 		/* Polling mode */
 		unsigned long x = jiffies + dev->adap.timeout * HZ;
-		
+
 		while (in_8(&iic->sts) & STS_PT){
 			if (unlikely(time_after(jiffies, x))){
 				DBG("%d: poll timeout\n", dev->idx);
 				ret = -ETIMEDOUT;
 				break;
 			}
-		
+
 			if (unlikely(signal_pending(current))){
 				DBG("%d: poll interrupted\n", dev->idx);
 				ret = -ERESTARTSYS;
 				break;
 			}
 			schedule();
-		}	
+		}
 	}
-	
+
 	if (unlikely(ret < 0))
 		iic_abort_xfer(dev);
 	else
 		ret = iic_xfer_result(dev);
-	
+
 	DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
-	
+
 	return ret;
 }
 
 /*
  * Low level master transfer routine
  */
-static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, 
+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
 			  int combined_xfer)
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
@@ -465,48 +465,48 @@
 	u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
 	if (pm->flags & I2C_M_RD)
 		cntl |= CNTL_RW;
-	
+
 	loops = (len + 3) / 4;
 	for (i = 0; i < loops; ++i, len -= 4){
 		int count = len > 4 ? 4 : len;
 		u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
-		
+
 		if (!(cntl & CNTL_RW))
 			for (j = 0; j < count; ++j)
 				out_8((void __iomem *)&iic->mdbuf, *buf++);
-		
+
 		if (i < loops - 1)
 			cmd |= CNTL_CHT;
 		else if (combined_xfer)
 			cmd |= CNTL_RPST;
-		
+
 		DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
-		
+
 		/* Start transfer */
 		out_8(&iic->cntl, cmd);
-		
+
 		/* Wait for completion */
 		ret = iic_wait_for_tc(dev);
 
 		if (unlikely(ret < 0))
 			break;
 		else if (unlikely(ret != count)){
-			DBG("%d: xfer_bytes, requested %d, transfered %d\n", 
+			DBG("%d: xfer_bytes, requested %d, transfered %d\n",
 				dev->idx, count, ret);
-			
+
 			/* If it's not a last part of xfer, abort it */
 			if (combined_xfer || (i < loops - 1))
     				iic_abort_xfer(dev);
-				
+
 			ret = -EREMOTEIO;
-			break;				
+			break;
 		}
-		
+
 		if (cntl & CNTL_RW)
 			for (j = 0; j < count; ++j)
 				*buf++ = in_8((void __iomem *)&iic->mdbuf);
 	}
-	
+
 	return ret > 0 ? 0 : ret;
 }
 
@@ -517,10 +517,10 @@
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	u16 addr = msg->addr;
-	
-	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, 
+
+	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
 		addr, msg->flags & I2C_M_TEN ? 10 : 7);
-	
+
 	if (msg->flags & I2C_M_TEN){
 	    out_8(&iic->cntl, CNTL_AMD);
 	    out_8(&iic->lmadr, addr);
@@ -537,15 +537,15 @@
 	return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
 }
 
-static inline int iic_address_neq(const struct i2c_msg* p1, 
+static inline int iic_address_neq(const struct i2c_msg* p1,
 				  const struct i2c_msg* p2)
 {
-	return (p1->addr != p2->addr) 
+	return (p1->addr != p2->addr)
 		|| ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
-} 
+}
 
 /*
- * Generic master transfer entrypoint. 
+ * Generic master transfer entrypoint.
  * Returns the number of processed messages or error (<0)
  */
 static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
@@ -553,20 +553,20 @@
     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int i, ret = 0;
-	
+
 	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
-	
+
 	if (!num)
 		return 0;
-	
+
 	/* Check the sanity of the passed messages.
 	 * Uhh, generic i2c layer is more suitable place for such code...
 	 */
 	if (unlikely(iic_invalid_address(&msgs[0]))){
-		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, 
+		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
 			msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
 		return -EINVAL;
-	}		
+	}
 	for (i = 0; i < num; ++i){
 		if (unlikely(msgs[i].len <= 0)){
 			if (num == 1 && !msgs[0].len){
@@ -576,7 +576,7 @@
 				 */
 				return iic_smbus_quick(dev, &msgs[0]);
 			}
-			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
+			DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
 				msgs[i].len, i);
 			return -EINVAL;
 		}
@@ -585,34 +585,34 @@
 			return -EINVAL;
 		}
 	}
-	
+
 	/* Check bus state */
 	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
 		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
-		
+
 		/* Usually it means something serious has happend.
 		 * We *cannot* have unfinished previous transfer
 		 * so it doesn't make any sense to try to stop it.
-		 * Probably we were not able to recover from the 
+		 * Probably we were not able to recover from the
 		 * previous error.
 		 * The only *reasonable* thing I can think of here
 		 * is soft reset.  --ebs
 		 */
 		iic_dev_reset(dev);
-		
+
 		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
 			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
 			return -EREMOTEIO;
 		}
-	} 
+	}
 	else {
 		/* Flush master data buffer (just in case) */
 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
 	}
-	
+
 	/* Load slave address */
 	iic_address(dev, &msgs[0]);
-	
+
 	/* Do real transfer */
     	for (i = 0; i < num && !ret; ++i)
 		ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
@@ -648,7 +648,7 @@
 
 	/* Convert to MHz */
 	opb /= 1000000;
-	
+
 	if (opb < 20 || opb > 150){
 		printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
 			opb);
@@ -666,7 +666,7 @@
 	struct i2c_adapter* adap;
 	struct ocp_func_iic_data* iic_data = ocp->def->additions;
 	int ret;
-	
+
 	if (!iic_data)
 		printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
 			ocp->def->index);
@@ -679,7 +679,7 @@
 
 	dev->idx = ocp->def->index;
 	ocp_set_drvdata(ocp, dev);
-	
+
 	if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
 				"ibm_iic")) {
 		ret = -EBUSY;
@@ -692,7 +692,7 @@
 		ret = -ENXIO;
 		goto fail2;
 	}
-	
+
 	init_waitqueue_head(&dev->wq);
 
 	dev->irq = iic_force_poll ? -1 : ocp->def->irq;
@@ -702,29 +702,29 @@
 		 */
 		iic_interrupt_mode(dev, 0);
 		if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
-			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", 
+			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
 				dev->idx, dev->irq);
-			/* Fallback to the polling mode */	
+			/* Fallback to the polling mode */
 			dev->irq = -1;
 		}
 	}
-	
+
 	if (dev->irq < 0)
-		printk(KERN_WARNING "ibm-iic%d: using polling mode\n", 
+		printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
 			dev->idx);
-		
+
 	/* Board specific settings */
 	dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
-	
-	/* clckdiv is the same for *all* IIC interfaces, 
+
+	/* clckdiv is the same for *all* IIC interfaces,
 	 * but I'd rather make a copy than introduce another global. --ebs
 	 */
 	dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
-	
+
 	/* Initialize IIC interface */
 	iic_dev_init(dev);
-	
+
 	/* Register it with i2c layer */
 	adap = &dev->adap;
 	adap->dev.parent = &ocp->dev;
@@ -736,7 +736,6 @@
 	adap->client_register = NULL;
 	adap->client_unregister = NULL;
 	adap->timeout = 1;
-	adap->retries = 1;
 
 	/*
 	 * If "dev->idx" is negative we consider it as zero.
@@ -750,24 +749,24 @@
 			dev->idx);
 		goto fail;
 	}
-	
+
 	printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
 		dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
 
 	return 0;
 
-fail:	
+fail:
 	if (dev->irq >= 0){
 		iic_interrupt_mode(dev, 0);
 		free_irq(dev->irq, dev);
-	}	
+	}
 
 	iounmap(dev->vaddr);
-fail2:	
+fail2:
 	release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
 fail1:
 	ocp_set_drvdata(ocp, NULL);
-	kfree(dev);	
+	kfree(dev);
 	return ret;
 }
 
@@ -783,13 +782,13 @@
 			dev->idx);
 		/* That's *very* bad, just shutdown IRQ ... */
 		if (dev->irq >= 0){
-		    iic_interrupt_mode(dev, 0);	
+		    iic_interrupt_mode(dev, 0);
 		    free_irq(dev->irq, dev);
 		    dev->irq = -1;
 		}
 	} else {
 		if (dev->irq >= 0){
-		    iic_interrupt_mode(dev, 0);	
+		    iic_interrupt_mode(dev, 0);
 		    free_irq(dev->irq, dev);
 		}
 		iounmap(dev->vaddr);
@@ -798,7 +797,7 @@
 	}
 }
 
-static struct ocp_device_id ibm_iic_ids[] __devinitdata = 
+static struct ocp_device_id ibm_iic_ids[] __devinitdata =
 {
 	{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
 	{ .vendor = OCP_VENDOR_INVALID }
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
index 59d7b43..fdaa482 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.h
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -2,11 +2,11 @@
  * drivers/i2c/busses/i2c-ibm_iic.h
  *
  * Support for the IIC peripheral on IBM PPC 4xx
- * 
+ *
  * Copyright (c) 2003 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
- * Based on original work by 
+ * Based on original work by
  * 	Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
  * 	Matt Porter  <mporter@mvista.com>
@@ -22,7 +22,7 @@
 #ifndef __I2C_IBM_IIC_H_
 #define __I2C_IBM_IIC_H_
 
-#include <linux/i2c.h> 
+#include <linux/i2c.h>
 
 struct iic_regs {
 	u16 mdbuf;
@@ -58,7 +58,7 @@
 #define CNTL_TCT_MASK	0x30
 #define CNTL_TCT_SHIFT	4
 #define CNTL_RPST	0x08
-#define CNTL_CHT	0x04 
+#define CNTL_CHT	0x04
 #define CNTL_RW		0x02
 #define CNTL_PT		0x01
 
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index c70146e..ab41400 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -490,7 +490,6 @@
 	 * Default values...should these come in from board code?
 	 */
 	new_adapter->timeout = 100;	
-	new_adapter->retries = 3;
 	new_adapter->algo = &iop3xx_i2c_algo;
 
 	init_waitqueue_head(&adapter_data->waitq);
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
deleted file mode 100644
index 069ed7f..0000000
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * drivers/i2c/busses/i2c-ixp4xx.c
- *
- * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
- * an on board I2C controller but provide 16 GPIO pins that are often
- * used to create an I2C bus. This driver provides an i2c_adapter 
- * interface that plugs in under algo_bit and drives the GPIO pins
- * as instructed by the alogorithm driver.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (c) 2003-2004 MontaVista Software Inc.
- *
- * This file is licensed under the terms of the GNU General Public 
- * License version 2. This program is licensed "as is" without any 
- * warranty of any kind, whether express or implied.
- *
- * NOTE: Since different platforms will use different GPIO pins for
- *       I2C, this driver uses an IXP4xx-specific platform_data
- *       pointer to pass the GPIO numbers to the driver. This 
- *       allows us to support all the different IXP4xx platforms
- *       w/o having to put #ifdefs in this driver.
- *
- *       See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a 
- *       device list and filling in the ixp4xx_i2c_pins data structure 
- *       that is passed as the platform_data to this driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include <asm/hardware.h>	/* Pick up IXP4xx-specific bits */
-
-static inline int ixp4xx_scl_pin(void *data)
-{
-	return ((struct ixp4xx_i2c_pins*)data)->scl_pin;
-}
-
-static inline int ixp4xx_sda_pin(void *data)
-{
-	return ((struct ixp4xx_i2c_pins*)data)->sda_pin;
-}
-
-static void ixp4xx_bit_setscl(void *data, int val)
-{
-	gpio_line_set(ixp4xx_scl_pin(data), 0);
-	gpio_line_config(ixp4xx_scl_pin(data),
-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
-}
-
-static void ixp4xx_bit_setsda(void *data, int val)
-{
-	gpio_line_set(ixp4xx_sda_pin(data), 0);
-	gpio_line_config(ixp4xx_sda_pin(data),
-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
-}
-
-static int ixp4xx_bit_getscl(void *data)
-{
-	int scl;
-
-	gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN );
-	gpio_line_get(ixp4xx_scl_pin(data), &scl);
-
-	return scl;
-}	
-
-static int ixp4xx_bit_getsda(void *data)
-{
-	int sda;
-
-	gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN );
-	gpio_line_get(ixp4xx_sda_pin(data), &sda);
-
-	return sda;
-}	
-
-struct ixp4xx_i2c_data {
-	struct ixp4xx_i2c_pins *gpio_pins;
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo_data;
-};
-
-static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
-{
-	struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev);
-
-	platform_set_drvdata(plat_dev, NULL);
-
-	i2c_del_adapter(&drv_data->adapter);
-
-	kfree(drv_data);
-
-	return 0;
-}
-
-static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
-{
-	int err;
-	struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data;
-	struct ixp4xx_i2c_data *drv_data = 
-		kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL);
-
-	if(!drv_data)
-		return -ENOMEM;
-
-	drv_data->gpio_pins = gpio;
-
-	/*
-	 * We could make a lot of these structures static, but
-	 * certain platforms may have multiple GPIO-based I2C
-	 * buses for various device domains, so we need per-device
-	 * algo_data->data. 
-	 */
-	drv_data->algo_data.data = gpio;
-	drv_data->algo_data.setsda = ixp4xx_bit_setsda;
-	drv_data->algo_data.setscl = ixp4xx_bit_setscl;
-	drv_data->algo_data.getsda = ixp4xx_bit_getsda;
-	drv_data->algo_data.getscl = ixp4xx_bit_getscl;
-	drv_data->algo_data.udelay = 10;
-	drv_data->algo_data.timeout = 100;
-
-	drv_data->adapter.id = I2C_HW_B_IXP4XX;
-	drv_data->adapter.class = I2C_CLASS_HWMON;
-	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
-		sizeof(drv_data->adapter.name));
-	drv_data->adapter.algo_data = &drv_data->algo_data;
-
-	drv_data->adapter.dev.parent = &plat_dev->dev;
-
-	gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN);
-	gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN);
-	gpio_line_set(gpio->scl_pin, 0);
-	gpio_line_set(gpio->sda_pin, 0);
-
-	err = i2c_bit_add_bus(&drv_data->adapter);
-	if (err) {
-		printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id);
-
-		kfree(drv_data);
-		return err;
-	}
-
-	platform_set_drvdata(plat_dev, drv_data);
-
-	return 0;
-}
-
-static struct platform_driver ixp4xx_i2c_driver = {
-	.probe		= ixp4xx_i2c_probe,
-	.remove		= ixp4xx_i2c_remove,
-	.driver		= {
-		.name	= "IXP4XX-I2C",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init ixp4xx_i2c_init(void)
-{
-	return platform_driver_register(&ixp4xx_i2c_driver);
-}
-
-static void __exit ixp4xx_i2c_exit(void)
-{
-	platform_driver_unregister(&ixp4xx_i2c_driver);
-}
-
-module_init(ixp4xx_i2c_init);
-module_exit(ixp4xx_i2c_exit);
-
-MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index d8de4ac..bbe787b 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -180,7 +180,7 @@
 static int mpc_write(struct mpc_i2c *i2c, int target,
 		     const u8 * data, int length, int restart)
 {
-	int i;
+	int i, result;
 	unsigned timeout = i2c->adap.timeout;
 	u32 flags = restart ? CCR_RSTA : 0;
 
@@ -192,15 +192,17 @@
 	/* Write target byte */
 	writeb((target << 1), i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	for (i = 0; i < length; i++) {
 		/* Write data byte */
 		writeb(data[i], i2c->base + MPC_I2C_DR);
 
-		if (i2c_wait(i2c, timeout, 1) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0)
+			return result;
 	}
 
 	return 0;
@@ -210,7 +212,7 @@
 		    u8 * data, int length, int restart)
 {
 	unsigned timeout = i2c->adap.timeout;
-	int i;
+	int i, result;
 	u32 flags = restart ? CCR_RSTA : 0;
 
 	/* Start with MEN */
@@ -221,8 +223,9 @@
 	/* Write target address byte - this time with the read flag set */
 	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	if (length) {
 		if (length == 1)
@@ -234,8 +237,9 @@
 	}
 
 	for (i = 0; i < length; i++) {
-		if (i2c_wait(i2c, timeout, 0) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
 
 		/* Generate txack on next to last byte */
 		if (i == length - 2)
@@ -309,7 +313,6 @@
 	.algo = &mpc_algo,
 	.class = I2C_CLASS_HWMON,
 	.timeout = 1,
-	.retries = 1
 };
 
 static int fsl_i2c_probe(struct platform_device *pdev)
@@ -321,9 +324,9 @@
 
 	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
 
-	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
-	}
 
 	i2c->irq = platform_get_irq(pdev, 0);
 	if (i2c->irq < 0) {
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 1bf590c..3dac920 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -351,6 +351,7 @@
 	pci_set_drvdata(dev, smbuses);
 
 	switch(dev->device) {
+	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
 		smbuses[0].blockops = 1;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index f2552b1..da66397 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -362,8 +362,6 @@
 
 	omap_i2c_enable_clocks(dev);
 
-	/* REVISIT: initialize and use adap->retries. This is an optional
-	 * feature */
 	if ((r = omap_i2c_wait_for_bb(dev)) < 0)
 		goto out;
 
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index ca18e0b..1603c81 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -368,6 +368,7 @@
 	smbus->adapter.class = I2C_CLASS_HWMON;
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
+	smbus->adapter.nr = PCI_FUNC(dev->devfn);
 
 	/* set up the sysfs linkage to our parent device */
 	smbus->adapter.dev.parent = &dev->dev;
@@ -375,7 +376,7 @@
 	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
 		  (CLK_100K_DIV & CTL_CLK_M)));
 
-	error = i2c_add_adapter(&smbus->adapter);
+	error = i2c_add_numbered_adapter(&smbus->adapter);
 	if (error)
 		goto out_release_region;
 
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 167e413..9bbe96c 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -121,10 +121,6 @@
 {
 	unsigned char temp;
 
-	/* match up the function */
-	if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
-		return -ENODEV;
-
 	dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
 
 	/* Don't access SMBus on IBM systems which get corrupted eeproms */
@@ -389,28 +385,21 @@
 };
 
 static struct pci_device_id piix4_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
-	  .driver_data = 3 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3),
-	  .driver_data = 3 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3),
-	  .driver_data = 0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB5) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
 	{ 0, }
 };
 
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 6426a61..2598d29 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -65,6 +65,7 @@
 	unsigned long		iosize;
 
 	int			irq;
+	int			use_pio;
 };
 
 #define _IBMR(i2c)	((i2c)->reg_base + 0)
@@ -163,6 +164,7 @@
 #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
 
 static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
 
 static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
 {
@@ -554,6 +556,71 @@
 	writel(icr, _ICR(i2c));
 }
 
+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+{
+	/* make timeout the same as for interrupt based functions */
+	long timeout = 2 * DEF_TIMEOUT;
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+		udelay(1000);
+		show_state(i2c);
+	}
+
+	if (timeout <= 0) {
+		show_state(i2c);
+		dev_err(&i2c->adap.dev,
+			"i2c_pxa: timeout waiting for bus free\n");
+		return I2C_RETRY;
+	}
+
+	/*
+	 * Set master mode.
+	 */
+	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+
+	return 0;
+}
+
+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+			       struct i2c_msg *msg, int num)
+{
+	unsigned long timeout = 500000; /* 5 seconds */
+	int ret = 0;
+
+	ret = i2c_pxa_pio_set_master(i2c);
+	if (ret)
+		goto out;
+
+	i2c->msg = msg;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+	i2c->msg_ptr = 0;
+	i2c->irqlogidx = 0;
+
+	i2c_pxa_start_message(i2c);
+
+	while (timeout-- && i2c->msg_num > 0) {
+		i2c_pxa_handler(0, i2c);
+		udelay(10);
+	}
+
+	i2c_pxa_stop_message(i2c);
+
+	/*
+	 * We place the return code in i2c->msg_idx.
+	 */
+	ret = i2c->msg_idx;
+
+out:
+	if (timeout == 0)
+		i2c_pxa_scream_blue_murder(i2c, "timeout");
+
+	return ret;
+}
+
 /*
  * We are protected by the adapter bus mutex.
  */
@@ -610,6 +677,35 @@
 	return ret;
 }
 
+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg msgs[], int num)
+{
+	struct pxa_i2c *i2c = adap->algo_data;
+	int ret, i;
+
+	/* If the I2C controller is disabled we need to reset it
+	  (probably due to a suspend/resume destroying state). We do
+	  this here as we can then avoid worrying about resuming the
+	  controller before its users. */
+	if (!(readl(_ICR(i2c)) & ICR_IUE))
+		i2c_pxa_reset(i2c);
+
+	for (i = adap->retries; i >= 0; i--) {
+		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+		if (ret != I2C_RETRY)
+			goto out;
+
+		if (i2c_debug)
+			dev_dbg(&adap->dev, "Retrying transmission\n");
+		udelay(100);
+	}
+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+	ret = -EREMOTEIO;
+ out:
+	i2c_pxa_set_slave(i2c, ret);
+	return ret;
+}
+
 /*
  * i2c_pxa_master_complete - complete the message and wake up.
  */
@@ -621,7 +717,8 @@
 	i2c->msg_num = 0;
 	if (ret)
 		i2c->msg_idx = ret;
-	wake_up(&i2c->wait);
+	if (!i2c->use_pio)
+		wake_up(&i2c->wait);
 }
 
 static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
@@ -840,6 +937,37 @@
 	.functionality	= i2c_pxa_functionality,
 };
 
+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+	.master_xfer	= i2c_pxa_pio_xfer,
+	.functionality	= i2c_pxa_functionality,
+};
+
+static void i2c_pxa_enable(struct platform_device *dev)
+{
+	if (cpu_is_pxa27x()) {
+		switch (dev->id) {
+		case 0:
+			pxa_gpio_mode(GPIO117_I2CSCL_MD);
+			pxa_gpio_mode(GPIO118_I2CSDA_MD);
+			break;
+		case 1:
+			local_irq_disable();
+			PCFR |= PCFR_PI2CEN;
+			local_irq_enable();
+			break;
+		}
+	}
+}
+
+static void i2c_pxa_disable(struct platform_device *dev)
+{
+	if (cpu_is_pxa27x() && dev->id == 1) {
+		local_irq_disable();
+		PCFR &= ~PCFR_PI2CEN;
+		local_irq_enable();
+	}
+}
+
 #define res_len(r)		((r)->end - (r)->start + 1)
 static int i2c_pxa_probe(struct platform_device *dev)
 {
@@ -864,7 +992,6 @@
 	}
 
 	i2c->adap.owner   = THIS_MODULE;
-	i2c->adap.algo    = &i2c_pxa_algorithm;
 	i2c->adap.retries = 5;
 
 	spin_lock_init(&i2c->lock);
@@ -899,34 +1026,28 @@
 #endif
 
 	clk_enable(i2c->clk);
-#ifdef CONFIG_PXA27x
-	switch (dev->id) {
-	case 0:
-		pxa_gpio_mode(GPIO117_I2CSCL_MD);
-		pxa_gpio_mode(GPIO118_I2CSDA_MD);
-		break;
-	case 1:
-		local_irq_disable();
-		PCFR |= PCFR_PI2CEN;
-		local_irq_enable();
+	i2c_pxa_enable(dev);
+
+	if (plat) {
+		i2c->adap.class = plat->class;
+		i2c->use_pio = plat->use_pio;
 	}
-#endif
 
-	ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
-			  i2c->adap.name, i2c);
-	if (ret)
-		goto ereqirq;
-
+	if (i2c->use_pio) {
+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
+	} else {
+		i2c->adap.algo = &i2c_pxa_algorithm;
+		ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+				  i2c->adap.name, i2c);
+		if (ret)
+			goto ereqirq;
+	}
 
 	i2c_pxa_reset(i2c);
 
 	i2c->adap.algo_data = i2c;
 	i2c->adap.dev.parent = &dev->dev;
 
-	if (plat) {
-		i2c->adap.class = plat->class;
-	}
-
 	/*
 	 * If "dev->id" is negative we consider it as zero.
 	 * The reason to do so is to avoid sysfs names that only make
@@ -952,17 +1073,11 @@
 	return 0;
 
 eadapt:
-	free_irq(irq, i2c);
+	if (!i2c->use_pio)
+		free_irq(irq, i2c);
 ereqirq:
 	clk_disable(i2c->clk);
-
-#ifdef CONFIG_PXA27x
-	if (dev->id == 1) {
-		local_irq_disable();
-		PCFR &= ~PCFR_PI2CEN;
-		local_irq_enable();
-	}
-#endif
+	i2c_pxa_disable(dev);
 eremap:
 	clk_put(i2c->clk);
 eclk:
@@ -979,18 +1094,12 @@
 	platform_set_drvdata(dev, NULL);
 
 	i2c_del_adapter(&i2c->adap);
-	free_irq(i2c->irq, i2c);
+	if (!i2c->use_pio)
+		free_irq(i2c->irq, i2c);
 
 	clk_disable(i2c->clk);
 	clk_put(i2c->clk);
-
-#ifdef CONFIG_PXA27x
-	if (dev->id == 1) {
-		local_irq_disable();
-		PCFR &= ~PCFR_PI2CEN;
-		local_irq_enable();
-	}
-#endif
+	i2c_pxa_disable(dev);
 
 	release_mem_region(i2c->iobase, i2c->iosize);
 	kfree(i2c);
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index 503a134..8fbbdb4 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -36,14 +36,6 @@
 /* ----- global defines ----------------------------------------------- */
 #define SMB_CSR(a,r) ((long)(a->reg_base + r))
 
-/* ----- global variables --------------------------------------------- */
-
-/* module parameters:
- */
-static int bit_scan;	/* have a look at what's hanging 'round */
-module_param(bit_scan, int, 0);
-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
-
 
 static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
 		      unsigned short flags, char read_write,
@@ -140,9 +132,8 @@
 /*
  * registering functions to load algorithms at runtime
  */
-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
 {
-	int i;
 	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
 
 	/* register new adapter to i2c module... */
@@ -152,24 +143,6 @@
 	csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
 	csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
 
-	/* scan bus */
-	if (bit_scan) {
-		union i2c_smbus_data data;
-		int rc;
-		printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
-		       i2c_adap->name);
-		for (i = 0x00; i < 0x7f; i++) {
-			/* XXXKW is this a realistic probe? */
-			rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
-					I2C_SMBUS_BYTE_DATA, &data);
-			if (!rc) {
-				printk("(%02x)",i);
-			} else
-				printk(".");
-		}
-		printk("\n");
-	}
-
 	return i2c_add_adapter(i2c_adap);
 }
 
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 84df29d..c2a9f8c 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -1,8 +1,8 @@
 /*
-    i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
-              monitoring
+    i2c-stub.c - I2C/SMBus chip emulator
 
     Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
 
     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
@@ -37,8 +37,8 @@
 
 struct stub_chip {
 	u8 pointer;
-	u8 bytes[256];
-	u16 words[256];
+	u16 words[256];		/* Byte operations use the LSB as per SMBus
+				   specification */
 };
 
 static struct stub_chip *stub_chips;
@@ -75,7 +75,7 @@
 					"wrote 0x%02x.\n",
 					addr, command);
 		} else {
-			data->byte = chip->bytes[chip->pointer++];
+			data->byte = chip->words[chip->pointer++] & 0xff;
 			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
 					"read  0x%02x.\n",
 					addr, data->byte);
@@ -86,12 +86,13 @@
 
 	case I2C_SMBUS_BYTE_DATA:
 		if (read_write == I2C_SMBUS_WRITE) {
-			chip->bytes[command] = data->byte;
+			chip->words[command] &= 0xff00;
+			chip->words[command] |= data->byte;
 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
 					"wrote 0x%02x at 0x%02x.\n",
 					addr, data->byte, command);
 		} else {
-			data->byte = chip->bytes[command];
+			data->byte = chip->words[command] & 0xff;
 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
 					"read  0x%02x at 0x%02x.\n",
 					addr, data->byte, command);
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index c9ce77f..77b13d0 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -4,7 +4,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
     Mark D. Studebaker <mdsxyz123@yahoo.com>
-    Copyright (C) 2005 - 2007  Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2005 - 2008  Jean Delvare <khali@linux-fr.org>
 
     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
@@ -35,6 +35,7 @@
    VT8235             0x3177             yes
    VT8237R            0x3227             yes
    VT8237A            0x3337             yes
+   VT8237S            0x3372             yes
    VT8251             0x3287             yes
    CX700              0x8324             yes
 
@@ -318,6 +319,10 @@
 	unsigned char temp;
 	int error = -ENODEV;
 
+	/* driver_data might come from user-space, so check it */
+	if (id->driver_data & 1 || id->driver_data > 0xff)
+		return -EINVAL;
+
 	/* Determine the address of the SMBus areas */
 	if (force_addr) {
 		vt596_smba = force_addr & 0xfff0;
@@ -389,6 +394,7 @@
 	case PCI_DEVICE_ID_VIA_8251:
 	case PCI_DEVICE_ID_VIA_8237:
 	case PCI_DEVICE_ID_VIA_8237A:
+	case PCI_DEVICE_ID_VIA_8237S:
 	case PCI_DEVICE_ID_VIA_8235:
 	case PCI_DEVICE_ID_VIA_8233A:
 	case PCI_DEVICE_ID_VIA_8233_0:
@@ -440,6 +446,8 @@
 	  .driver_data = SMBBA3 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
 	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
+	  .driver_data = SMBBA3 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
 	  .driver_data = SMBBA1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
@@ -455,6 +463,7 @@
 	.name		= "vt596_smbus",
 	.id_table	= vt596_ids,
 	.probe		= vt596_probe,
+	.dynids.use_driver_data = 1,
 };
 
 static int __init i2c_vt596_init(void)
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 2e1c24f..bd7082c 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -4,32 +4,6 @@
 
 menu "Miscellaneous I2C Chip support"
 
-config SENSORS_DS1337
-	tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
-	depends on EXPERIMENTAL
-	help
-	  If you say yes here you get support for Dallas Semiconductor
-	  DS1337 and DS1339 real-time clock chips.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called ds1337.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1307 instead.
-
-config SENSORS_DS1374
-	tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
-	depends on EXPERIMENTAL
-	help
-	  If you say yes here you get support for Dallas Semiconductor
-	  DS1374 real-time clock chips.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called ds1374.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1374 instead.
-
 config DS1682
 	tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
 	depends on EXPERIMENTAL
@@ -57,7 +31,7 @@
 	default n
 	help
 	  If you say yes here you get support for Philips PCF8574 and 
-	  PCF8574A chips.
+	  PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8574.
@@ -65,6 +39,20 @@
 	  These devices are hard to detect and rarely found on mainstream
 	  hardware.  If unsure, say N.
 
+config PCF8575
+	tristate "Philips PCF8575"
+	default n
+	help
+	  If you say yes here you get support for Philips PCF8575 chip.
+	  This chip is a 16-bit I/O expander for the I2C bus.  Several other
+	  chip manufacturers sell equivalent chips, e.g. Texas Instruments.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pcf8575.
+
+	  This device is hard to detect and is rarely found on mainstream
+	  hardware.  If unsure, say N.
+
 config SENSORS_PCA9539
 	tristate "Philips PCA9539 16-bit I/O port"
 	depends on EXPERIMENTAL
@@ -100,12 +88,8 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called isp1301_omap.
 
-# NOTE:  This isn't really OMAP-specific, except for the current
-# interface location in  <include/asm-arm/arch-omap/tps65010.h>
-# and having mostly OMAP-specific board support
 config TPS65010
 	tristate "TPS6501x Power Management chips"
-	depends on ARCH_OMAP
 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
 	help
 	  If you say yes here you get support for the TPS6501x series of
@@ -116,18 +100,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps65010.
 
-config SENSORS_M41T00
-	tristate "ST M41T00 RTC chip (DEPRECATED)"
-	depends on PPC32
-	help
-	  If you say yes here you get support for the ST M41T00 RTC chip.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called m41t00.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1307 or rtc-m41t80 instead.
-
 config SENSORS_MAX6875
 	tristate "Maxim MAX6875 Power supply supervisor"
 	depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index ca924e1..501f00c 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -2,14 +2,12 @@
 # Makefile for miscellaneous I2C chip drivers.
 #
 
-obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
-obj-$(CONFIG_SENSORS_DS1374)	+= ds1374.o
 obj-$(CONFIG_DS1682)		+= ds1682.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
 obj-$(CONFIG_SENSORS_MAX6875)	+= max6875.o
-obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
 obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
+obj-$(CONFIG_PCF8575)		+= pcf8575.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
deleted file mode 100644
index ec17d6b..0000000
--- a/drivers/i2c/chips/ds1337.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/ds1337.c
- *
- *  Copyright (C) 2005 James Chapman <jchapman@katalix.com>
- *
- *	based on linux/drivers/acorn/char/pcf8583.c
- *  Copyright (C) 2000 Russell King
- *
- * 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.
- *
- * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/rtc.h>		/* get the user-level API */
-#include <linux/bcd.h>
-#include <linux/list.h>
-
-/* Device registers */
-#define DS1337_REG_HOUR		2
-#define DS1337_REG_DAY		3
-#define DS1337_REG_DATE		4
-#define DS1337_REG_MONTH	5
-#define DS1337_REG_CONTROL	14
-#define DS1337_REG_STATUS	15
-
-/* FIXME - how do we export these interface constants? */
-#define DS1337_GET_DATE		0
-#define DS1337_SET_DATE		1
-
-/*
- * Functions declaration
- */
-static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD_1(ds1337);
-
-static int ds1337_attach_adapter(struct i2c_adapter *adapter);
-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
-static void ds1337_init_client(struct i2c_client *client);
-static int ds1337_detach_client(struct i2c_client *client);
-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg);
-
-/*
- * Driver data (common to all clients)
- */
-static struct i2c_driver ds1337_driver = {
-	.driver = {
-		.name	= "ds1337",
-	},
-	.attach_adapter	= ds1337_attach_adapter,
-	.detach_client	= ds1337_detach_client,
-	.command	= ds1337_command,
-};
-
-/*
- * Client data (each client gets its own)
- */
-struct ds1337_data {
-	struct i2c_client client;
-	struct list_head list;
-};
-
-/*
- * Internal variables
- */
-static LIST_HEAD(ds1337_clients);
-
-static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
-{
-	s32 tmp = i2c_smbus_read_byte_data(client, reg);
-
-	if (tmp < 0)
-		return -EIO;
-
-	*value = tmp;
-
-	return 0;
-}
-
-/*
- * Chip access functions
- */
-static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
-{
-	int result;
-	u8 buf[7];
-	u8 val;
-	struct i2c_msg msg[2];
-	u8 offs = 0;
-
-	if (!dt) {
-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	msg[0].addr = client->addr;
-	msg[0].flags = 0;
-	msg[0].len = 1;
-	msg[0].buf = &offs;
-
-	msg[1].addr = client->addr;
-	msg[1].flags = I2C_M_RD;
-	msg[1].len = sizeof(buf);
-	msg[1].buf = &buf[0];
-
-	result = i2c_transfer(client->adapter, msg, 2);
-
-	dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
-		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6]);
-
-	if (result == 2) {
-		dt->tm_sec = BCD2BIN(buf[0]);
-		dt->tm_min = BCD2BIN(buf[1]);
-		val = buf[2] & 0x3f;
-		dt->tm_hour = BCD2BIN(val);
-		dt->tm_wday = BCD2BIN(buf[3]) - 1;
-		dt->tm_mday = BCD2BIN(buf[4]);
-		val = buf[5] & 0x7f;
-		dt->tm_mon = BCD2BIN(val) - 1;
-		dt->tm_year = BCD2BIN(buf[6]);
-		if (buf[5] & 0x80)
-			dt->tm_year += 100;
-
-		dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
-			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
-			__FUNCTION__, dt->tm_sec, dt->tm_min,
-			dt->tm_hour, dt->tm_mday,
-			dt->tm_mon, dt->tm_year, dt->tm_wday);
-
-		return 0;
-	}
-
-	dev_err(&client->dev, "error reading data! %d\n", result);
-	return -EIO;
-}
-
-static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
-{
-	int result;
-	u8 buf[8];
-	u8 val;
-	struct i2c_msg msg[1];
-
-	if (!dt) {
-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
-		dt->tm_sec, dt->tm_min, dt->tm_hour,
-		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
-
-	buf[0] = 0;		/* reg offset */
-	buf[1] = BIN2BCD(dt->tm_sec);
-	buf[2] = BIN2BCD(dt->tm_min);
-	buf[3] = BIN2BCD(dt->tm_hour);
-	buf[4] = BIN2BCD(dt->tm_wday + 1);
-	buf[5] = BIN2BCD(dt->tm_mday);
-	buf[6] = BIN2BCD(dt->tm_mon + 1);
-	val = dt->tm_year;
-	if (val >= 100) {
-		val -= 100;
-		buf[6] |= (1 << 7);
-	}
-	buf[7] = BIN2BCD(val);
-
-	msg[0].addr = client->addr;
-	msg[0].flags = 0;
-	msg[0].len = sizeof(buf);
-	msg[0].buf = &buf[0];
-
-	result = i2c_transfer(client->adapter, msg, 1);
-	if (result == 1)
-		return 0;
-
-	dev_err(&client->dev, "error writing data! %d\n", result);
-	return -EIO;
-}
-
-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg)
-{
-	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
-
-	switch (cmd) {
-	case DS1337_GET_DATE:
-		return ds1337_get_datetime(client, arg);
-
-	case DS1337_SET_DATE:
-		return ds1337_set_datetime(client, arg);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * Public API for access to specific device. Useful for low-level
- * RTC access from kernel code.
- */
-int ds1337_do_command(int bus, int cmd, void *arg)
-{
-	struct list_head *walk;
-	struct list_head *tmp;
-	struct ds1337_data *data;
-
-	list_for_each_safe(walk, tmp, &ds1337_clients) {
-		data = list_entry(walk, struct ds1337_data, list);
-		if (data->client.adapter->nr == bus)
-			return ds1337_command(&data->client, cmd, arg);
-	}
-
-	return -ENODEV;
-}
-
-static int ds1337_attach_adapter(struct i2c_adapter *adapter)
-{
-	return i2c_probe(adapter, &addr_data, ds1337_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *new_client;
-	struct ds1337_data *data;
-	int err = 0;
-	const char *name = "";
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-				     I2C_FUNC_I2C))
-		goto exit;
-
-	if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-	INIT_LIST_HEAD(&data->list);
-
-	/* The common I2C client data is placed right before the
-	 * DS1337-specific data. 
-	 */
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &ds1337_driver;
-	new_client->flags = 0;
-
-	/*
-	 * Now we do the remaining detection. A negative kind means that
-	 * the driver was loaded with no force parameter (default), so we
-	 * must both detect and identify the chip. A zero kind means that
-	 * the driver was loaded with the force parameter, the detection
-	 * step shall be skipped. A positive kind means that the driver
-	 * was loaded with the force parameter and a given kind of chip is
-	 * requested, so both the detection and the identification steps
-	 * are skipped.
-	 *
-	 * For detection, we read registers that are most likely to cause
-	 * detection failure, i.e. those that have more bits with fixed
-	 * or reserved values.
-	 */
-
-	/* Default to an DS1337 if forced */
-	if (kind == 0)
-		kind = ds1337;
-
-	if (kind < 0) {		/* detection and identification */
-		u8 data;
-
-		/* Check that status register bits 6-2 are zero */
-		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
-		    (data & 0x7c))
-			goto exit_free;
-
-		/* Check for a valid day register value */
-		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
-		    (data == 0) || (data & 0xf8))
-			goto exit_free;
-
-		/* Check for a valid date register value */
-		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
-		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
-		    (data >= 0x32))
-			goto exit_free;
-
-		/* Check for a valid month register value */
-		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
-		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
-		    ((data >= 0x13) && (data <= 0x19)))
-			goto exit_free;
-
-		/* Check that control register bits 6-5 are zero */
-		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
-		    (data & 0x60))
-			goto exit_free;
-
-		kind = ds1337;
-	}
-
-	if (kind == ds1337)
-		name = "ds1337";
-
-	/* We can fill in the remaining client fields */
-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
-		goto exit_free;
-
-	/* Initialize the DS1337 chip */
-	ds1337_init_client(new_client);
-
-	/* Add client to local list */
-	list_add(&data->list, &ds1337_clients);
-
-	return 0;
-
-exit_free:
-	kfree(data);
-exit:
-	return err;
-}
-
-static void ds1337_init_client(struct i2c_client *client)
-{
-	u8 status, control;
-
-	/* On some boards, the RTC isn't configured by boot firmware.
-	 * Handle that case by starting/configuring the RTC now.
-	 */
-	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-
-	if ((status & 0x80) || (control & 0x80)) {
-		/* RTC not running */
-		u8 buf[1+16];	/* First byte is interpreted as address */
-		struct i2c_msg msg[1];
-
-		dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
-
-		/* Initialize all, including STATUS and CONTROL to zero */
-		memset(buf, 0, sizeof(buf));
-
-		/* Write valid values in the date/time registers */
-		buf[1+DS1337_REG_DAY] = 1;
-		buf[1+DS1337_REG_DATE] = 1;
-		buf[1+DS1337_REG_MONTH] = 1;
-
-		msg[0].addr = client->addr;
-		msg[0].flags = 0;
-		msg[0].len = sizeof(buf);
-		msg[0].buf = &buf[0];
-
-		i2c_transfer(client->adapter, msg, 1);
-	} else {
-		/* Running: ensure that device is set in 24-hour mode */
-		s32 val;
-
-		val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
-		if ((val >= 0) && (val & (1 << 6)))
-			i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
-						  val & 0x3f);
-	}
-}
-
-static int ds1337_detach_client(struct i2c_client *client)
-{
-	int err;
-	struct ds1337_data *data = i2c_get_clientdata(client);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	list_del(&data->list);
-	kfree(data);
-	return 0;
-}
-
-static int __init ds1337_init(void)
-{
-	return i2c_add_driver(&ds1337_driver);
-}
-
-static void __exit ds1337_exit(void)
-{
-	i2c_del_driver(&ds1337_driver);
-}
-
-MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
-MODULE_DESCRIPTION("DS1337 RTC driver");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(ds1337_do_command);
-
-module_init(ds1337_init);
-module_exit(ds1337_exit);
diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c
deleted file mode 100644
index 8a2ff0c..0000000
--- a/drivers/i2c/chips/ds1374.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * drivers/i2c/chips/ds1374.c
- *
- * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
- *
- * Author: Randy Vinson <rvinson@mvista.com>
- *
- * Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
- * interface and the SMBus interface of the i2c subsystem.
- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
- * recommened in .../Documentation/i2c/writing-clients section
- * "Sending and receiving", using SMBus level communication is preferred.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-
-#define DS1374_REG_TOD0		0x00
-#define DS1374_REG_TOD1		0x01
-#define DS1374_REG_TOD2		0x02
-#define DS1374_REG_TOD3		0x03
-#define DS1374_REG_WDALM0	0x04
-#define DS1374_REG_WDALM1	0x05
-#define DS1374_REG_WDALM2	0x06
-#define DS1374_REG_CR		0x07
-#define DS1374_REG_SR		0x08
-#define DS1374_REG_SR_OSF	0x80
-#define DS1374_REG_TCR		0x09
-
-#define	DS1374_DRV_NAME		"ds1374"
-
-static DEFINE_MUTEX(ds1374_mutex);
-
-static struct i2c_driver ds1374_driver;
-static struct i2c_client *save_client;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c = normal_addr,
-	.probe = ignore,
-	.ignore = ignore,
-};
-
-static ulong ds1374_read_rtc(void)
-{
-	ulong time = 0;
-	int reg = DS1374_REG_WDALM0;
-
-	while (reg--) {
-		s32 tmp;
-		if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
-			dev_warn(&save_client->dev,
-				 "can't read from rtc chip\n");
-			return 0;
-		}
-		time = (time << 8) | (tmp & 0xff);
-	}
-	return time;
-}
-
-static void ds1374_write_rtc(ulong time)
-{
-	int reg;
-
-	for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
-		if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
-		    < 0) {
-			dev_warn(&save_client->dev,
-				 "can't write to rtc chip\n");
-			break;
-		}
-		time = time >> 8;
-	}
-}
-
-static void ds1374_check_rtc_status(void)
-{
-	s32 tmp;
-
-	tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
-	if (tmp < 0) {
-		dev_warn(&save_client->dev,
-			 "can't read status from rtc chip\n");
-		return;
-	}
-	if (tmp & DS1374_REG_SR_OSF) {
-		dev_warn(&save_client->dev,
-			 "oscillator discontinuity flagged, time unreliable\n");
-		tmp &= ~DS1374_REG_SR_OSF;
-		tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
-						tmp & 0xff);
-		if (tmp < 0)
-			dev_warn(&save_client->dev,
-				 "can't clear discontinuity notification\n");
-	}
-}
-
-ulong ds1374_get_rtc_time(void)
-{
-	ulong t1, t2;
-	int limit = 10;		/* arbitrary retry limit */
-
-	mutex_lock(&ds1374_mutex);
-
-	/*
-	 * Since the reads are being performed one byte at a time using
-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
-	 * carry will occur during the read. To detect this, 2 reads are
-	 * performed and compared.
-	 */
-	do {
-		t1 = ds1374_read_rtc();
-		t2 = ds1374_read_rtc();
-	} while (t1 != t2 && limit--);
-
-	mutex_unlock(&ds1374_mutex);
-
-	if (t1 != t2) {
-		dev_warn(&save_client->dev,
-			 "can't get consistent time from rtc chip\n");
-		t1 = 0;
-	}
-
-	return t1;
-}
-
-static ulong new_time;
-
-static void ds1374_set_work(struct work_struct *work)
-{
-	ulong t1, t2;
-	int limit = 10;		/* arbitrary retry limit */
-
-	t1 = new_time;
-
-	mutex_lock(&ds1374_mutex);
-
-	/*
-	 * Since the writes are being performed one byte at a time using
-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
-	 * carry will occur during the write. To detect this, the write
-	 * value is read back and compared.
-	 */
-	do {
-		ds1374_write_rtc(t1);
-		t2 = ds1374_read_rtc();
-	} while (t1 != t2 && limit--);
-
-	mutex_unlock(&ds1374_mutex);
-
-	if (t1 != t2)
-		dev_warn(&save_client->dev,
-			 "can't confirm time set from rtc chip\n");
-}
-
-static struct workqueue_struct *ds1374_workqueue;
-
-static DECLARE_WORK(ds1374_work, ds1374_set_work);
-
-int ds1374_set_rtc_time(ulong nowtime)
-{
-	new_time = nowtime;
-
-	if (in_interrupt())
-		queue_work(ds1374_workqueue, &ds1374_work);
-	else
-		ds1374_set_work(NULL);
-
-	return 0;
-}
-
-/*
- *****************************************************************************
- *
- *	Driver Interface
- *
- *****************************************************************************
- */
-static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct i2c_client *client;
-	int rc;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;
-
-	strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
-	client->addr = addr;
-	client->adapter = adap;
-	client->driver = &ds1374_driver;
-
-	ds1374_workqueue = create_singlethread_workqueue("ds1374");
-	if (!ds1374_workqueue) {
-		kfree(client);
-		return -ENOMEM;	/* most expected reason */
-	}
-
-	if ((rc = i2c_attach_client(client)) != 0) {
-		kfree(client);
-		return rc;
-	}
-
-	save_client = client;
-
-	ds1374_check_rtc_status();
-
-	return 0;
-}
-
-static int ds1374_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, ds1374_probe);
-}
-
-static int ds1374_detach(struct i2c_client *client)
-{
-	int rc;
-
-	if ((rc = i2c_detach_client(client)) == 0) {
-		kfree(i2c_get_clientdata(client));
-		destroy_workqueue(ds1374_workqueue);
-	}
-	return rc;
-}
-
-static struct i2c_driver ds1374_driver = {
-	.driver = {
-		.name	= DS1374_DRV_NAME,
-	},
-	.id = I2C_DRIVERID_DS1374,
-	.attach_adapter = ds1374_attach,
-	.detach_client = ds1374_detach,
-};
-
-static int __init ds1374_init(void)
-{
-	return i2c_add_driver(&ds1374_driver);
-}
-
-static void __exit ds1374_exit(void)
-{
-	i2c_del_driver(&ds1374_driver);
-}
-
-module_init(ds1374_init);
-module_exit(ds1374_exit);
-
-MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
-MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 1a7eeeb..fde297b2 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -35,7 +35,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
+static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
 					0x55, 0x56, 0x57, I2C_CLIENT_END };
 
 /* Insmod parameters */
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ebfbb29..2a31601 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -100,7 +100,7 @@
 
 #if	defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
 
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 
 #else
 
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
deleted file mode 100644
index 3fcb646..0000000
--- a/drivers/i2c/chips/m41t00.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * I2C client/driver for the ST M41T00 family of i2c rtc chips.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
- * interface and the SMBus interface of the i2c subsystem.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/m41t00.h>
-#include <asm/time.h>
-#include <asm/rtc.h>
-
-static struct i2c_driver m41t00_driver;
-static struct i2c_client *save_client;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c	= normal_addr,
-	.probe		= ignore,
-	.ignore		= ignore,
-};
-
-struct m41t00_chip_info {
-	u8	type;
-	char	*name;
-	u8	read_limit;
-	u8	sec;		/* Offsets for chip regs */
-	u8	min;
-	u8	hour;
-	u8	day;
-	u8	mon;
-	u8	year;
-	u8	alarm_mon;
-	u8	alarm_hour;
-	u8	sqw;
-	u8	sqw_freq;
-};
-
-static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
-	{
-		.type		= M41T00_TYPE_M41T00,
-		.name		= "m41t00",
-		.read_limit	= 5,
-		.sec		= 0,
-		.min		= 1,
-		.hour		= 2,
-		.day		= 4,
-		.mon		= 5,
-		.year		= 6,
-	},
-	{
-		.type		= M41T00_TYPE_M41T81,
-		.name		= "m41t81",
-		.read_limit	= 1,
-		.sec		= 1,
-		.min		= 2,
-		.hour		= 3,
-		.day		= 5,
-		.mon		= 6,
-		.year		= 7,
-		.alarm_mon	= 0xa,
-		.alarm_hour	= 0xc,
-		.sqw		= 0x13,
-	},
-	{
-		.type		= M41T00_TYPE_M41T85,
-		.name		= "m41t85",
-		.read_limit	= 1,
-		.sec		= 1,
-		.min		= 2,
-		.hour		= 3,
-		.day		= 5,
-		.mon		= 6,
-		.year		= 7,
-		.alarm_mon	= 0xa,
-		.alarm_hour	= 0xc,
-		.sqw		= 0x13,
-	},
-};
-static struct m41t00_chip_info *m41t00_chip;
-
-ulong
-m41t00_get_rtc_time(void)
-{
-	s32 sec, min, hour, day, mon, year;
-	s32 sec1, min1, hour1, day1, mon1, year1;
-	u8 reads = 0;
-	u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
-	struct i2c_msg msgs[] = {
-		{
-			.addr	= save_client->addr,
-			.flags	= 0,
-			.len	= 1,
-			.buf	= msgbuf,
-		},
-		{
-			.addr	= save_client->addr,
-			.flags	= I2C_M_RD,
-			.len	= 8,
-			.buf	= buf,
-		},
-	};
-
-	sec = min = hour = day = mon = year = 0;
-
-	do {
-		if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
-			goto read_err;
-
-		sec1 = sec;
-		min1 = min;
-		hour1 = hour;
-		day1 = day;
-		mon1 = mon;
-		year1 = year;
-
-		sec = buf[m41t00_chip->sec] & 0x7f;
-		min = buf[m41t00_chip->min] & 0x7f;
-		hour = buf[m41t00_chip->hour] & 0x3f;
-		day = buf[m41t00_chip->day] & 0x3f;
-		mon = buf[m41t00_chip->mon] & 0x1f;
-		year = buf[m41t00_chip->year];
-	} while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
-			|| (min != min1) || (hour != hour1) || (day != day1)
-			|| (mon != mon1) || (year != year1)));
-
-	if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
-			|| (hour != hour1) || (day != day1) || (mon != mon1)
-			|| (year != year1)))
-		goto read_err;
-
-	sec = BCD2BIN(sec);
-	min = BCD2BIN(min);
-	hour = BCD2BIN(hour);
-	day = BCD2BIN(day);
-	mon = BCD2BIN(mon);
-	year = BCD2BIN(year);
-
-	year += 1900;
-	if (year < 1970)
-		year += 100;
-
-	return mktime(year, mon, day, hour, min, sec);
-
-read_err:
-	dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
-	return 0;
-}
-EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
-
-static void
-m41t00_set(void *arg)
-{
-	struct rtc_time	tm;
-	int nowtime = *(int *)arg;
-	s32 sec, min, hour, day, mon, year;
-	u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
-	struct i2c_msg msgs[] = {
-		{
-			.addr	= save_client->addr,
-			.flags	= 0,
-			.len	= 1,
-			.buf	= msgbuf,
-		},
-		{
-			.addr	= save_client->addr,
-			.flags	= I2C_M_RD,
-			.len	= 8,
-			.buf	= buf,
-		},
-	};
-
-	to_tm(nowtime, &tm);
-	tm.tm_year = (tm.tm_year - 1900) % 100;
-
-	sec = BIN2BCD(tm.tm_sec);
-	min = BIN2BCD(tm.tm_min);
-	hour = BIN2BCD(tm.tm_hour);
-	day = BIN2BCD(tm.tm_mday);
-	mon = BIN2BCD(tm.tm_mon);
-	year = BIN2BCD(tm.tm_year);
-
-	/* Read reg values into buf[0..7]/wbuf[1..8] */
-	if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
-		dev_err(&save_client->dev, "m41t00_set: Read error\n");
-		return;
-	}
-
-	wbuf[0] = 0; /* offset into rtc's regs */
-	buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
-	buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
-	buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
-	buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
-	buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
-	buf[m41t00_chip->year] = year;
-
-	if (i2c_master_send(save_client, wbuf, 9) < 0)
-		dev_err(&save_client->dev, "m41t00_set: Write error\n");
-}
-
-static ulong new_time;
-/* well, isn't this API just _lovely_? */
-static void
-m41t00_barf(struct work_struct *unusable)
-{
-	m41t00_set(&new_time);
-}
-
-static struct workqueue_struct *m41t00_wq;
-static DECLARE_WORK(m41t00_work, m41t00_barf);
-
-int
-m41t00_set_rtc_time(ulong nowtime)
-{
-	new_time = nowtime;
-
-	if (in_interrupt())
-		queue_work(m41t00_wq, &m41t00_work);
-	else
-		m41t00_set(&new_time);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
-
-/*
- *****************************************************************************
- *
- *	platform_data Driver Interface
- *
- *****************************************************************************
- */
-static int __init
-m41t00_platform_probe(struct platform_device *pdev)
-{
-	struct m41t00_platform_data *pdata;
-	int i;
-
-	if (pdev && (pdata = pdev->dev.platform_data)) {
-		normal_addr[0] = pdata->i2c_addr;
-
-		for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
-			if (m41t00_chip_info_tbl[i].type == pdata->type) {
-				m41t00_chip = &m41t00_chip_info_tbl[i];
-				m41t00_chip->sqw_freq = pdata->sqw_freq;
-				return 0;
-			}
-	}
-	return -ENODEV;
-}
-
-static int __exit
-m41t00_platform_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static struct platform_driver m41t00_platform_driver = {
-	.probe  = m41t00_platform_probe,
-	.remove = m41t00_platform_remove,
-	.driver = {
-		.owner = THIS_MODULE,
-		.name  = M41T00_DRV_NAME,
-	},
-};
-
-/*
- *****************************************************************************
- *
- *	Driver Interface
- *
- *****************************************************************************
- */
-static int
-m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct i2c_client *client;
-	int rc;
-
-	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
-			| I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;
-
-	strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
-	client->addr = addr;
-	client->adapter = adap;
-	client->driver = &m41t00_driver;
-
-	if ((rc = i2c_attach_client(client)))
-		goto attach_err;
-
-	if (m41t00_chip->type != M41T00_TYPE_M41T00) {
-		/* If asked, disable SQW, set SQW frequency & re-enable */
-		if (m41t00_chip->sqw_freq)
-			if (((rc = i2c_smbus_read_byte_data(client,
-					m41t00_chip->alarm_mon)) < 0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_mon, rc & ~0x40)) <0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->sqw,
-					m41t00_chip->sqw_freq)) < 0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_mon, rc | 0x40)) <0))
-				goto sqw_err;
-
-		/* Make sure HT (Halt Update) bit is cleared */
-		if ((rc = i2c_smbus_read_byte_data(client,
-				m41t00_chip->alarm_hour)) < 0)
-			goto ht_err;
-
-		if (rc & 0x40)
-			if ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_hour, rc & ~0x40))<0)
-				goto ht_err;
-	}
-
-	/* Make sure ST (stop) bit is cleared */
-	if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
-		goto st_err;
-
-	if (rc & 0x80)
-		if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
-				rc & ~0x80)) < 0)
-			goto st_err;
-
-	m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
-	save_client = client;
-	return 0;
-
-st_err:
-	dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
-	goto attach_err;
-ht_err:
-	dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
-	goto attach_err;
-sqw_err:
-	dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
-attach_err:
-	kfree(client);
-	return rc;
-}
-
-static int
-m41t00_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, m41t00_probe);
-}
-
-static int
-m41t00_detach(struct i2c_client *client)
-{
-	int rc;
-
-	if ((rc = i2c_detach_client(client)) == 0) {
-		kfree(client);
-		destroy_workqueue(m41t00_wq);
-	}
-	return rc;
-}
-
-static struct i2c_driver m41t00_driver = {
-	.driver = {
-		.name	= M41T00_DRV_NAME,
-	},
-	.id		= I2C_DRIVERID_STM41T00,
-	.attach_adapter	= m41t00_attach,
-	.detach_client	= m41t00_detach,
-};
-
-static int __init
-m41t00_init(void)
-{
-	int rc;
-
-	if (!(rc = platform_driver_register(&m41t00_platform_driver)))
-		rc = i2c_add_driver(&m41t00_driver);
-	return rc;
-}
-
-static void __exit
-m41t00_exit(void)
-{
-	i2c_del_driver(&m41t00_driver);
-	platform_driver_unregister(&m41t00_platform_driver);
-}
-
-module_init(m41t00_init);
-module_exit(m41t00_exit);
-
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 64692f6..fb7ea56 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -34,7 +34,7 @@
 #include <linux/mutex.h>
 
 /* Do not scan - the MAX6875 access method will write to some EEPROM chips */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_1(max6875);
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index 21c6dd6..b3b830c 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -41,9 +41,11 @@
 #include <linux/i2c.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-					I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	I2C_CLIENT_END
+};
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
new file mode 100644
index 0000000..3ea08ac
--- /dev/null
+++ b/drivers/i2c/chips/pcf8575.c
@@ -0,0 +1,214 @@
+/*
+  pcf8575.c
+
+  About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
+  produced by a.o. Philips Semiconductors.
+
+  Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
+  <hennerich@blackfin.uclinux.org>
+  Based on pcf8574.c.
+
+  Copyright (c) 2007 Bart Van Assche <bart.vanassche@gmail.com>.
+  Ported this driver from ucLinux to the mainstream Linux kernel.
+
+  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>  /* kzalloc() */
+#include <linux/sysfs.h> /* sysfs_create_group() */
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	I2C_CLIENT_END
+};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+
+/* Each client has this additional data */
+struct pcf8575_data {
+	struct i2c_client client;
+	int write;		/* last written value, or error code */
+};
+
+static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pcf8575_detach_client(struct i2c_client *client);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pcf8575_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "pcf8575",
+	},
+	.attach_adapter	= pcf8575_attach_adapter,
+	.detach_client	= pcf8575_detach_client,
+};
+
+/* following are the sysfs callback functions */
+static ssize_t show_read(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u16 val;
+	u8 iopin_state[2];
+
+	i2c_master_recv(client, iopin_state, 2);
+
+	val = iopin_state[0];
+	val |= iopin_state[1] << 8;
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
+
+static ssize_t show_write(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct pcf8575_data *data = dev_get_drvdata(dev);
+	if (data->write < 0)
+		return data->write;
+	return sprintf(buf, "%d\n", data->write);
+}
+
+static ssize_t set_write(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8575_data *data = i2c_get_clientdata(client);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+	u8 iopin_state[2];
+
+	if (val > 0xffff)
+		return -EINVAL;
+
+	data->write = val;
+
+	iopin_state[0] = val & 0xFF;
+	iopin_state[1] = val >> 8;
+
+	i2c_master_send(client, iopin_state, 2);
+
+	return count;
+}
+
+static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+
+static struct attribute *pcf8575_attributes[] = {
+	&dev_attr_read.attr,
+	&dev_attr_write.attr,
+	NULL
+};
+
+static const struct attribute_group pcf8575_attr_group = {
+	.attrs = pcf8575_attributes,
+};
+
+/*
+ * Real code
+ */
+
+static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, pcf8575_detect);
+}
+
+/* This function is called by i2c_probe */
+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct pcf8575_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+		goto exit;
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet. */
+	data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &pcf8575_driver;
+	strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
+	data->write = -EAGAIN;
+
+	/* This is the place to detect whether the chip at the specified
+	   address really is a PCF8575 chip. However, there is no method known
+	   to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
+
+	/* Tell the I2C layer a new client has arrived */
+	err = i2c_attach_client(client);
+	if (err)
+		goto exit_free;
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
+	if (err)
+		goto exit_detach;
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int pcf8575_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
+
+	err = i2c_detach_client(client);
+	if (err)
+		return err;
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static int __init pcf8575_init(void)
+{
+	return i2c_add_driver(&pcf8575_driver);
+}
+
+static void __exit pcf8575_exit(void)
+{
+	i2c_del_driver(&pcf8575_driver);
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>, "
+	      "Bart Van Assche <bart.vanassche@gmail.com>");
+MODULE_DESCRIPTION("pcf8575 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pcf8575_init);
+module_exit(pcf8575_exit);
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index 4dc3637..865f440 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -27,7 +27,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 /* Insmod parameters */
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index e320994..4154a91 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -31,7 +31,7 @@
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
 
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
index 3de4b19..a10fd27 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/i2c/chips/tsl2550.c
@@ -432,11 +432,32 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return tsl2550_set_power_state(client, 0);
+}
+
+static int tsl2550_resume(struct i2c_client *client)
+{
+	return tsl2550_set_power_state(client, 1);
+}
+
+#else
+
+#define tsl2550_suspend		NULL
+#define tsl2550_resume		NULL
+
+#endif /* CONFIG_PM */
+
 static struct i2c_driver tsl2550_driver = {
 	.driver = {
 		.name	= TSL2550_DRV_NAME,
 		.owner	= THIS_MODULE,
 	},
+	.suspend = tsl2550_suspend,
+	.resume	= tsl2550_resume,
 	.probe	= tsl2550_probe,
 	.remove	= __devexit_p(tsl2550_remove),
 };
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b5e13e4..96da22e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -33,14 +33,15 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #include "i2c-core.h"
 
 
-static LIST_HEAD(adapters);
-static LIST_HEAD(drivers);
-static DEFINE_MUTEX(core_lists);
+static DEFINE_MUTEX(core_lock);
 static DEFINE_IDR(i2c_adapter_idr);
 
 #define is_newstyle_driver(d) ((d)->probe || (d)->remove)
@@ -198,6 +199,25 @@
 	.resume		= i2c_device_resume,
 };
 
+
+/**
+ * i2c_verify_client - return parameter as i2c_client, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find.  Use this function to avoid oopses caused
+ * by wrongly treating some non-I2C device as an i2c_client.
+ */
+struct i2c_client *i2c_verify_client(struct device *dev)
+{
+	return (dev->bus == &i2c_bus_type)
+			? to_i2c_client(dev)
+			: NULL;
+}
+EXPORT_SYMBOL(i2c_verify_client);
+
+
 /**
  * i2c_new_device - instantiate an i2c device for use with a new style driver
  * @adap: the adapter managing the device
@@ -276,6 +296,50 @@
 EXPORT_SYMBOL_GPL(i2c_unregister_device);
 
 
+static int dummy_nop(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver dummy_driver = {
+	.driver.name	= "dummy",
+	.probe		= dummy_nop,
+	.remove		= dummy_nop,
+};
+
+/**
+ * i2c_new_dummy - return a new i2c device bound to a dummy driver
+ * @adapter: the adapter managing the device
+ * @address: seven bit address to be used
+ * @type: optional label used for i2c_client.name
+ * Context: can sleep
+ *
+ * This returns an I2C client bound to the "dummy" driver, intended for use
+ * with devices that consume multiple addresses.  Examples of such chips
+ * include various EEPROMS (like 24c04 and 24c08 models).
+ *
+ * These dummy devices have two main uses.  First, most I2C and SMBus calls
+ * except i2c_transfer() need a client handle; the dummy will be that handle.
+ * And second, this prevents the specified address from being bound to a
+ * different driver.
+ *
+ * This returns the new i2c client, which should be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
+{
+	struct i2c_board_info info = {
+		.driver_name	= "dummy",
+		.addr		= address,
+	};
+
+	if (type)
+		strlcpy(info.type, type, sizeof info.type);
+	return i2c_new_device(adapter, &info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_dummy);
+
 /* ------------------------------------------------------------------------- */
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -320,18 +384,27 @@
 	mutex_unlock(&__i2c_board_lock);
 }
 
+static int i2c_do_add_adapter(struct device_driver *d, void *data)
+{
+	struct i2c_driver *driver = to_i2c_driver(d);
+	struct i2c_adapter *adap = data;
+
+	if (driver->attach_adapter) {
+		/* We ignore the return code; if it fails, too bad */
+		driver->attach_adapter(adap);
+	}
+	return 0;
+}
+
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
-	int res = 0;
-	struct list_head   *item;
-	struct i2c_driver  *driver;
+	int res = 0, dummy;
 
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
 	INIT_LIST_HEAD(&adap->clients);
 
-	mutex_lock(&core_lists);
-	list_add_tail(&adap->list, &adapters);
+	mutex_lock(&core_lock);
 
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
@@ -356,19 +429,14 @@
 		i2c_scan_static_board_info(adap);
 
 	/* let legacy drivers scan this bus for matching devices */
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->attach_adapter)
-			/* We ignore the return code; if it fails, too bad */
-			driver->attach_adapter(adap);
-	}
+	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+				 i2c_do_add_adapter);
 
 out_unlock:
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return res;
 
 out_list:
-	list_del(&adap->list);
 	idr_remove(&i2c_adapter_idr, adap->nr);
 	goto out_unlock;
 }
@@ -394,11 +462,11 @@
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
 		return -ENOMEM;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	/* "above" here means "above or equal to", sigh */
 	res = idr_get_new_above(&i2c_adapter_idr, adapter,
 				__i2c_first_dynamic_bus_num, &id);
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 
 	if (res < 0) {
 		if (res == -EAGAIN)
@@ -443,7 +511,7 @@
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
 		return -ENOMEM;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	/* "above" here means "above or equal to", sigh;
 	 * we need the "equal to" result to force the result
 	 */
@@ -452,7 +520,7 @@
 		status = -EBUSY;
 		idr_remove(&i2c_adapter_idr, id);
 	}
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	if (status == -EAGAIN)
 		goto retry;
 
@@ -462,6 +530,21 @@
 }
 EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 
+static int i2c_do_del_adapter(struct device_driver *d, void *data)
+{
+	struct i2c_driver *driver = to_i2c_driver(d);
+	struct i2c_adapter *adapter = data;
+	int res;
+
+	if (!driver->detach_adapter)
+		return 0;
+	res = driver->detach_adapter(adapter);
+	if (res)
+		dev_err(&adapter->dev, "detach_adapter failed (%d) "
+			"for driver [%s]\n", res, driver->driver.name);
+	return res;
+}
+
 /**
  * i2c_del_adapter - unregister I2C adapter
  * @adap: the adapter being unregistered
@@ -473,35 +556,24 @@
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
 	struct list_head  *item, *_n;
-	struct i2c_adapter *adap_from_list;
-	struct i2c_driver *driver;
 	struct i2c_client *client;
 	int res = 0;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
 	/* First make sure that this adapter was ever added */
-	list_for_each_entry(adap_from_list, &adapters, list) {
-		if (adap_from_list == adap)
-			break;
-	}
-	if (adap_from_list != adap) {
+	if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
 		pr_debug("i2c-core: attempting to delete unregistered "
 			 "adapter [%s]\n", adap->name);
 		res = -EINVAL;
 		goto out_unlock;
 	}
 
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->detach_adapter)
-			if ((res = driver->detach_adapter(adap))) {
-				dev_err(&adap->dev, "detach_adapter failed "
-					"for driver [%s]\n",
-					driver->driver.name);
-				goto out_unlock;
-			}
-	}
+	/* Tell drivers about this removal */
+	res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+			       i2c_do_del_adapter);
+	if (res)
+		goto out_unlock;
 
 	/* detach any active clients. This must be done first, because
 	 * it can fail; in which case we give up. */
@@ -529,7 +601,6 @@
 	/* clean up the sysfs representation */
 	init_completion(&adap->dev_released);
 	device_unregister(&adap->dev);
-	list_del(&adap->list);
 
 	/* wait for sysfs to drop all references */
 	wait_for_completion(&adap->dev_released);
@@ -540,7 +611,7 @@
 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return res;
 }
 EXPORT_SYMBOL(i2c_del_adapter);
@@ -583,21 +654,23 @@
 	if (res)
 		return res;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
-	list_add_tail(&driver->list,&drivers);
 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
 	/* legacy drivers scan i2c busses directly */
 	if (driver->attach_adapter) {
 		struct i2c_adapter *adapter;
 
-		list_for_each_entry(adapter, &adapters, list) {
+		down(&i2c_adapter_class.sem);
+		list_for_each_entry(adapter, &i2c_adapter_class.devices,
+				    dev.node) {
 			driver->attach_adapter(adapter);
 		}
+		up(&i2c_adapter_class.sem);
 	}
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
@@ -609,11 +682,11 @@
  */
 void i2c_del_driver(struct i2c_driver *driver)
 {
-	struct list_head   *item1, *item2, *_n;
+	struct list_head   *item2, *_n;
 	struct i2c_client  *client;
 	struct i2c_adapter *adap;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
 	/* new-style driver? */
 	if (is_newstyle_driver(driver))
@@ -623,8 +696,8 @@
 	 * attached. If so, detach them to be able to kill the driver
 	 * afterwards.
 	 */
-	list_for_each(item1,&adapters) {
-		adap = list_entry(item1, struct i2c_adapter, list);
+	down(&i2c_adapter_class.sem);
+	list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
 		if (driver->detach_adapter) {
 			if (driver->detach_adapter(adap)) {
 				dev_err(&adap->dev, "detach_adapter failed "
@@ -648,40 +721,31 @@
 			}
 		}
 	}
+	up(&i2c_adapter_class.sem);
 
  unregister:
 	driver_unregister(&driver->driver);
-	list_del(&driver->list);
 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 }
 EXPORT_SYMBOL(i2c_del_driver);
 
 /* ------------------------------------------------------------------------- */
 
-static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+static int __i2c_check_addr(struct device *dev, void *addrp)
 {
-	struct list_head   *item;
-	struct i2c_client  *client;
+	struct i2c_client	*client = i2c_verify_client(dev);
+	int			addr = *(int *)addrp;
 
-	list_for_each(item,&adapter->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->addr == addr)
-			return -EBUSY;
-	}
+	if (client && client->addr == addr)
+		return -EBUSY;
 	return 0;
 }
 
 static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
-	int rval;
-
-	mutex_lock(&adapter->clist_lock);
-	rval = __i2c_check_addr(adapter, addr);
-	mutex_unlock(&adapter->clist_lock);
-
-	return rval;
+	return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
 }
 
 int i2c_attach_client(struct i2c_client *client)
@@ -689,15 +753,6 @@
 	struct i2c_adapter *adapter = client->adapter;
 	int res = 0;
 
-	mutex_lock(&adapter->clist_lock);
-	if (__i2c_check_addr(client->adapter, client->addr)) {
-		res = -EBUSY;
-		goto out_unlock;
-	}
-	list_add_tail(&client->list,&adapter->clients);
-
-	client->usage_count = 0;
-
 	client->dev.parent = &client->adapter->dev;
 	client->dev.bus = &i2c_bus_type;
 
@@ -712,13 +767,17 @@
 
 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
-	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
-		client->name, client->dev.bus_id);
 	res = device_register(&client->dev);
 	if (res)
-		goto out_list;
+		goto out_err;
+
+	mutex_lock(&adapter->clist_lock);
+	list_add_tail(&client->list, &adapter->clients);
 	mutex_unlock(&adapter->clist_lock);
 
+	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+		client->name, client->dev.bus_id);
+
 	if (adapter->client_register)  {
 		if (adapter->client_register(client)) {
 			dev_dbg(&adapter->dev, "client_register "
@@ -729,12 +788,9 @@
 
 	return 0;
 
-out_list:
-	list_del(&client->list);
+out_err:
 	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
 		"(%d)\n", client->name, client->addr, res);
-out_unlock:
-	mutex_unlock(&adapter->clist_lock);
 	return res;
 }
 EXPORT_SYMBOL(i2c_attach_client);
@@ -744,12 +800,6 @@
 	struct i2c_adapter *adapter = client->adapter;
 	int res = 0;
 
-	if (client->usage_count > 0) {
-		dev_warn(&client->dev, "Client [%s] still busy, "
-			 "can't detach\n", client->name);
-		return -EBUSY;
-	}
-
 	if (adapter->client_unregister)  {
 		res = adapter->client_unregister(client);
 		if (res) {
@@ -762,9 +812,10 @@
 
 	mutex_lock(&adapter->clist_lock);
 	list_del(&client->list);
+	mutex_unlock(&adapter->clist_lock);
+
 	init_completion(&client->released);
 	device_unregister(&client->dev);
-	mutex_unlock(&adapter->clist_lock);
 	wait_for_completion(&client->released);
 
  out:
@@ -772,72 +823,58 @@
 }
 EXPORT_SYMBOL(i2c_detach_client);
 
-static int i2c_inc_use_client(struct i2c_client *client)
+/**
+ * i2c_use_client - increments the reference count of the i2c client structure
+ * @client: the client being referenced
+ *
+ * Each live reference to a client should be refcounted. The driver model does
+ * that automatically as part of driver binding, so that most drivers don't
+ * need to do this explicitly: they hold a reference until they're unbound
+ * from the device.
+ *
+ * A pointer to the client with the incremented reference counter is returned.
+ */
+struct i2c_client *i2c_use_client(struct i2c_client *client)
 {
-
-	if (!try_module_get(client->driver->driver.owner))
-		return -ENODEV;
-	if (!try_module_get(client->adapter->owner)) {
-		module_put(client->driver->driver.owner);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void i2c_dec_use_client(struct i2c_client *client)
-{
-	module_put(client->driver->driver.owner);
-	module_put(client->adapter->owner);
-}
-
-int i2c_use_client(struct i2c_client *client)
-{
-	int ret;
-
-	ret = i2c_inc_use_client(client);
-	if (ret)
-		return ret;
-
-	client->usage_count++;
-
-	return 0;
+	get_device(&client->dev);
+	return client;
 }
 EXPORT_SYMBOL(i2c_use_client);
 
-int i2c_release_client(struct i2c_client *client)
+/**
+ * i2c_release_client - release a use of the i2c client structure
+ * @client: the client being no longer referenced
+ *
+ * Must be called when a user of a client is finished with it.
+ */
+void i2c_release_client(struct i2c_client *client)
 {
-	if (!client->usage_count) {
-		pr_debug("i2c-core: %s used one too many times\n",
-			 __FUNCTION__);
-		return -EPERM;
-	}
-
-	client->usage_count--;
-	i2c_dec_use_client(client);
-
-	return 0;
+	put_device(&client->dev);
 }
 EXPORT_SYMBOL(i2c_release_client);
 
+struct i2c_cmd_arg {
+	unsigned	cmd;
+	void		*arg;
+};
+
+static int i2c_cmd(struct device *dev, void *_arg)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_cmd_arg	*arg = _arg;
+
+	if (client && client->driver && client->driver->command)
+		client->driver->command(client, arg->cmd, arg->arg);
+	return 0;
+}
+
 void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
 {
-	struct list_head  *item;
-	struct i2c_client *client;
+	struct i2c_cmd_arg	cmd_arg;
 
-	mutex_lock(&adap->clist_lock);
-	list_for_each(item,&adap->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (!try_module_get(client->driver->driver.owner))
-			continue;
-		if (NULL != client->driver->command) {
-			mutex_unlock(&adap->clist_lock);
-			client->driver->command(client,cmd,arg);
-			mutex_lock(&adap->clist_lock);
-		}
-		module_put(client->driver->driver.owner);
-       }
-       mutex_unlock(&adap->clist_lock);
+	cmd_arg.cmd = cmd;
+	cmd_arg.arg = arg;
+	device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
 }
 EXPORT_SYMBOL(i2c_clients_command);
 
@@ -848,11 +885,24 @@
 	retval = bus_register(&i2c_bus_type);
 	if (retval)
 		return retval;
-	return class_register(&i2c_adapter_class);
+	retval = class_register(&i2c_adapter_class);
+	if (retval)
+		goto bus_err;
+	retval = i2c_add_driver(&dummy_driver);
+	if (retval)
+		goto class_err;
+	return 0;
+
+class_err:
+	class_unregister(&i2c_adapter_class);
+bus_err:
+	bus_unregister(&i2c_bus_type);
+	return retval;
 }
 
 static void __exit i2c_exit(void)
 {
+	i2c_del_driver(&dummy_driver);
 	class_unregister(&i2c_adapter_class);
 	bus_unregister(&i2c_bus_type);
 }
@@ -879,7 +929,15 @@
 		}
 #endif
 
-		mutex_lock_nested(&adap->bus_lock, adap->level);
+		if (in_atomic() || irqs_disabled()) {
+			ret = mutex_trylock(&adap->bus_lock);
+			if (!ret)
+				/* I2C activity is ongoing. */
+				return -EAGAIN;
+		} else {
+			mutex_lock_nested(&adap->bus_lock, adap->level);
+		}
+
 		ret = adap->algo->master_xfer(adap,msgs,num);
 		mutex_unlock(&adap->bus_lock);
 
@@ -978,7 +1036,7 @@
 }
 
 int i2c_probe(struct i2c_adapter *adapter,
-	      struct i2c_client_address_data *address_data,
+	      const struct i2c_client_address_data *address_data,
 	      int (*found_proc) (struct i2c_adapter *, int, int))
 {
 	int i, err;
@@ -987,7 +1045,7 @@
 	/* Force entries are done first, and are not affected by ignore
 	   entries */
 	if (address_data->forces) {
-		unsigned short **forces = address_data->forces;
+		const unsigned short * const *forces = address_data->forces;
 		int kind;
 
 		for (kind = 0; forces[kind]; kind++) {
@@ -1085,7 +1143,6 @@
 		return NULL;
 	}
 
-	mutex_lock(&adap->clist_lock);
 	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
 		/* Check address validity */
 		if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
@@ -1095,7 +1152,7 @@
 		}
 
 		/* Check address availability */
-		if (__i2c_check_addr(adap, addr_list[i])) {
+		if (i2c_check_addr(adap, addr_list[i])) {
 			dev_dbg(&adap->dev, "Address 0x%02x already in "
 				"use, not probing\n", addr_list[i]);
 			continue;
@@ -1123,7 +1180,6 @@
 				break;
 		}
 	}
-	mutex_unlock(&adap->clist_lock);
 
 	if (addr_list[i] == I2C_CLIENT_END) {
 		dev_dbg(&adap->dev, "Probing failed, no device found\n");
@@ -1139,12 +1195,12 @@
 {
 	struct i2c_adapter *adapter;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
 	if (adapter && !try_module_get(adapter->owner))
 		adapter = NULL;
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return adapter;
 }
 EXPORT_SYMBOL(i2c_get_adapter);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index df540d5..393e679 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -182,27 +182,22 @@
 	return ret;
 }
 
+static int i2cdev_check(struct device *dev, void *addrp)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if (!client || client->addr != *(unsigned int *)addrp)
+		return 0;
+
+	return dev->driver ? -EBUSY : 0;
+}
+
 /* This address checking function differs from the one in i2c-core
    in that it considers an address with a registered device, but no
-   bound driver, as NOT busy. */
+   driver bound to it, as NOT busy. */
 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
-	struct list_head *item;
-	struct i2c_client *client;
-	int res = 0;
-
-	mutex_lock(&adapter->clist_lock);
-	list_for_each(item, &adapter->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->addr == addr) {
-			if (client->driver)
-				res = -EBUSY;
-			break;
-		}
-	}
-	mutex_unlock(&adapter->clist_lock);
-
-	return res;
+	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
 }
 
 static int i2cdev_ioctl(struct inode *inode, struct file *file,
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index ee01e27..64df55e 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -325,7 +325,7 @@
 	  If unsure, say N.
 
 config BLK_DEV_CMD640
-	bool "CMD640 chipset bugfix/support"
+	tristate "CMD640 chipset bugfix/support"
 	depends on X86
 	---help---
 	  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
@@ -359,9 +359,8 @@
 	  Otherwise say N.
 
 config BLK_DEV_IDEPNP
-	bool "PNP EIDE support"
+	tristate "PNP EIDE support"
 	depends on PNP
-	select IDE_GENERIC
 	help
 	  If you have a PnP (Plug and Play) compatible EIDE card and
 	  would like the kernel to automatically detect and activate
@@ -375,7 +374,19 @@
 	bool
 
 config IDEPCI_PCIBUS_ORDER
-	def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
+	depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	default y
+	help
+	  Probe IDE PCI devices in the order in which they appear on the
+	  PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
+	  instead of the order in which IDE PCI host drivers are loaded.
+
+	  Please note that this method of assuring stable naming of
+	  IDE devices is unreliable and use other means for achieving
+	  it (i.e. udev).
+
+	  If in doubt, say N.
 
 # TODO: split it on per host driver config options (or module parameters)
 config BLK_DEV_OFFBOARD
@@ -789,7 +800,7 @@
 endif
 
 config BLK_DEV_IDE_PMAC
-	bool "Builtin PowerMac IDE support"
+	tristate "Builtin PowerMac IDE support"
 	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
 	help
 	  This driver provides support for the built-in IDE controller on
@@ -843,8 +854,9 @@
        depends on BLK_DEV_IDE_AU1XXX
 
 config IDE_ARM
-	def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
-	select IDE_GENERIC
+	tristate "ARM IDE support"
+	depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+	default y
 
 config BLK_DEV_IDE_ICSIDE
 	tristate "ICS IDE interface support"
@@ -876,10 +888,9 @@
 	  Simtec BAST or the Thorcom VR1000
 
 config ETRAX_IDE
-	bool "ETRAX IDE support"
+	tristate "ETRAX IDE support"
 	depends on CRIS && BROKEN
 	select BLK_DEV_IDEDMA
-	select IDE_GENERIC
 	help
 	  Enables the ETRAX IDE driver.
 
@@ -911,17 +922,15 @@
 endchoice
 
 config IDE_H8300
-	bool "H8300 IDE support"
+	tristate "H8300 IDE support"
 	depends on H8300
-	select IDE_GENERIC
 	default y
 	help
 	  Enables the H8300 IDE driver.
 
 config BLK_DEV_GAYLE
-	bool "Amiga Gayle IDE interface support"
+	tristate "Amiga Gayle IDE interface support"
 	depends on AMIGA
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
 	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
@@ -951,9 +960,8 @@
 	  runtime using the "ide=doubler" kernel boot parameter.
 
 config BLK_DEV_BUDDHA
-	bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
+	tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
 	depends on ZORRO && EXPERIMENTAL
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the IDE interfaces on the Buddha, 
 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
@@ -964,9 +972,8 @@
 	  to one of its IDE interfaces.
 
 config BLK_DEV_FALCON_IDE
-	bool "Falcon IDE interface support"
+	tristate "Falcon IDE interface support"
 	depends on ATARI
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on the Atari
 	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
@@ -974,9 +981,8 @@
 	  interface.
 
 config BLK_DEV_MAC_IDE
-	bool "Macintosh Quadra/Powerbook IDE interface support"
+	tristate "Macintosh Quadra/Powerbook IDE interface support"
 	depends on MAC
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on some m68k
 	  Macintosh models. It supports both the `Quadra style' (used in
@@ -988,18 +994,16 @@
 	  builtin IDE interface.
 
 config BLK_DEV_Q40IDE
-	bool "Q40/Q60 IDE interface support"
+	tristate "Q40/Q60 IDE interface support"
 	depends on Q40
-	select IDE_GENERIC
 	help
 	  Enable the on-board IDE controller in the Q40/Q60.  This should
 	  normally be on; disable it only if you are running a custom hard
 	  drive subsystem through an expansion card.
 
 config BLK_DEV_MPC8xx_IDE
-	bool "MPC8xx IDE support"
+	tristate "MPC8xx IDE support"
 	depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
-	select IDE_GENERIC
 	help
 	  This option provides support for IDE on Motorola MPC8xx Systems.
 	  Please see 'Type of MPC8xx IDE interface' for details.
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index b181fc6..0d2da89 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -7,41 +7,37 @@
 # Note : at this point, these files are compiled on all systems.
 # In the future, some of these should be built conditionally.
 #
-# First come modules that register themselves with the core
+# link order is important here
 
 EXTRA_CFLAGS				+= -Idrivers/ide
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
-
 ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
 
-ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
-
-# Core IDE code - must come before legacy
+# core IDE code
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.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
 
-# built-in only drivers from arm/
-ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
-
-# built-in only drivers from legacy/
-ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
-ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
-ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
-ide-core-$(CONFIG_BLK_DEV_MAC_IDE)	+= legacy/macide.o
-ide-core-$(CONFIG_BLK_DEV_Q40IDE)	+= legacy/q40ide.o
-
-# built-in only drivers from ppc/
-ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ppc/mpc8xx.o
-ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ppc/pmac.o
-
-# built-in only drivers from h8300/
-ide-core-$(CONFIG_IDE_H8300)		+= h8300/ide-h8300.o
-
 obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
+
+ifeq ($(CONFIG_IDE_ARM), y)
+	ide-arm-core-y += arm/ide_arm.o
+	obj-y += ide-arm-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ pci/
+
+obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)	+= ide-scan-pci.o
+
+ifeq ($(CONFIG_BLK_DEV_CMD640), y)
+	cmd640-core-y += pci/cmd640.o
+	obj-y += cmd640-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= cris/ ppc/
+obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o
+obj-$(CONFIG_IDE_H8300)			+= h8300/
 obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
 
 obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
@@ -49,6 +45,20 @@
 obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ arm/ mips/
-obj-$(CONFIG_BLK_DEV_HD)		+= legacy/
-obj-$(CONFIG_ETRAX_IDE)		+= cris/
+ifeq ($(CONFIG_BLK_DEV_IDECS), y)
+	ide-cs-core-y += legacy/ide-cs.o
+	obj-y += ide-cs-core.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
+	ide-platform-core-y += legacy/ide_platform.o
+	obj-y += ide-platform-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= arm/ mips/
+
+# old hd driver must be last
+ifeq ($(CONFIG_BLK_DEV_HD), y)
+	hd-core-y += legacy/hd.o
+	obj-y += hd-core.o
+endif
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
index 6a78f07..5f63ad2 100644
--- a/drivers/ide/arm/Makefile
+++ b/drivers/ide/arm/Makefile
@@ -3,4 +3,8 @@
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
 obj-$(CONFIG_BLK_DEV_IDE_BAST)		+= bast-ide.o
 
+ifeq ($(CONFIG_IDE_ARM), m)
+	obj-m += ide_arm.o
+endif
+
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index 48db616..45bf9c8 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, NULL, 0, hwif);
+	ide_register_hw(&hw, NULL, hwif);
 
 	return 0;
 }
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 673402f..8a5c720 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -287,26 +287,10 @@
 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 }
 
-static void icside_dma_host_off(ide_drive_t *drive)
+static void icside_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void icside_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-}
-
-static void icside_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static int icside_dma_on(ide_drive_t *drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
 static int icside_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
@@ -422,10 +406,7 @@
 	hwif->dmatable_dma	= 0;
 	hwif->set_dma_mode	= icside_set_dma_mode;
 
-	hwif->dma_host_off	= icside_dma_host_off;
-	hwif->dma_off_quietly	= icside_dma_off_quietly;
-	hwif->dma_host_on	= icside_dma_host_on;
-	hwif->ide_dma_on	= icside_dma_on;
+	hwif->dma_host_set	= icside_dma_host_set;
 	hwif->dma_setup		= icside_dma_setup;
 	hwif->dma_exec_cmd	= icside_dma_exec_cmd;
 	hwif->dma_start		= icside_dma_start;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index 8957cba..60f2497 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -24,12 +24,25 @@
 # define IDE_ARM_IRQ	IRQ_HARDDISK
 #endif
 
-void __init ide_arm_init(void)
+static int __init ide_arm_init(void)
 {
+	ide_hwif_t *hwif;
 	hw_regs_t hw;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	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, 1, NULL);
+
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		ide_init_port_hw(hwif, &hw);
+		idx[0] = hwif->index;
+
+		ide_device_add(idx);
+	}
+
+	return 0;
 }
+
+module_init(ide_arm_init);
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index 0775a3a..e6b56d1 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -13,26 +13,18 @@
 
 #include <asm/ecard.h>
 
-static ide_hwif_t *
-rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
+static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+			       void __iomem *ctrl, unsigned int sz, int irq)
 {
 	unsigned long port = (unsigned long)base;
-	ide_hwif_t *hwif = ide_find_port(port);
 	int i;
 
-	if (hwif == NULL)
-		goto out;
-
 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hwif->io_ports[i] = port;
+		hw->io_ports[i] = port;
 		port += sz;
 	}
-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
-	hwif->irq = irq;
-	hwif->mmio = 1;
-	default_hwif_mmiops(hwif);
-out:
-	return hwif;
+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+	hw->irq = irq;
 }
 
 static int __devinit
@@ -42,6 +34,7 @@
 	void __iomem *base;
 	int ret;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+	hw_regs_t hw;
 
 	ret = ecard_request_resources(ec);
 	if (ret)
@@ -53,11 +46,17 @@
 		goto release;
 	}
 
-	hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
+	hwif = ide_find_port((unsigned long)base);
 	if (hwif) {
-		hwif->hwif_data = base;
-		hwif->gendev.parent = &ec->dev;
-		hwif->noprobe = 0;
+		memset(&hw, 0, sizeof(hw));
+		rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
+		hw.chipset = ide_generic;
+		hw.dev = &ec->dev;
+
+		ide_init_port_hw(hwif, &hw);
+
+		hwif->mmio = 1;
+		default_hwif_mmiops(hwif);
 
 		idx[0] = hwif->index;
 
diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
index 6176e8d..20b9596 100644
--- a/drivers/ide/cris/Makefile
+++ b/drivers/ide/cris/Makefile
@@ -1,3 +1,3 @@
 EXTRA_CFLAGS				+= -Idrivers/ide
 
-obj-y					+= ide-cris.o
+obj-$(CONFIG_IDE_ETRAX)			+= ide-cris.o
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 325e608..8c3294c 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -673,9 +673,8 @@
 static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-static int cris_dma_on (ide_drive_t *drive);
 
-static void cris_dma_off(ide_drive_t *drive)
+static void cris_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -755,13 +754,11 @@
 		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
 }
 
-void __init
-init_e100_ide (void)
+static int __init init_e100_ide(void)
 {
 	hw_regs_t hw;
-	int ide_offsets[IDE_NR_PORTS];
-	int h;
-	int i;
+	int ide_offsets[IDE_NR_PORTS], h, i;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	printk("ide: ETRAX FS built-in ATA DMA controller\n");
 
@@ -778,9 +775,11 @@
 		                ide_offsets,
 		                0, 0, cris_ide_ack_intr,
 		                ide_default_irq(0));
-		ide_register_hw(&hw, NULL, 1, &hwif);
+		hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
 		if (hwif == NULL)
 			continue;
+		ide_init_port_data(hwif, hwif->index);
+		ide_init_port_hw(hwif, &hw);
 		hwif->mmio = 1;
 		hwif->chipset = ide_etrax100;
 		hwif->set_pio_mode = &cris_set_pio_mode;
@@ -789,6 +788,7 @@
 		hwif->ata_output_data = &cris_ide_output_data;
 		hwif->atapi_input_bytes = &cris_atapi_input_bytes;
 		hwif->atapi_output_bytes = &cris_atapi_output_bytes;
+		hwif->dma_host_set = &cris_dma_host_set;
 		hwif->ide_dma_end = &cris_dma_end;
 		hwif->dma_setup = &cris_dma_setup;
 		hwif->dma_exec_cmd = &cris_dma_exec_cmd;
@@ -799,9 +799,6 @@
 		hwif->OUTBSYNC = &cris_ide_outbsync;
 		hwif->INB = &cris_ide_inb;
 		hwif->INW = &cris_ide_inw;
-		hwif->dma_host_off = &cris_dma_off;
-		hwif->dma_host_on = &cris_dma_on;
-		hwif->dma_off_quietly = &cris_dma_off;
 		hwif->cbl = ATA_CBL_PATA40;
 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
 		hwif->pio_mask = ATA_PIO4,
@@ -809,6 +806,8 @@
 		hwif->drives[1].autotune = 1;
 		hwif->ultra_mask = cris_ultra_mask;
 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
+
+		idx[h] = hwif->index;
 	}
 
 	/* Reset pulse */
@@ -821,14 +820,12 @@
 	cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
 	cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
 	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
-}
 
-static int cris_dma_on (ide_drive_t *drive)
-{
+	ide_device_add(idx);
+
 	return 0;
 }
 
-
 static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
 
 /*
@@ -1060,3 +1057,5 @@
 		LED_DISK_READ(1);
 	}
 }
+
+module_init(init_e100_ide);
diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
new file mode 100644
index 0000000..5eba16f
--- /dev/null
+++ b/drivers/ide/h8300/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_IDE_H8300)			+= ide-h8300.o
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 4a49b5c..4f6d019 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -84,11 +84,12 @@
 	hwif->INSL  = NULL;
 }
 
-void __init h8300_ide_init(void)
+static int __init h8300_ide_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int idx;
+	int index;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
 		goto out_busy;
@@ -100,16 +101,28 @@
 	hw_setup(&hw);
 
 	/* register if */
-	idx = ide_register_hw(&hw, NULL, 1, &hwif);
-	if (idx == -1) {
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif == NULL) {
 		printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
-		return;
+		return -ENOENT;
 	}
 
+	index = hwif->index;
+	ide_init_port_data(hwif, index);
+	ide_init_port_hw(hwif, &hw);
 	hwif_setup(hwif);
-	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
-	return;
+	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index);
+
+	idx[0] = index;
+
+	ide_device_add(idx);
+
+	return 0;
 
 out_busy:
 	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
+
+	return -EBUSY;
 }
+
+module_init(h8300_ide_init);
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index e0bb0cf..e888fc3 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -386,7 +386,7 @@
 
 	/* convert gtf to IDE Taskfile */
 	memcpy(&args.tf_array[7], &gtf->tfa, 7);
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
 	if (ide_noacpitfs) {
 		DEBPRINT("_GTF execution disabled\n");
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index d8fdd86..717e114 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -201,7 +201,7 @@
 
 	memset(&task, 0, sizeof(task));
 	task.tf_flags = IDE_TFLAG_NO_SELECT_MASK;  /* FIXME? */
-	task.tf_flags |= (IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE);
+	task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE);
 
 	if (drive->select.b.lba) {
 		if (lba48) {
@@ -219,13 +219,8 @@
 			tf->lbal   = (u8) block;
 			tf->lbam   = (u8)(block >>  8);
 			tf->lbah   = (u8)(block >> 16);
-#ifdef DEBUG
-			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
-				drive->name, tf->hob_nsect, tf->nsect,
-				tf->hob_lbah, tf->hob_lbam, tf->hob_lbal,
-				tf->lbah, tf->lbam, tf->lbal);
-#endif
-			task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB);
+
+			task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 		} else {
 			tf->nsect  = nsectors & 0xff;
 			tf->lbal   = block;
@@ -319,9 +314,9 @@
 	else
 		tf->command = WIN_READ_NATIVE_MAX;
 	tf->device  = ATA_LBA;
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	if (lba48)
-		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB);
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 	/* submit command request */
 	ide_no_data_taskfile(drive, &args);
 
@@ -358,9 +353,9 @@
 		tf->command  = WIN_SET_MAX;
 	}
 	tf->device |= ATA_LBA;
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	if (lba48)
-		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB);
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 	/* submit command request */
 	ide_no_data_taskfile(drive, &args);
 	/* if OK, compute maximum address value */
@@ -500,7 +495,7 @@
 	tf->lbam    = SMART_LCYL_PASS;
 	tf->lbah    = SMART_HCYL_PASS;
 	tf->command = WIN_SMART;
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	return ide_no_data_taskfile(drive, &args);
 }
 
@@ -515,7 +510,7 @@
 	tf->lbam    = SMART_LCYL_PASS;
 	tf->lbah    = SMART_HCYL_PASS;
 	tf->command = WIN_SMART;
-	args.tf_flags	= IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	args.data_phase	= TASKFILE_IN;
 	(void) smart_enable(drive);
 	return ide_raw_taskfile(drive, &args, buf, 1);
@@ -625,8 +620,10 @@
 
 	if (drive->special.b.set_multmode)
 		return -EBUSY;
+
 	ide_init_drive_cmd (&rq);
-	rq.cmd_type = REQ_TYPE_ATA_CMD;
+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
@@ -694,7 +691,7 @@
 		args.tf.feature = arg ?
 			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
 		args.tf.command = WIN_SETFEATURES;
-		args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+		args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 		err = ide_no_data_taskfile(drive, &args);
 		if (err == 0)
 			drive->wcache = arg;
@@ -714,7 +711,7 @@
 		args.tf.command = WIN_FLUSH_CACHE_EXT;
 	else
 		args.tf.command = WIN_FLUSH_CACHE;
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	return ide_no_data_taskfile(drive, &args);
 }
 
@@ -729,7 +726,7 @@
 	args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM;
 	args.tf.nsect   = arg;
 	args.tf.command = WIN_SETFEATURES;
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	ide_no_data_taskfile(drive, &args);
 	drive->acoustic = arg;
 	return 0;
@@ -766,7 +763,6 @@
 	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);
@@ -975,6 +971,17 @@
 #endif
 };
 
+static int idedisk_set_doorlock(ide_drive_t *drive, int on)
+{
+	ide_task_t task;
+
+	memset(&task, 0, sizeof(task));
+	task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+	return ide_no_data_taskfile(drive, &task);
+}
+
 static int idedisk_open(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -989,17 +996,13 @@
 	idkp->openers++;
 
 	if (drive->removable && idkp->openers == 1) {
-		ide_task_t args;
-		memset(&args, 0, sizeof(ide_task_t));
-		args.tf.command = WIN_DOORLOCK;
-		args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
 		check_disk_change(inode->i_bdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_no_data_taskfile(drive, &args))
+		if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -1015,11 +1018,7 @@
 		ide_cacheflush_p(drive);
 
 	if (drive->removable && idkp->openers == 1) {
-		ide_task_t args;
-		memset(&args, 0, sizeof(ide_task_t));
-		args.tf.command = WIN_DOORUNLOCK;
-		args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
-		if (drive->doorlocking && ide_no_data_taskfile(drive, &args))
+		if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
 			drive->doorlocking = 0;
 	}
 
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 18c78ad..5bf3203 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -153,13 +153,7 @@
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
 
-			if (rq->rq_disk) {
-				ide_driver_t *drv;
-
-				drv = *(ide_driver_t **)rq->rq_disk->private_data;
-				drv->end_request(drive, 1, rq->nr_sectors);
-			} else
-				ide_end_request(drive, 1, rq->nr_sectors);
+			task_end_request(drive, rq, stat);
 			return ide_stopped;
 		}
 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
@@ -408,23 +402,29 @@
 }
 
 /**
- *	ide_dma_host_off	-	Generic DMA kill
+ *	ide_dma_host_set	-	Enable/disable DMA on a host
  *	@drive: drive to control
  *
- *	Perform the generic IDE controller DMA off operation. This
- *	works for most IDE bus mastering controllers
+ *	Enable/disable DMA on an IDE controller following generic
+ *	bus-mastering IDE controller behaviour.
  */
 
-void ide_dma_host_off(ide_drive_t *drive)
+void ide_dma_host_set(ide_drive_t *drive, int on)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	if (on)
+		dma_stat |= (1 << (5 + unit));
+	else
+		dma_stat &= ~(1 << (5 + unit));
+
+	hwif->OUTB(dma_stat, hwif->dma_status);
 }
 
-EXPORT_SYMBOL(ide_dma_host_off);
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *	ide_dma_off_quietly	-	Generic DMA kill
@@ -438,11 +438,10 @@
 	drive->using_dma = 0;
 	ide_toggle_bounce(drive, 0);
 
-	drive->hwif->dma_host_off(drive);
+	drive->hwif->dma_host_set(drive, 0);
 }
 
 EXPORT_SYMBOL(ide_dma_off_quietly);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *	ide_dma_off	-	disable DMA on a device
@@ -455,52 +454,29 @@
 void ide_dma_off(ide_drive_t *drive)
 {
 	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	drive->hwif->dma_off_quietly(drive);
+	ide_dma_off_quietly(drive);
 }
 
 EXPORT_SYMBOL(ide_dma_off);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
- *	ide_dma_host_on	-	Enable DMA on a host
- *	@drive: drive to enable for DMA
- *
- *	Enable DMA on an IDE controller following generic bus mastering
- *	IDE controller behaviour
- */
-
-void ide_dma_host_on(ide_drive_t *drive)
-{
-	if (drive->using_dma) {
-		ide_hwif_t *hwif	= HWIF(drive);
-		u8 unit			= (drive->select.b.unit & 0x01);
-		u8 dma_stat		= hwif->INB(hwif->dma_status);
-
-		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
-	}
-}
-
-EXPORT_SYMBOL(ide_dma_host_on);
-
-/**
- *	__ide_dma_on		-	Enable DMA on a device
+ *	ide_dma_on		-	Enable DMA on a device
  *	@drive: drive to enable DMA on
  *
  *	Enable IDE DMA for a device on this IDE controller.
  */
- 
-int __ide_dma_on (ide_drive_t *drive)
+
+void ide_dma_on(ide_drive_t *drive)
 {
 	drive->using_dma = 1;
 	ide_toggle_bounce(drive, 1);
 
-	drive->hwif->dma_host_on(drive);
-
-	return 0;
+	drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(__ide_dma_on);
+EXPORT_SYMBOL(ide_dma_on);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *	ide_dma_setup	-	begin a DMA phase
  *	@drive: target device
@@ -755,6 +731,7 @@
 
 static int ide_tune_dma(ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = drive->hwif;
 	u8 speed;
 
 	if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
@@ -767,15 +744,21 @@
 	if (ide_id_dma_bug(drive))
 		return 0;
 
-	if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
 		return config_drive_for_dma(drive);
 
 	speed = ide_max_dma_mode(drive);
 
-	if (!speed)
-		return 0;
+	if (!speed) {
+		 /* is this really correct/needed? */
+		if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
+		    ide_dma_good_drive(drive))
+			return 1;
+		else
+			return 0;
+	}
 
-	if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+	if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
 		return 0;
 
 	if (ide_set_dma_mode(drive, speed))
@@ -820,7 +803,6 @@
 
 int ide_set_dma(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = drive->hwif;
 	int rc;
 
 	/*
@@ -829,13 +811,15 @@
 	 * things, if not checked and cleared.
 	 *   PARANOIA!!!
 	 */
-	hwif->dma_off_quietly(drive);
+	ide_dma_off_quietly(drive);
 
 	rc = ide_dma_check(drive);
 	if (rc)
 		return rc;
 
-	return hwif->ide_dma_on(drive);
+	ide_dma_on(drive);
+
+	return 0;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -972,14 +956,8 @@
 	if (!(hwif->dma_prdtable))
 		hwif->dma_prdtable	= (hwif->dma_base + 4);
 
-	if (!hwif->dma_off_quietly)
-		hwif->dma_off_quietly = &ide_dma_off_quietly;
-	if (!hwif->dma_host_off)
-		hwif->dma_host_off = &ide_dma_host_off;
-	if (!hwif->ide_dma_on)
-		hwif->ide_dma_on = &__ide_dma_on;
-	if (!hwif->dma_host_on)
-		hwif->dma_host_on = &ide_dma_host_on;
+	if (!hwif->dma_host_set)
+		hwif->dma_host_set = &ide_dma_host_set;
 	if (!hwif->dma_setup)
 		hwif->dma_setup = &ide_dma_setup;
 	if (!hwif->dma_exec_cmd)
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 0f72b98..bb30c29 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -14,10 +14,16 @@
 
 static int __init ide_generic_init(void)
 {
+	u8 idx[MAX_HWIFS];
+	int i;
+
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
 		ide_get_lock(NULL, NULL); /* for atari only */
 
-	(void)ideprobe_init();
+	for (i = 0; i < MAX_HWIFS; i++)
+		idx[i] = ide_hwifs[i].present ? 0xff : i;
+
+	ide_device_add_all(idx);
 
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
 		ide_release_lock();	/* for atari only */
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 2711b5a..6f8f544 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -75,7 +75,7 @@
 	 */
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		HWGROUP(drive)->hwif->ide_dma_on(drive);
+		ide_dma_on(drive);
 	}
 
 	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
@@ -219,7 +219,7 @@
 		 * we could be smarter and check for current xfer_speed
 		 * in struct drive etc...
 		 */
-		if (drive->hwif->ide_dma_on == NULL)
+		if (drive->hwif->dma_host_set == NULL)
 			break;
 		/*
 		 * TODO: respect ->using_dma setting
@@ -231,7 +231,7 @@
 	return ide_stopped;
 
 out_do_tf:
-	args->tf_flags	 = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args->tf_flags	 = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	args->data_phase = TASKFILE_NO_DATA;
 	return do_rw_taskfile(drive, args);
 }
@@ -354,7 +354,6 @@
  
 void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 {
-	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 
@@ -362,17 +361,7 @@
 	rq = HWGROUP(drive)->rq;
 	spin_unlock_irqrestore(&ide_lock, flags);
 
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-		u8 *args = (u8 *) rq->buffer;
-		if (rq->errors == 0)
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-		if (args) {
-			args[0] = stat;
-			args[1] = err;
-			args[2] = hwif->INB(IDE_NSECTOR_REG);
-		}
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
 		ide_task_t *args = (ide_task_t *) rq->special;
 		if (rq->errors == 0)
 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
@@ -383,10 +372,6 @@
 			tf->error = err;
 			tf->status = stat;
 
-			args->tf_flags |= (IDE_TFLAG_IN_TF|IDE_TFLAG_IN_DEVICE);
-			if (args->tf_flags & IDE_TFLAG_LBA48)
-				args->tf_flags |= IDE_TFLAG_IN_HOB;
-
 			ide_tf_read(drive, args);
 		}
 	} else if (blk_pm_request(rq)) {
@@ -626,42 +611,6 @@
 		return __ide_abort(drive, rq);
 }
 
-/**
- *	drive_cmd_intr		- 	drive command completion interrupt
- *	@drive: drive the completion interrupt occurred on
- *
- *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- *	We do any necessary data reading and then wait for the drive to
- *	go non busy. At that point we may read the error data and complete
- *	the request
- */
- 
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
-{
-	struct request *rq = HWGROUP(drive)->rq;
-	ide_hwif_t *hwif = HWIF(drive);
-	u8 *args = (u8 *) rq->buffer;
-	u8 stat = hwif->INB(IDE_STATUS_REG);
-	int retries = 10;
-
-	local_irq_enable_in_hardirq();
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
-	    (stat & DRQ_STAT) && args && args[3]) {
-		u8 io_32bit = drive->io_32bit;
-		drive->io_32bit = 0;
-		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
-		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "drive_cmd", stat);
-		/* calls ide_end_drive_cmd */
-	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
-	return ide_stopped;
-}
-
 static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
 	tf->nsect   = drive->sect;
@@ -710,7 +659,7 @@
 		return ide_stopped;
 	}
 
-	args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
 			IDE_TFLAG_CUSTOM_HANDLER;
 
 	do_rw_taskfile(drive, &args);
@@ -787,7 +736,7 @@
 
 			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
 				if (keep_dma)
-					hwif->ide_dma_on(drive);
+					ide_dma_on(drive);
 			}
 		}
 
@@ -847,16 +796,9 @@
 		struct request *rq)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	u8 *args = rq->buffer;
-	ide_task_t ltask;
-	struct ide_taskfile *tf = &ltask.tf;
+	ide_task_t *task = rq->special;
 
-	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-		ide_task_t *task = rq->special;
- 
-		if (task == NULL)
-			goto done;
-
+	if (task) {
 		hwif->data_phase = task->data_phase;
 
 		switch (hwif->data_phase) {
@@ -873,33 +815,6 @@
 		return do_rw_taskfile(drive, task);
 	}
 
-	if (args == NULL)
-		goto done;
-
-	memset(&ltask, 0, sizeof(ltask));
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-#ifdef DEBUG
-		printk("%s: DRIVE_CMD\n", drive->name);
-#endif
-		tf->feature = args[2];
-		if (args[0] == WIN_SMART) {
-			tf->nsect = args[3];
-			tf->lbal  = args[1];
-			tf->lbam  = 0x4f;
-			tf->lbah  = 0xc2;
-			ltask.tf_flags = IDE_TFLAG_OUT_TF;
-		} else {
-			tf->nsect = args[1];
-			ltask.tf_flags = IDE_TFLAG_OUT_FEATURE |
-					 IDE_TFLAG_OUT_NSECT;
-		}
- 	}
-	tf->command = args[0];
-	ide_tf_load(drive, &ltask);
-	ide_execute_command(drive, args[0], &drive_cmd_intr, WAIT_WORSTCASE, NULL);
-	return ide_started;
-
-done:
  	/*
  	 * NULL is actually a valid way of waiting for
  	 * all current requests to be flushed from the queue.
@@ -939,8 +854,7 @@
 		if (rc)
 			printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
 		SELECT_DRIVE(drive);
-		if (IDE_CONTROL_REG)
-			HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+		ide_set_irq(drive, 1);
 		rc = ide_wait_not_busy(HWIF(drive), 100000);
 		if (rc)
 			printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
@@ -1004,8 +918,7 @@
 		if (drive->current_speed == 0xff)
 			ide_config_drive_speed(drive, drive->desired_speed);
 
-		if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-		    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+		if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
 			return execute_drive_cmd(drive, rq);
 		else if (blk_pm_request(rq)) {
 			struct request_pm_state *pm = rq->data;
@@ -1213,15 +1126,13 @@
 		}
 	again:
 		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq &&
-		    hwif != hwgroup->hwif &&
-		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
 			/*
 			 * set nIEN for previous hwif, drives in the
 			 * quirk_list may not like intr setups/cleanups
 			 */
 			if (drive->quirk_list != 1)
-				hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+				ide_set_irq(drive, 0);
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
@@ -1334,7 +1245,7 @@
 	 */
 	drive->retry_pio++;
 	drive->state = DMA_PIO_RETRY;
-	hwif->dma_off_quietly(drive);
+	ide_dma_off_quietly(drive);
 
 	/*
 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1679,7 +1590,6 @@
 void ide_init_drive_cmd (struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
-	rq->cmd_type = REQ_TYPE_ATA_CMD;
 	rq->ref_count = 1;
 }
 
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index c97c071..e2a7e95 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -619,7 +619,7 @@
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
 	if (args->tf.command == WIN_SETFEATURES &&
-	    args->tf.lbal > XFER_UDMA_2 &&
+	    args->tf.nsect > XFER_UDMA_2 &&
 	    args->tf.feature == SETFEATURES_XFER) {
 		if (eighty_ninty_three(drive) == 0) {
 			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
@@ -639,7 +639,7 @@
 int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
 	if (args->tf.command == WIN_SETFEATURES &&
-	    args->tf.lbal >= XFER_SW_DMA_0 &&
+	    args->tf.nsect >= XFER_SW_DMA_0 &&
 	    args->tf.feature == SETFEATURES_XFER &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
@@ -688,8 +688,7 @@
 	 */
 
 	SELECT_MASK(drive, 1);
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_set_irq(drive, 1);
 	msleep(50);
 	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
@@ -742,8 +741,8 @@
 //		msleep(50);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->ide_dma_on)	/* check if host supports DMA */
-		hwif->dma_host_off(drive);
+	if (hwif->dma_host_set)	/* check if host supports DMA */
+		hwif->dma_host_set(drive, 0);
 #endif
 
 	/* Skip setting PIO flow-control modes on pre-EIDE drives */
@@ -772,13 +771,12 @@
 	SELECT_DRIVE(drive);
 	SELECT_MASK(drive, 0);
 	udelay(1);
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	ide_set_irq(drive, 0);
 	hwif->OUTB(speed, IDE_NSECTOR_REG);
 	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
 	hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (drive->quirk_list == 2)
+		ide_set_irq(drive, 1);
 
 	error = __ide_wait_stat(drive, drive->ready_stat,
 				BUSY_STAT|DRQ_STAT|ERR_STAT,
@@ -799,10 +797,11 @@
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0)
-		hwif->dma_host_on(drive);
-	else if (hwif->ide_dma_on)	/* check if host supports DMA */
-		hwif->dma_off_quietly(drive);
+	if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
+	    drive->using_dma)
+		hwif->dma_host_set(drive, 1);
+	else if (hwif->dma_host_set)	/* check if host supports DMA */
+		ide_dma_off_quietly(drive);
 #endif
 
 	switch(speed) {
@@ -1012,10 +1011,10 @@
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->crc_count) {
-		drive->hwif->dma_off_quietly(drive);
+		ide_dma_off_quietly(drive);
 		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
 		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->ide_dma_on(drive);
+			ide_dma_on(drive);
 	} else
 		ide_dma_off(drive);
 #endif
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index a3bd8e8..9b44fbd 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -454,8 +454,7 @@
 static void ide_dump_opcode(ide_drive_t *drive)
 {
 	struct request *rq;
-	u8 opcode = 0;
-	int found = 0;
+	ide_task_t *task = NULL;
 
 	spin_lock(&ide_lock);
 	rq = NULL;
@@ -464,25 +463,15 @@
 	spin_unlock(&ide_lock);
 	if (!rq)
 		return;
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-		char *args = rq->buffer;
-		if (args) {
-			opcode = args[0];
-			found = 1;
-		}
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-		ide_task_t *args = rq->special;
-		if (args) {
-			opcode = args->tf.command;
-			found = 1;
-		}
-	}
+
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+		task = rq->special;
 
 	printk("ide: failed opcode was: ");
-	if (!found)
-		printk("unknown\n");
+	if (task == NULL)
+		printk(KERN_CONT "unknown\n");
 	else
-		printk("0x%02x\n", opcode);
+		printk(KERN_CONT "0x%02x\n", task->tf.command);
 }
 
 u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index e245521..cbbb0f7 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -31,7 +31,6 @@
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index;
 
 	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
 		return -1;
@@ -41,11 +40,19 @@
 				pnp_port_start(dev, 1));
 	hw.irq = pnp_irq(dev, 0);
 
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
 
-	if (index != -1) {
-	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
+
+		printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
 		pnp_set_drvdata(dev,hwif);
+
+		ide_device_add(idx);
+
 		return 0;
 	}
 
@@ -68,12 +75,15 @@
 	.remove		= idepnp_remove,
 };
 
-void __init pnpide_init(void)
+static int __init pnpide_init(void)
 {
-	pnp_register_driver(&idepnp_driver);
+	return pnp_register_driver(&idepnp_driver);
 }
 
-void __exit pnpide_exit(void)
+static void __exit pnpide_exit(void)
 {
 	pnp_unregister_driver(&idepnp_driver);
 }
+
+module_init(pnpide_init);
+module_exit(pnpide_exit);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 0379d1f..edf650b 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -235,9 +235,6 @@
 	drive->media = ide_disk;
 	printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
 
-	if (hwif->quirkproc)
-		drive->quirk_list = hwif->quirkproc(drive);
-
 	return;
 
 err_misc:
@@ -353,22 +350,19 @@
 	 * the irq handler isn't expecting.
 	 */
 	if (IDE_CONTROL_REG) {
-		u8 ctl = drive->ctl | 2;
 		if (!hwif->irq) {
 			autoprobe = 1;
 			cookie = probe_irq_on();
-			/* enable device irq */
-			ctl &= ~2;
 		}
-		hwif->OUTB(ctl, IDE_CONTROL_REG);
+		ide_set_irq(drive, autoprobe);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		/* mask device irq */
-		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+
+		ide_set_irq(drive, 0);
 		/* clear drive IRQ */
 		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
@@ -388,6 +382,20 @@
 	return retval;
 }
 
+static int ide_busy_sleep(ide_hwif_t *hwif)
+{
+	unsigned long timeout = jiffies + WAIT_WORSTCASE;
+	u8 stat;
+
+	do {
+		msleep(50);
+		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		if ((stat & BUSY_STAT) == 0)
+			return 0;
+	} while (time_before(jiffies, timeout));
+
+	return 1;
+}
 
 /**
  *	do_probe		-	probe an IDE device
@@ -456,7 +464,6 @@
 		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
 			((drive->autotune == IDE_TUNE_DEFAULT) ||
 			(drive->autotune == IDE_TUNE_AUTO))) {
-			unsigned long timeout;
 			printk("%s: no response (status = 0x%02x), "
 				"resetting drive\n", drive->name,
 				hwif->INB(IDE_STATUS_REG));
@@ -464,10 +471,7 @@
 			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			msleep(50);
 			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
-			timeout = jiffies;
-			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
-			       time_before(jiffies, timeout + WAIT_WORSTCASE))
-				msleep(50);
+			(void)ide_busy_sleep(hwif);
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
@@ -495,20 +499,16 @@
 static void enable_nest (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long timeout;
 
 	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
 	SELECT_DRIVE(drive);
 	msleep(50);
 	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (time_after(jiffies, timeout)) {
-			printk("failed (timeout)\n");
-			return;
-		}
-		msleep(50);
-	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
+	if (ide_busy_sleep(hwif)) {
+		printk(KERN_CONT "failed (timeout)\n");
+		return;
+	}
 
 	msleep(50);
 
@@ -656,8 +656,7 @@
 		/* Ignore disks that we will not probe for later. */
 		if (!drive->noprobe || drive->present) {
 			SELECT_DRIVE(drive);
-			if (IDE_CONTROL_REG)
-				hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+			ide_set_irq(drive, 1);
 			mdelay(2);
 			rc = ide_wait_not_busy(hwif, 35000);
 			if (rc)
@@ -676,19 +675,18 @@
 
 /**
  *	ide_undecoded_slave	-	look for bad CF adapters
- *	@hwif: interface
+ *	@drive1: drive
  *
  *	Analyse the drives on the interface and attempt to decide if we
  *	have the same drive viewed twice. This occurs with crap CF adapters
  *	and PCMCIA sometimes.
  */
 
-void ide_undecoded_slave(ide_hwif_t *hwif)
+void ide_undecoded_slave(ide_drive_t *drive1)
 {
-	ide_drive_t *drive0 = &hwif->drives[0];
-	ide_drive_t *drive1 = &hwif->drives[1];
+	ide_drive_t *drive0 = &drive1->hwif->drives[0];
 
-	if (drive0->present == 0 || drive1->present == 0)
+	if ((drive1->dn & 1) == 0 || drive0->present == 0)
 		return;
 
 	/* If the models don't match they are not the same product */
@@ -791,18 +789,11 @@
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
-		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		u8 stat;
-
 		printk(KERN_WARNING "%s: reset\n", hwif->name);
 		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
 		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			msleep(50);
-			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
-
+		(void)ide_busy_sleep(hwif);
 	}
 	local_irq_restore(flags);
 	/*
@@ -817,8 +808,12 @@
 		return;
 	}
 
-	if (hwif->fixup)
-		hwif->fixup(hwif);
+	for (unit = 0; unit < MAX_DRIVES; unit++) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (drive->present && hwif->quirkproc)
+			hwif->quirkproc(drive);
+	}
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
@@ -833,7 +828,7 @@
 
 			drive->nice1 = 1;
 
-			if (hwif->ide_dma_on)
+			if (hwif->dma_host_set)
 				ide_set_dma(drive);
 		}
 	}
@@ -848,25 +843,6 @@
 	}
 }
 
-static int hwif_init(ide_hwif_t *hwif);
-static void hwif_register_devices(ide_hwif_t *hwif);
-
-static int probe_hwif_init(ide_hwif_t *hwif)
-{
-	probe_hwif(hwif);
-
-	if (!hwif_init(hwif)) {
-		printk(KERN_INFO "%s: failed to initialize IDE interface\n",
-				 hwif->name);
-		return -1;
-	}
-
-	if (hwif->present)
-		hwif_register_devices(hwif);
-
-	return 0;
-}
-
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -1359,54 +1335,63 @@
 	}
 }
 
-int ideprobe_init (void)
+int ide_device_add_all(u8 *idx)
 {
-	unsigned int index;
-	int probe[MAX_HWIFS];
+	ide_hwif_t *hwif;
+	int i, rc = 0;
 
-	memset(probe, 0, MAX_HWIFS * sizeof(int));
-	for (index = 0; index < MAX_HWIFS; ++index)
-		probe[index] = !ide_hwifs[index].present;
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
 
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			probe_hwif(&ide_hwifs[index]);
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			hwif_init(&ide_hwifs[index]);
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		if (probe[index]) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-			if (!hwif->present)
-				continue;
-			if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
+		probe_hwif(&ide_hwifs[idx[i]]);
+	}
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
+
+		hwif = &ide_hwifs[idx[i]];
+
+		if (hwif_init(hwif) == 0) {
+			printk(KERN_INFO "%s: failed to initialize IDE "
+					 "interface\n", hwif->name);
+			rc = -1;
+			continue;
+		}
+	}
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
+
+		hwif = &ide_hwifs[idx[i]];
+
+		if (hwif->present) {
+			if (hwif->chipset == ide_unknown ||
+			    hwif->chipset == ide_forced)
 				hwif->chipset = ide_generic;
 			hwif_register_devices(hwif);
 		}
 	}
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			ide_proc_register_port(&ide_hwifs[index]);
-	return 0;
-}
 
-EXPORT_SYMBOL_GPL(ideprobe_init);
-
-int ide_device_add(u8 idx[4])
-{
-	int i, rc = 0;
-
-	for (i = 0; i < 4; i++) {
-		if (idx[i] != 0xff)
-			rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
-	}
-
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < MAX_HWIFS; i++) {
 		if (idx[i] != 0xff)
 			ide_proc_register_port(&ide_hwifs[idx[i]]);
 	}
 
 	return rc;
 }
+EXPORT_SYMBOL_GPL(ide_device_add_all);
 
+int ide_device_add(u8 idx[4])
+{
+	u8 idx_all[MAX_HWIFS];
+	int i;
+
+	for (i = 0; i < MAX_HWIFS; i++)
+		idx_all[i] = (i < 4) ? idx[i] : 0xff;
+
+	return ide_device_add_all(idx_all);
+}
 EXPORT_SYMBOL_GPL(ide_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index a4007d3..aa663e7 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -346,14 +346,20 @@
 
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
+	ide_task_t task;
 	int err;
 
 	if (arg < 0 || arg > 70)
 		return -EINVAL;
 
-	err = ide_wait_cmd(drive,
-			WIN_SETFEATURES, (u8) arg,
-			SETFEATURES_XFER, 0, NULL);
+	memset(&task, 0, sizeof(task));
+	task.tf.command = WIN_SETFEATURES;
+	task.tf.feature = SETFEATURES_XFER;
+	task.tf.nsect   = (u8)arg;
+	task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+			IDE_TFLAG_IN_NSECT;
+
+	err = ide_no_data_taskfile(drive, &task);
 
 	if (!err && arg) {
 		ide_set_xfer_rate(drive, (u8) arg);
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
new file mode 100644
index 0000000..7ffa332
--- /dev/null
+++ b/drivers/ide/ide-scan-pci.c
@@ -0,0 +1,121 @@
+/*
+ * support for probing IDE PCI devices in the PCI bus order
+ *
+ * Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ * Copyright (c) 1995-1998  Mark Lord
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+/*
+ *	Module interfaces
+ */
+
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	__ide_pci_register_driver	-	attach IDE driver
+ *	@driver: pci driver
+ *	@module: owner module of the driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+			      const char *mod_name)
+{
+	if (!pre_init)
+		return __pci_register_driver(driver, module, mod_name);
+	driver->driver.owner = module;
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+
+	list_for_each(l, &ide_pci_drivers) {
+		d = list_entry(l, struct pci_driver, node);
+		if (d->id_table) {
+			const struct pci_device_id *id =
+				pci_match_id(d->id_table, dev);
+
+			if (id != NULL && d->probe(dev, id) >= 0) {
+				dev->driver = d;
+				pci_dev_get(dev);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+
+int __init ide_scan_pcibus(void)
+{
+	struct pci_dev *dev = NULL;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	pre_init = 0;
+	if (!ide_scan_direction)
+		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+			ide_scan_pcidev(dev);
+	else
+		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
+						     dev)))
+			ide_scan_pcidev(dev);
+
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers) {
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		if (__pci_register_driver(d, d->driver.owner,
+					  d->driver.mod_name))
+			printk(KERN_ERR "%s: failed to register %s driver\n",
+					__FUNCTION__, d->driver.mod_name);
+	}
+
+	return 0;
+}
+
+static int __init ide_scan_pci(void)
+{
+	return ide_scan_pcibus();
+}
+
+module_init(ide_scan_pci);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 3cbca3f..d71a584 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1690,6 +1690,11 @@
 	if (error)
 		tape->failed_pc = NULL;
 
+	if (!blk_special_request(rq)) {
+		ide_end_request(drive, uptodate, nr_sects);
+		return 0;
+	}
+
 	spin_lock_irqsave(&tape->spinlock, flags);
 
 	/* The request was a pipelined data transfer request */
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 2d63ea9..5eb6fa1 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -35,34 +35,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static void ata_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
-
-static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-	HWIF(drive)->ata_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		ata_bswap_data(buffer, wcount);
-}
-
-static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-	if (drive->bswap) {
-		ata_bswap_data(buffer, wcount);
-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
-		ata_bswap_data(buffer, wcount);
-	} else {
-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
-	}
-}
-
 void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
 {
 	ide_hwif_t *hwif = drive->hwif;
@@ -77,10 +49,13 @@
 		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
 		drive->name, tf->feature, tf->nsect, tf->lbal,
 		tf->lbam, tf->lbah, tf->device, tf->command);
+	printk("%s: hob: nsect 0x%02x lbal 0x%02x "
+		"lbam 0x%02x lbah 0x%02x\n",
+		drive->name, tf->hob_nsect, tf->hob_lbal,
+		tf->hob_lbam, tf->hob_lbah);
 #endif
 
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
+	ide_set_irq(drive, 1);
 
 	if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
 		SELECT_MASK(drive, 0);
@@ -124,7 +99,7 @@
 		args.tf.command = WIN_IDENTIFY;
 	else
 		args.tf.command = WIN_PIDENTIFY;
-	args.tf_flags	= IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 	args.data_phase	= TASKFILE_IN;
 	return ide_raw_taskfile(drive, &args, buf, 1);
 }
@@ -285,7 +260,7 @@
 	return ide_stopped;
 }
 
-static u8 wait_drive_not_busy(ide_drive_t *drive)
+u8 wait_drive_not_busy(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	int retries;
@@ -293,8 +268,7 @@
 
 	/*
 	 * Last sector was transfered, wait until drive is ready.
-	 * This can take up to 10 usec, but we will wait max 1 ms
-	 * (drive_cmd_intr() waits that long).
+	 * This can take up to 10 usec, but we will wait max 1 ms.
 	 */
 	for (retries = 0; retries < 100; retries++) {
 		if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
@@ -349,9 +323,9 @@
 
 	/* do the actual data transfer */
 	if (write)
-		taskfile_output_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_output_data(drive, buf, SECTOR_WORDS);
 	else
-		taskfile_input_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_input_data(drive, buf, SECTOR_WORDS);
 
 	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 #ifdef CONFIG_HIGHMEM
@@ -371,9 +345,18 @@
 static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 				     unsigned int write)
 {
+	u8 saved_io_32bit = drive->io_32bit;
+
 	if (rq->bio)	/* fs request */
 		rq->errors = 0;
 
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+		ide_task_t *task = rq->special;
+
+		if (task->tf_flags & IDE_TFLAG_IO_16BIT)
+			drive->io_32bit = 0;
+	}
+
 	touch_softlockup_watchdog();
 
 	switch (drive->hwif->data_phase) {
@@ -385,6 +368,8 @@
 		ide_pio_sector(drive, write);
 		break;
 	}
+
+	drive->io_32bit = saved_io_32bit;
 }
 
 static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
@@ -422,27 +407,22 @@
 	return ide_error(drive, s, stat);
 }
 
-static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
-	HWIF(drive)->cursg = NULL;
-
 	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-		ide_task_t *task = rq->special;
+		u8 err = drive->hwif->INB(IDE_ERROR_REG);
 
-		if (task->tf_flags & IDE_TFLAG_FLAGGED) {
-			u8 err = drive->hwif->INB(IDE_ERROR_REG);
-			ide_end_drive_cmd(drive, stat, err);
-			return;
-		}
+		ide_end_drive_cmd(drive, stat, err);
+		return;
 	}
 
 	if (rq->rq_disk) {
 		ide_driver_t *drv;
 
 		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
-		drv->end_request(drive, 1, rq->hard_nr_sectors);
+		drv->end_request(drive, 1, rq->nr_sectors);
 	} else
-		ide_end_request(drive, 1, rq->hard_nr_sectors);
+		ide_end_request(drive, 1, rq->nr_sectors);
 }
 
 /*
@@ -455,7 +435,7 @@
 	u8 stat = hwif->INB(IDE_STATUS_REG);
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+	if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
 		if (stat & (ERR_STAT | DRQ_STAT))
 			return task_error(drive, rq, __FUNCTION__, stat);
 		/* No data yet, so wait for another IRQ. */
@@ -468,7 +448,7 @@
 	/* If it was the last datablock check status and finish transfer. */
 	if (!hwif->nleft) {
 		stat = wait_drive_not_busy(drive);
-		if (!OK_STAT(stat, 0, BAD_R_STAT))
+		if (!OK_STAT(stat, 0, BAD_STAT))
 			return task_error(drive, rq, __FUNCTION__, stat);
 		task_end_request(drive, rq, stat);
 		return ide_stopped;
@@ -512,7 +492,7 @@
 {
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DATA_READY,
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
 			  drive->bad_wstat, WAIT_DRQ)) {
 		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
 				drive->name,
@@ -580,7 +560,6 @@
 	unsigned int taskin	= 0;
 	unsigned int taskout	= 0;
 	u16 nsect		= 0;
-	u8 io_32bit		= drive->io_32bit;
 	char __user *buf = (char __user *)arg;
 
 //	printk("IDE Taskfile ...\n");
@@ -633,9 +612,10 @@
 
 	args.data_phase = req_task->data_phase;
 
-	args.tf_flags = IDE_TFLAG_OUT_DEVICE;
+	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
+			IDE_TFLAG_IN_TF;
 	if (drive->addressing == 1)
-		args.tf_flags |= IDE_TFLAG_LBA48;
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
 
 	if (req_task->out_flags.all) {
 		args.tf_flags |= IDE_TFLAG_FLAGGED;
@@ -671,7 +651,6 @@
 	if (req_task->in_flags.b.data)
 		args.tf_flags |= IDE_TFLAG_IN_DATA;
 
-	drive->io_32bit = 0;
 	switch(req_task->data_phase) {
 		case TASKFILE_MULTI_OUT:
 			if (!drive->mult_count) {
@@ -767,41 +746,24 @@
 
 //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
 
-	drive->io_32bit = io_32bit;
-
 	return err;
 }
 #endif
 
-int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
-{
-	struct request rq;
-	u8 buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
-	int err = 0;
-	u8 args[4], *argbuf = args;
-	u8 xfer_rate = 0;
-	int argsize = 4;
+	u8 *buf = NULL;
+	int bufsize = 0, err = 0;
+	u8 args[4], xfer_rate = 0;
 	ide_task_t tfargs;
 	struct ide_taskfile *tf = &tfargs.tf;
 
 	if (NULL == (void *) arg) {
 		struct request rq;
+
 		ide_init_drive_cmd(&rq);
+		rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 		return ide_do_drive_cmd(drive, &rq, ide_wait);
 	}
 
@@ -810,23 +772,39 @@
 
 	memset(&tfargs, 0, sizeof(ide_task_t));
 	tf->feature = args[2];
-	tf->nsect   = args[3];
-	tf->lbal    = args[1];
+	if (args[0] == WIN_SMART) {
+		tf->nsect = args[3];
+		tf->lbal  = args[1];
+		tf->lbam  = 0x4f;
+		tf->lbah  = 0xc2;
+		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+	} else {
+		tf->nsect = args[1];
+		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+	}
 	tf->command = args[0];
+	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
 
 	if (args[3]) {
-		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-		argbuf = kzalloc(argsize, GFP_KERNEL);
-		if (argbuf == NULL)
+		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+		bufsize = SECTOR_WORDS * 4 * args[3];
+		buf = kzalloc(bufsize, GFP_KERNEL);
+		if (buf == NULL)
 			return -ENOMEM;
 	}
+
 	if (set_transfer(drive, &tfargs)) {
 		xfer_rate = args[1];
 		if (ide_ata66_check(drive, &tfargs))
 			goto abort;
 	}
 
-	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+	args[0] = tf->status;
+	args[1] = tf->error;
+	args[2] = tf->nsect;
 
 	if (!err && xfer_rate) {
 		/* active-retuning-calls future */
@@ -834,10 +812,13 @@
 		ide_driveid_update(drive);
 	}
 abort:
-	if (copy_to_user((void __user *)arg, argbuf, argsize))
+	if (copy_to_user((void __user *)arg, &args, 4))
 		err = -EFAULT;
-	if (argsize > 4)
-		kfree(argbuf);
+	if (buf) {
+		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+			err = -EFAULT;
+		kfree(buf);
+	}
 	return err;
 }
 
@@ -854,7 +835,7 @@
 	memset(&task, 0, sizeof(task));
 	memcpy(&task.tf_array[7], &args[1], 6);
 	task.tf.command = args[0];
-	task.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
 	err = ide_no_data_taskfile(drive, &task);
 
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index c6d4f63..97894ab 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -95,7 +95,7 @@
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
+int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
 int noautodma = 0;
@@ -116,7 +116,7 @@
 /*
  * Do not even *think* about calling this!
  */
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
 {
 	unsigned int unit;
 
@@ -159,6 +159,7 @@
 		init_completion(&drive->gendev_rel_comp);
 	}
 }
+EXPORT_SYMBOL_GPL(ide_init_port_data);
 
 static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
 {
@@ -177,8 +178,6 @@
 #endif
 }
 
-extern void ide_arm_init(void);
-
 /*
  * init_ide_data() sets reasonable default values into all fields
  * of all instances of the hwifs and drives, but only on the first call.
@@ -210,16 +209,13 @@
 	/* Initialise all interface structures */
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		hwif = &ide_hwifs[index];
-		init_hwif_data(hwif, index);
+		ide_init_port_data(hwif, index);
 		init_hwif_default(hwif, index);
 #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
 		hwif->irq =
 			ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
 #endif
 	}
-#ifdef CONFIG_IDE_ARM
-	ide_arm_init();
-#endif
 }
 
 /**
@@ -414,8 +410,6 @@
 	hwif->cds			= tmp_hwif->cds;
 #endif
 
-	hwif->fixup			= tmp_hwif->fixup;
-
 	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
 	hwif->set_dma_mode		= tmp_hwif->set_dma_mode;
 	hwif->mdma_filter		= tmp_hwif->mdma_filter;
@@ -433,16 +427,13 @@
 	hwif->atapi_input_bytes		= tmp_hwif->atapi_input_bytes;
 	hwif->atapi_output_bytes	= tmp_hwif->atapi_output_bytes;
 
+	hwif->dma_host_set		= tmp_hwif->dma_host_set;
 	hwif->dma_setup			= tmp_hwif->dma_setup;
 	hwif->dma_exec_cmd		= tmp_hwif->dma_exec_cmd;
 	hwif->dma_start			= tmp_hwif->dma_start;
 	hwif->ide_dma_end		= tmp_hwif->ide_dma_end;
-	hwif->ide_dma_on		= tmp_hwif->ide_dma_on;
-	hwif->dma_off_quietly		= tmp_hwif->dma_off_quietly;
 	hwif->ide_dma_test_irq		= tmp_hwif->ide_dma_test_irq;
 	hwif->ide_dma_clear_irq		= tmp_hwif->ide_dma_clear_irq;
-	hwif->dma_host_on		= tmp_hwif->dma_host_on;
-	hwif->dma_host_off		= tmp_hwif->dma_host_off;
 	hwif->dma_lost_irq		= tmp_hwif->dma_lost_irq;
 	hwif->dma_timeout		= tmp_hwif->dma_timeout;
 
@@ -614,7 +605,7 @@
 	tmp_hwif = *hwif;
 
 	/* restore hwif data to pristine status */
-	init_hwif_data(hwif, index);
+	ide_init_port_data(hwif, index);
 	init_hwif_default(hwif, index);
 
 	ide_hwif_restore(hwif, &tmp_hwif);
@@ -680,24 +671,34 @@
  */
 }
 
+void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+{
+	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+	hwif->irq = hw->irq;
+	hwif->noprobe = 0;
+	hwif->chipset = hw->chipset;
+	hwif->gendev.parent = hw->dev;
+	hwif->ack_intr = hw->ack_intr;
+}
+EXPORT_SYMBOL_GPL(ide_init_port_hw);
+
 /**
  *	ide_register_hw		-	register IDE interface
  *	@hw: hardware registers
- *	@fixup: fixup function
- *	@initializing: set while initializing built-in drivers
+ *	@quirkproc: quirkproc function
  *	@hwifp: pointer to returned hwif
  *
  *	Register an IDE interface, specifying exactly the registers etc.
- *	Set init=1 iff calling before probes have taken place.
  *
  *	Returns -1 on error.
  */
 
-int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
-		    int initializing, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
+		    ide_hwif_t **hwifp)
 {
 	int index, retry = 1;
 	ide_hwif_t *hwif;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	do {
 		for (index = 0; index < MAX_HWIFS; ++index) {
@@ -709,8 +710,7 @@
 			hwif = &ide_hwifs[index];
 			if (hwif->hold)
 				continue;
-			if ((!hwif->present && !hwif->mate && !initializing) ||
-			    (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
+			if (!hwif->present && hwif->mate == NULL)
 				goto found;
 		}
 		for (index = 0; index < MAX_HWIFS; index++)
@@ -721,29 +721,23 @@
 	if (hwif->present)
 		ide_unregister(index);
 	else if (!hwif->hold) {
-		init_hwif_data(hwif, index);
+		ide_init_port_data(hwif, index);
 		init_hwif_default(hwif, index);
 	}
 	if (hwif->present)
 		return -1;
-	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
-	hwif->irq = hw->irq;
-	hwif->noprobe = 0;
-	hwif->fixup = fixup;
-	hwif->chipset = hw->chipset;
-	hwif->gendev.parent = hw->dev;
-	hwif->ack_intr = hw->ack_intr;
 
-	if (initializing == 0) {
-		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+	ide_init_port_hw(hwif, hw);
+	hwif->quirkproc = quirkproc;
 
-		ide_device_add(idx);
-	}
+	idx[0] = index;
+
+	ide_device_add(idx);
 
 	if (hwifp)
 		*hwifp = hwif;
 
-	return (initializing || hwif->present) ? index : -1;
+	return hwif->present ? index : -1;
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -836,7 +830,7 @@
 	if (!drive->id || !(drive->id->capability & 1))
 		goto out;
 
-	if (hwif->ide_dma_on == NULL)
+	if (hwif->dma_host_set == NULL)
 		goto out;
 
 	err = -EBUSY;
@@ -884,7 +878,10 @@
 
 	if (drive->special.b.set_tune)
 		return -EBUSY;
+
 	ide_init_drive_cmd(&rq);
+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
 	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
@@ -1066,7 +1063,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, 0, NULL) == -1)
+			if (ide_register_hw(&hw, NULL, NULL) == -1)
 				return -EIO;
 			return 0;
 		}
@@ -1227,26 +1224,12 @@
 	return 0;	/* zero = nothing matched */
 }
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
 extern int probe_ali14xx;
-extern int ali14xx_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
 extern int probe_umc8672;
-extern int umc8672_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
 extern int probe_dtc2278;
-extern int dtc2278_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
 extern int probe_ht6560b;
-extern int ht6560b_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
 extern int probe_qd65xx;
-extern int qd65xx_init(void);
-#endif
+extern int cmd640_vlb;
 
 static int __initdata is_chipset_set[MAX_HWIFS];
 
@@ -1323,7 +1306,7 @@
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
 		const char *hd_words[] = {
 			"none", "noprobe", "nowerr", "cdrom", "nodma",
-			"autotune", "noautotune", "minus8", "swapdata", "bswap",
+			"autotune", "noautotune", "-8", "-9", "-10",
 			"noflush", "remap", "remap63", "scsi", NULL };
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
@@ -1359,10 +1342,6 @@
 			case -7: /* "noautotune" */
 				drive->autotune = IDE_TUNE_NOAUTO;
 				goto obsolete_option;
-			case -9: /* "swapdata" */
-			case -10: /* "bswap" */
-				drive->bswap = 1;
-				goto done;
 			case -11: /* noflush */
 				drive->noflush = 1;
 				goto done;
@@ -1462,11 +1441,8 @@
 #endif
 #ifdef CONFIG_BLK_DEV_CMD640
 			case -14: /* "cmd640_vlb" */
-			{
-				extern int cmd640_vlb; /* flag for cmd640.c */
 				cmd640_vlb = 1;
 				goto done;
-			}
 #endif
 #ifdef CONFIG_BLK_DEV_HT6560B
 			case -13: /* "ht6560b" */
@@ -1556,79 +1532,6 @@
 	return 1;
 }
 
-extern void __init pnpide_init(void);
-extern void __exit pnpide_exit(void);
-extern void __init h8300_ide_init(void);
-
-/*
- * probe_for_hwifs() finds/initializes "known" IDE interfaces
- */
-static void __init probe_for_hwifs (void)
-{
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-	ide_scan_pcibus(ide_scan_direction);
-#endif
-
-#ifdef CONFIG_ETRAX_IDE
-	{
-		extern void init_e100_ide(void);
-		init_e100_ide();
-	}
-#endif /* CONFIG_ETRAX_IDE */
-#ifdef CONFIG_BLK_DEV_CMD640
-	{
-		extern void ide_probe_for_cmd640x(void);
-		ide_probe_for_cmd640x();
-	}
-#endif /* CONFIG_BLK_DEV_CMD640 */
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	{
-		extern int pmac_ide_probe(void);
-		(void)pmac_ide_probe();
-	}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_GAYLE
-	{
-		extern void gayle_init(void);
-		gayle_init();
-	}
-#endif /* CONFIG_BLK_DEV_GAYLE */
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-	{
-		extern void falconide_init(void);
-		falconide_init();
-	}
-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	{
-		extern void macide_init(void);
-		macide_init();
-	}
-#endif /* CONFIG_BLK_DEV_MAC_IDE */
-#ifdef CONFIG_BLK_DEV_Q40IDE
-	{
-		extern void q40ide_init(void);
-		q40ide_init();
-	}
-#endif /* CONFIG_BLK_DEV_Q40IDE */
-#ifdef CONFIG_BLK_DEV_BUDDHA
-	{
-		extern void buddha_init(void);
-		buddha_init();
-	}
-#endif /* CONFIG_BLK_DEV_BUDDHA */
-#ifdef CONFIG_BLK_DEV_IDEPNP
-	pnpide_init();
-#endif
-#ifdef CONFIG_H8300
-	h8300_ide_init();
-#endif
-}
-
-/*
- * Probe module
- */
-
 EXPORT_SYMBOL(ide_lock);
 
 static int ide_bus_match(struct device *dev, struct device_driver *drv)
@@ -1775,30 +1678,6 @@
 
 	proc_ide_create();
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
-	if (probe_ali14xx)
-		(void)ali14xx_init();
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
-	if (probe_umc8672)
-		(void)umc8672_init();
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
-	if (probe_dtc2278)
-		(void)dtc2278_init();
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
-	if (probe_ht6560b)
-		(void)ht6560b_init();
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
-	if (probe_qd65xx)
-		(void)qd65xx_init();
-#endif
-
-	/* Probe for special PCI and other "known" interface chipsets. */
-	probe_for_hwifs();
-
 	return 0;
 }
 
@@ -1834,10 +1713,6 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		ide_unregister(index);
 
-#ifdef CONFIG_BLK_DEV_IDEPNP
-	pnpide_exit();
-#endif
-
 	proc_ide_destroy();
 
 	bus_unregister(&ide_bus_type);
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
index 4098223..7043ec7 100644
--- a/drivers/ide/legacy/Makefile
+++ b/drivers/ide/legacy/Makefile
@@ -1,15 +1,24 @@
 
+# link order is important here
+
 obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
 obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
 obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
 obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
 
-obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
 
-obj-$(CONFIG_BLK_DEV_PLATFORM)		+= ide_platform.o
+ifeq ($(CONFIG_BLK_DEV_IDECS), m)
+	obj-m += ide-cs.o
+endif
 
-# Last of all
-obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
+	obj-m += ide_platform.o
+endif
 
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 38c3a6d..5ec0be4 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -231,8 +231,7 @@
 module_param_named(probe, probe_ali14xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init ali14xx_init(void)
+static int __init ali14xx_init(void)
 {
 	if (probe_ali14xx == 0)
 		goto out;
@@ -248,9 +247,7 @@
 	return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ali14xx_init);
-#endif
 
 MODULE_AUTHOR("see local file");
 MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 4a0be25..74d28e0 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -112,6 +112,7 @@
     BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
 } BuddhaType;
 
+static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
 
     /*
      *  Check and acknowledge the interrupt status
@@ -143,11 +144,11 @@
      *  Probe for a Buddha or Catweasel IDE interface
      */
 
-void __init buddha_init(void)
+static int __init buddha_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int i, index;
+	int i;
 
 	struct zorro_dev *z = NULL;
 	u_long buddha_board = 0;
@@ -156,6 +157,8 @@
 
 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
 		unsigned long board;
+		u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
 		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
 			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
 			type=BOARD_BUDDHA;
@@ -195,7 +198,10 @@
 		/* X-Surf doesn't have this.  IRQs are always on */
 		if (type != BOARD_XSURF)
 			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
+
+		printk(KERN_INFO "ide: %s IDE controller\n",
+				 buddha_board_name[type]);
+
 		for(i=0;i<buddha_num_hwifs;i++) {
 			if(type != BOARD_XSURF) {
 				ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
@@ -213,23 +219,23 @@
 						IRQ_AMIGA_PORTS);
 			}	
 
-			index = ide_register_hw(&hw, NULL, 1, &hwif);
-			if (index != -1) {
+			hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+			if (hwif) {
+				u8 index = hwif->index;
+
+				ide_init_port_data(hwif, index);
+				ide_init_port_hw(hwif, &hw);
+
 				hwif->mmio = 1;
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
+
+				idx[i] = index;
+			}
 		}
+
+		ide_device_add(idx);
 	}
+
+	return 0;
 }
+
+module_init(buddha_init);
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 24a845d..13eee6d 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -150,8 +150,7 @@
 module_param_named(probe, probe_dtc2278, bool, 0);
 MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init dtc2278_init(void)
+static int __init dtc2278_init(void)
 {
 	if (probe_dtc2278 == 0)
 		return -ENODEV;
@@ -163,9 +162,7 @@
 	return 0;
 }
 
-#ifdef MODULE
 module_init(dtc2278_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 7d7936f..2860956 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -62,19 +62,31 @@
      *  Probe for a Falcon IDE interface
      */
 
-void __init falconide_init(void)
+static int __init falconide_init(void)
 {
     if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
 	hw_regs_t hw;
-	int index;
+
+	printk(KERN_INFO "ide: Falcon IDE controller\n");
 
 	ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
 			0, 0, NULL,
 //			falconide_iops,
 			IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL, 1, NULL);
 
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
+
+		ide_device_add(idx);
+	}
     }
+
+    return 0;
 }
+
+module_init(falconide_init);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 53331ee..492fa04 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -110,12 +110,13 @@
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-void __init gayle_init(void)
+static int __init gayle_init(void)
 {
     int a4000, i;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_AMIGA)
-	return;
+	return -ENODEV;
 
     if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
 	goto found;
@@ -125,15 +126,21 @@
 			  NULL))
 	goto found;
 #endif
-    return;
+    return -ENODEV;
 
 found:
+	printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
+			 a4000 ? 4000 : 1200,
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+			 ide_doubler ? ", IDE doubler" :
+#endif
+			 "");
+
     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
 	unsigned long base, ctrlport, irqport;
 	ide_ack_intr_t *ack_intr;
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index;
 	unsigned long phys_base, res_start, res_n;
 
 	if (a4000) {
@@ -165,21 +172,23 @@
 //			&gayle_iops,
 			IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
-	if (index != -1) {
+	hwif = ide_find_port(base);
+	if (hwif) {
+	    u8 index = hwif->index;
+
+	    ide_init_port_data(hwif, index);
+	    ide_init_port_hw(hwif, &hw);
+
 	    hwif->mmio = 1;
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
+
+	    idx[i] = index;
 	} else
 	    release_mem_region(res_start, res_n);
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
+
+module_init(gayle_init);
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index a4245d1..8da5031 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -307,8 +307,7 @@
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
-/* Can be called directly from ide.c. */
-int __init ht6560b_init(void)
+static int __init ht6560b_init(void)
 {
 	ide_hwif_t *hwif, *mate;
 	static u8 idx[4] = { 0, 1, 0xff, 0xff };
@@ -369,9 +368,7 @@
 	return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ht6560b_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 03715c0..f4ea15b 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(&hw, &ide_undecoded_slave, 0, NULL);
+    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
 }
 
 /*======================================================================
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
index 7bb79f5..69a0fb0 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/legacy/ide_platform.c
@@ -28,39 +28,27 @@
 	int index;
 } hwif_prop;
 
-static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
-	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
-	    int mmio)
+static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+					   void __iomem *base,
+					   void __iomem *ctrl,
+					   struct pata_platform_info *pdata,
+					   int irq)
 {
 	unsigned long port = (unsigned long)base;
-	ide_hwif_t *hwif = ide_find_port(port);
 	int i;
 
-	if (hwif == NULL)
-		goto out;
-
-	hwif->io_ports[IDE_DATA_OFFSET] = port;
+	hw->io_ports[IDE_DATA_OFFSET] = port;
 
 	port += (1 << pdata->ioport_shift);
 	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
 	     i++, port += (1 << pdata->ioport_shift))
-		hwif->io_ports[i] = port;
+		hw->io_ports[i] = port;
 
-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
 
-	hwif->irq = irq;
+	hw->irq = irq;
 
-	hwif->chipset = ide_generic;
-
-	if (mmio) {
-		hwif->mmio = 1;
-		default_hwif_mmiops(hwif);
-	}
-
-	hwif_prop.hwif = hwif;
-	hwif_prop.index = hwif->index;
-out:
-	return hwif;
+	hw->chipset = ide_generic;
 }
 
 static int __devinit plat_ide_probe(struct platform_device *pdev)
@@ -71,6 +59,7 @@
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 	int ret = 0;
 	int mmio = 0;
+	hw_regs_t hw;
 
 	pdata = pdev->dev.platform_data;
 
@@ -106,15 +95,27 @@
 			res_alt->start, res_alt->end - res_alt->start + 1);
 	}
 
-	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
-	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
-
+	hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
 	if (!hwif) {
 		ret = -ENODEV;
 		goto out;
 	}
-	hwif->gendev.parent = &pdev->dev;
-	hwif->noprobe = 0;
+
+	memset(&hw, 0, sizeof(hw));
+	plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
+			     hwif_prop.plat_ide_alt_mapbase,
+			     pdata, res_irq->start);
+	hw.dev = &pdev->dev;
+
+	ide_init_port_hw(hwif, &hw);
+
+	if (mmio) {
+		hwif->mmio = 1;
+		default_hwif_mmiops(hwif);
+	}
+
+	hwif_prop.hwif = hwif;
+	hwif_prop.index = hwif->index;
 
 	idx[0] = hwif->index;
 
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 5c6aa77..782d4c7 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -77,15 +77,17 @@
 	return 0;
 }
 
+static const char *mac_ide_name[] =
+	{ "Quadra", "Powerbook", "Powerbook Baboon" };
+
 /*
  * Probe for a Macintosh IDE interface
  */
 
-void __init macide_init(void)
+static int __init macide_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index = -1;
 
 	switch (macintosh_config->ide_type) {
 	case MAC_IDE_QUADRA:
@@ -93,48 +95,50 @@
 				0, 0, macide_ack_intr,
 //				quadra_ide_iops,
 				IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL, 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, NULL, 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, NULL, 1, &hwif);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
+		break;
+	default:
+		return -ENODEV;
+	}
 
+	printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
+			 mac_ide_name[macintosh_config->ide_type - 1]);
+
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
+
+		if (macintosh_config->ide_type == MAC_IDE_BABOON &&
+		    macintosh_config->ident == MAC_MODEL_PB190) {
 			/* Fix breakage in ide-disk.c: drive capacity	*/
 			/* is not initialized for drives without a 	*/
 			/* hardware ID, and we can't get that without	*/
 			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+			ide_drive_t *drive = &hwif->drives[0];
 			drive->capacity64 = drive->cyl*drive->head*drive->sect;
-
 		}
-		break;
 
-	default:
-	    return;
-	}
-
-        if (index != -1) {
 		hwif->mmio = 1;
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+
+		ide_device_add(idx);
 	}
+
+	return 0;
 }
+
+module_init(macide_init);
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 6ea46a6..f532973 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -111,15 +111,17 @@
  *  Probe for Q40 IDE interfaces
  */
 
-void __init q40ide_init(void)
+static int __init q40ide_init(void)
 {
     int i;
     ide_hwif_t *hwif;
-    int index;
     const char *name;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_Q40)
-      return ;
+      return -ENODEV;
+
+    printk(KERN_INFO "ide: Q40 IDE controller\n");
 
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
@@ -141,10 +143,20 @@
 			0, NULL,
 //			m68kide_iops,
 			q40ide_default_irq(pcide_bases[i]));
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
-	// **FIXME**
-	if (index != -1)
+
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		ide_init_port_data(hwif, hwif->index);
+		ide_init_port_hw(hwif, &hw);
 		hwif->mmio = 1;
+
+		idx[i] = hwif->index;
+	}
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
 
+module_init(q40ide_init);
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 912e738..2bac4c1 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -478,8 +478,7 @@
 module_param_named(probe, probe_qd65xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init qd65xx_init(void)
+static int __init qd65xx_init(void)
 {
 	if (probe_qd65xx == 0)
 		return -ENODEV;
@@ -492,9 +491,7 @@
 	return 0;
 }
 
-#ifdef MODULE
 module_init(qd65xx_init);
-#endif
 
 MODULE_AUTHOR("Samuel Thibault");
 MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index 79577b9..a1ae1ae 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -169,8 +169,7 @@
 module_param_named(probe, probe_umc8672, bool, 0);
 MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
 
-/* Can be called directly from ide.c. */
-int __init umc8672_init(void)
+static int __init umc8672_init(void)
 {
 	if (probe_umc8672 == 0)
 		goto out;
@@ -181,9 +180,7 @@
 	return -ENODEV;;
 }
 
-#ifdef MODULE
 module_init(umc8672_init);
-#endif
 
 MODULE_AUTHOR("Wolfram Podien");
 MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index a4d0d4c..2d3e511 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -395,26 +395,10 @@
 	return 0;
 }
 
-static void auide_dma_host_on(ide_drive_t *drive)
+static void auide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static int auide_dma_on(ide_drive_t *drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
-static void auide_dma_host_off(ide_drive_t *drive)
-{
-}
-
-static void auide_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-}
-
 static void auide_dma_lost_irq(ide_drive_t *drive)
 {
 	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
@@ -641,12 +625,13 @@
 	/* FIXME:  This might possibly break PCMCIA IDE devices */
 
 	hwif                            = &ide_hwifs[pdev->id];
-	hwif->irq			= ahwif->irq;
-	hwif->chipset                   = ide_au1xxx;
 
 	memset(&hw, 0, sizeof(hw));
 	auide_setup_ports(&hw, ahwif);
-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+	hw.irq = ahwif->irq;
+	hw.chipset = ide_au1xxx;
+
+	ide_init_port_hw(hwif, &hw);
 
 	hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -660,7 +645,6 @@
 	hwif->pio_mask = ATA_PIO4;
 	hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
 
-	hwif->noprobe = 0;
 	hwif->drives[0].unmask          = 1;
 	hwif->drives[1].unmask          = 1;
 
@@ -682,29 +666,25 @@
 	hwif->set_dma_mode		= &auide_set_dma_mode;
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-	hwif->dma_off_quietly		= &auide_dma_off_quietly;
 	hwif->dma_timeout		= &auide_dma_timeout;
 
 	hwif->mdma_filter		= &auide_mdma_filter;
 
+	hwif->dma_host_set		= &auide_dma_host_set;
 	hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
 	hwif->dma_start                 = &auide_dma_start;
 	hwif->ide_dma_end               = &auide_dma_end;
 	hwif->dma_setup                 = &auide_dma_setup;
 	hwif->ide_dma_test_irq          = &auide_dma_test_irq;
-	hwif->dma_host_off		= &auide_dma_host_off;
-	hwif->dma_host_on		= &auide_dma_host_on;
 	hwif->dma_lost_irq		= &auide_dma_lost_irq;
-	hwif->ide_dma_on                = &auide_dma_on;
-#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
+#endif
 	hwif->channel                   = 0;
-	hwif->hold                      = 1;
 	hwif->select_data               = 0;    /* no chipset-specific code */
 	hwif->config_data               = 0;    /* no chipset-specific code */
 
 	hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
 	hwif->drives[1].autotune	= 1;
-#endif
+
 	hwif->drives[0].no_io_32bit	= 1;
 	hwif->drives[1].no_io_32bit	= 1;
 
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 521edd4..8b3959d 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -117,6 +117,7 @@
 	default_hwif_mmiops(hwif);
 	/* Prevent resource map manipulation.  */
 	hwif->mmio = 1;
+	hwif->chipset = ide_generic;
 	hwif->noprobe = 0;
 
 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 95d1ea8..9480325 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -36,4 +36,8 @@
 # Must appear at the end of the block
 obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
 
+ifeq ($(CONFIG_BLK_DEV_CMD640), m)
+	obj-m += cmd640.o
+endif
+
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 5ae2656..4918719 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c	Version 0.03	Aug 3 2007
+ *  linux/drivers/ide/pci/atiixp.c	Version 0.05	Nov 9 2007
  *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
@@ -43,47 +43,8 @@
 	{ 0x02, 0x00 },
 };
 
-static int save_mdma_mode[4];
-
 static DEFINE_SPINLOCK(atiixp_lock);
 
-static void atiixp_dma_host_on(ide_drive_t *drive)
-{
-	struct pci_dev *dev = drive->hwif->pci_dev;
-	unsigned long flags;
-	u16 tmp16;
-
-	spin_lock_irqsave(&atiixp_lock, flags);
-
-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-	if (save_mdma_mode[drive->dn])
-		tmp16 &= ~(1 << drive->dn);
-	else
-		tmp16 |= (1 << drive->dn);
-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-	spin_unlock_irqrestore(&atiixp_lock, flags);
-
-	ide_dma_host_on(drive);
-}
-
-static void atiixp_dma_host_off(ide_drive_t *drive)
-{
-	struct pci_dev *dev = drive->hwif->pci_dev;
-	unsigned long flags;
-	u16 tmp16;
-
-	spin_lock_irqsave(&atiixp_lock, flags);
-
-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-	tmp16 &= ~(1 << drive->dn);
-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-	spin_unlock_irqrestore(&atiixp_lock, flags);
-
-	ide_dma_host_off(drive);
-}
-
 /**
  *	atiixp_set_pio_mode	-	set host controller for PIO mode
  *	@drive: drive
@@ -132,26 +93,33 @@
 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
 	u32 tmp32;
 	u16 tmp16;
+	u16 udma_ctl = 0;
 
 	spin_lock_irqsave(&atiixp_lock, flags);
 
-	save_mdma_mode[drive->dn] = 0;
+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
+
 	if (speed >= XFER_UDMA_0) {
 		pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
 		tmp16 &= ~(0x07 << (drive->dn * 4));
 		tmp16 |= ((speed & 0x07) << (drive->dn * 4));
 		pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
-	} else {
-		if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
-			save_mdma_mode[drive->dn] = speed;
-			pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
-			tmp32 &= ~(0xff << timing_shift);
-			tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
-				(mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
-			pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
-		}
+
+		udma_ctl |= (1 << drive->dn);
+	} else if (speed >= XFER_MW_DMA_0) {
+		u8 i = speed & 0x03;
+
+		pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+		tmp32 &= ~(0xff << timing_shift);
+		tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
+			 (mdma_timing[i].command_width << (timing_shift + 4));
+		pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+
+		udma_ctl &= ~(1 << drive->dn);
 	}
 
+	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
+
 	spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
@@ -181,9 +149,6 @@
 		hwif->cbl = ATA_CBL_PATA80;
 	else
 		hwif->cbl = ATA_CBL_PATA40;
-
-	hwif->dma_host_on = &atiixp_dma_host_on;
-	hwif->dma_host_off = &atiixp_dma_host_off;
 }
 
 static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 4aa4810..da3565e 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -706,9 +706,9 @@
 }
 
 /*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ * Probe for a cmd640 chipset, and initialize it if found.
  */
-int __init ide_probe_for_cmd640x (void)
+static int __init cmd640x_init(void)
 {
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	int second_port_toggled = 0;
@@ -717,6 +717,7 @@
 	const char *bus_type, *port2;
 	unsigned int index;
 	u8 b, cfr;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
 		bus_type = "VLB";
@@ -769,6 +770,8 @@
 	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
+	idx[0] = cmd_hwif0->index;
+
 	/*
 	 * Ensure compatibility by always using the slowest timings
 	 * for access to the drive's command register block,
@@ -826,6 +829,8 @@
 		cmd_hwif1->pio_mask = ATA_PIO5;
 		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+		idx[1] = cmd_hwif1->index;
 	}
 	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
 		cmd_hwif0->serialized ? "" : "not ", port2);
@@ -872,6 +877,13 @@
 #ifdef CMD640_DUMP_REGS
 	cmd640_dump_regs();
 #endif
+
+	ide_device_add(idx);
+
 	return 1;
 }
 
+module_param_named(probe_vlb, cmd640_vlb, bool, 0);
+MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
+
+module_init(cmd640x_init);
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 0b1e947..cd4eb9d 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cmd64x.c		Version 1.52	Dec 24, 2007
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Due to massive hardware bugs, UltraDMA is only supported
@@ -22,8 +22,6 @@
 
 #include <asm/io.h>
 
-#define DISPLAY_CMD64X_TIMINGS
-
 #define CMD_DEBUG 0
 
 #if CMD_DEBUG
@@ -37,11 +35,6 @@
  */
 #define CFR		0x50
 #define   CFR_INTR_CH0		0x04
-#define CNTRL		0x51
-#define   CNTRL_ENA_1ST 	0x04
-#define   CNTRL_ENA_2ND 	0x08
-#define   CNTRL_DIS_RA0 	0x40
-#define   CNTRL_DIS_RA1 	0x80
 
 #define	CMDTIM		0x52
 #define	ARTTIM0		0x53
@@ -60,108 +53,13 @@
 #define MRDMODE		0x71
 #define   MRDMODE_INTR_CH0	0x04
 #define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
 #define UDIDETCR0	0x73
 #define DTPR0		0x74
 #define BMIDECR1	0x78
 #define BMIDECSR	0x79
-#define BMIDESR1	0x7A
 #define UDIDETCR1	0x7B
 #define DTPR1		0x7C
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 cmd64x_proc = 0;
-
-#define CMD_MAX_DEVS		5
-
-static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
-static int n_cmd_devs;
-
-static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
-{
-	char *p = buf;
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;	/* extra */
-
-	p += sprintf(p, "\nController: %d\n", index);
-	p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
-
-	(void) pci_read_config_byte(dev, CFR,       &reg50);
-	(void) pci_read_config_byte(dev, CNTRL,     &reg51);
-	(void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
-	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
-	/* PCI0643/6 originally didn't have the primary channel enable bit */
-	if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
-	    (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
-		reg51 |= CNTRL_ENA_1ST;
-
-	p += sprintf(p, "---------------- Primary Channel "
-			"---------------- Secondary Channel ------------\n");
-	p += sprintf(p, "                 %s                         %s\n",
-		 (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
-		 (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
-	p += sprintf(p, "---------------- drive0 --------- drive1 "
-			"-------- drive0 --------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:     %s              %s"
-			"             %s              %s\n",
-		(reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
-		(reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
-	p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
-		( reg73 & 0x01) ? " on" : "off",
-		((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
-		((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
-		((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
-		((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
-		( reg73 & 0x02) ? " on" : "off",
-		((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
-		((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
-		((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
-		((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
-	p += sprintf(p, "         %s (%c)          %s (%c)\n",
-		( reg7b & 0x01) ? " on" : "off",
-		((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
-		((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
-		((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
-		((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
-		( reg7b & 0x02) ? " on" : "off",
-		((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
-		((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
-		((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
-		((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
-	p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
-		(reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
-		(reg50 & CFR_INTR_CH0	  ) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
-		(reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
-
-	return (char *)p;
-}
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	for (i = 0; i < n_cmd_devs; i++) {
-		struct pci_dev *dev	= cmd_devs[i];
-		p = print_cmd64x_get_info(p, dev, i);
-	}
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
 static u8 quantize_timing(int timing, int quant)
 {
 	return (timing + quant - 1) / quant;
@@ -472,16 +370,6 @@
 	mrdmode &= ~0x30;
 	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-
-	cmd_devs[n_cmd_devs++] = dev;
-
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
-
 	return 0;
 }
 
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index d1a91bc..6ec00b8 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -71,7 +71,6 @@
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *pdev = hwif->pci_dev;
 	int controller = drive->dn > 1 ? 1 : 0;
-	u8 reg;
 
 	/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
 
@@ -91,11 +90,6 @@
 	pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
 		(cs5520_pio_clocks[pio].recovery << 4) |
 		(cs5520_pio_clocks[pio].assert));
-		
-	/* Set the DMA enable/disable flag */
-	reg = inb(hwif->dma_base + 0x02 + 8*controller);
-	reg |= 1<<((drive->dn&1)+5);
-	outb(reg, hwif->dma_base + 0x02 + 8*controller);
 }
 
 static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
@@ -109,13 +103,14 @@
  *	We wrap the DMA activate to set the vdma flag. This is needed
  *	so that the IDE DMA layer issues PIO not DMA commands over the
  *	DMA channel
+ *
+ *	ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA
  */
- 
-static int cs5520_dma_on(ide_drive_t *drive)
+
+static void cs5520_dma_host_set(ide_drive_t *drive, int on)
 {
-	/* ATAPI is harder so leave it for now */
-	drive->vdma = 1;
-	return 0;
+	drive->vdma = on;
+	ide_dma_host_set(drive, on);
 }
 
 static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
@@ -126,7 +121,7 @@
 	if (hwif->dma_base == 0)
 		return;
 
-	hwif->ide_dma_on = &cs5520_dma_on;
+	hwif->dma_host_set = &cs5520_dma_host_set;
 }
 
 #define DECLARE_CS_DEV(name_str)				\
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 1cd4e9c..3ec4c659 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cy82c693.c		Version 0.42	Oct 23, 2007
+ * linux/drivers/ide/pci/cy82c693.c		Version 0.44	Nov 8, 2007
  *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
  *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
@@ -176,17 +176,12 @@
  * set DMA mode a specific channel for CY82C693
  */
 
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
-	u8 index = 0, data = 0;
+	ide_hwif_t *hwif = drive->hwif;
+	u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
 
-	if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+	index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
 
 #if CY82C693_DEBUG_LOGS
 	/* for debug let's show the previous values */
@@ -199,7 +194,7 @@
 		(data&0x3), ((data>>2)&1));
 #endif /* CY82C693_DEBUG_LOGS */
 
-	data = (u8)mode|(u8)(single<<2);
+	data = (mode & 3) | (single << 2);
 
 	outb(index, CY82_INDEX_PORT);
 	outb(data, CY82_DATA_PORT);
@@ -207,7 +202,7 @@
 #if CY82C693_DEBUG_INFO
 	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
 		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		mode, single);
+		mode & 3, single);
 #endif /* CY82C693_DEBUG_INFO */
 
 	/* 
@@ -230,39 +225,6 @@
 #endif /* CY82C693_DEBUG_INFO */
 }
 
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_ide_dma_on (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-	if (id != NULL) {		
-		/* Enable DMA on any drive that has DMA
-		 * (multi or single) enabled
-		 */
-		if (id->field_valid & 2) {	/* regular DMA */
-			int mmode, smode;
-
-			mmode = id->dma_mword & (id->dma_mword >> 8);
-			smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-			if (mmode != 0) {
-				/* enable multi */
-				cy82c693_dma_enable(drive, (mmode >> 1), 0);
-			} else if (smode != 0) {
-				/* enable single */
-				cy82c693_dma_enable(drive, (smode >> 1), 1);
-			}
-		}
-	}
-        return __ide_dma_on(drive);
-}
-
 static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = HWIF(drive);
@@ -429,11 +391,7 @@
 static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
 {
 	hwif->set_pio_mode = &cy82c693_set_pio_mode;
-
-	if (hwif->dma_base == 0)
-		return;
-
-	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	hwif->set_dma_mode = &cy82c693_set_dma_mode;
 }
 
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
@@ -454,11 +412,11 @@
 	.init_iops	= init_iops_cy82c693,
 	.init_hwif	= init_hwif_cy82c693,
 	.chipset	= ide_cy82c693,
-	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
 			  IDE_HFLAG_BOOTABLE,
 	.pio_mask	= ATA_PIO4,
-	.swdma_mask	= ATA_SWDMA2_ONLY,
-	.mwdma_mask	= ATA_MWDMA2_ONLY,
+	.swdma_mask	= ATA_SWDMA2,
+	.mwdma_mask	= ATA_MWDMA2,
 };
 
 static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index 8382908..26aa492 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(&hw, &ide_undecoded_slave, 0, &hwif);
+	rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
 	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/hpt366.c b/drivers/ide/pci/hpt366.c
index 3777fb8..1268593 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -725,15 +725,18 @@
 	hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static int hpt3xx_quirkproc(ide_drive_t *drive)
+static void hpt3xx_quirkproc(ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
 	const  char **list	= quirk_drives;
 
 	while (*list)
-		if (strstr(id->model, *list++))
-			return 1;
-	return 0;
+		if (strstr(id->model, *list++)) {
+			drive->quirk_list = 1;
+			return;
+		}
+
+	drive->quirk_list = 0;
 }
 
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 99b7d76..e610a53 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -431,33 +431,29 @@
 }
 
 /**
- *	it821x_fixup	-	post init callback
- *	@hwif: interface
+ *	it821x_quirkproc	-	post init callback
+ *	@drive: drive
  *
- *	This callback is run after the drives have been probed but
+ *	This callback is run after the drive has been probed but
  *	before anything gets attached. It allows drivers to do any
  *	final tuning that is needed, or fixups to work around bugs.
  */
 
-static void __devinit it821x_fixups(ide_hwif_t *hwif)
+static void __devinit it821x_quirkproc(ide_drive_t *drive)
 {
-	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int i;
+	struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
+	struct hd_driveid *id = drive->id;
+	u16 *idbits = (u16 *)drive->id;
 
-	if(!itdev->smart) {
+	if (!itdev->smart) {
 		/*
 		 *	If we are in pass through mode then not much
 		 *	needs to be done, but we do bother to clear the
 		 *	IRQ mask as we may well be in PIO (eg rev 0x10)
 		 *	for now and we know unmasking is safe on this chipset.
 		 */
-		for (i = 0; i < 2; i++) {
-			ide_drive_t *drive = &hwif->drives[i];
-			if(drive->present)
-				drive->unmask = 1;
-		}
-		return;
-	}
+		drive->unmask = 1;
+	} else {
 	/*
 	 *	Perform fixups on smart mode. We need to "lose" some
 	 *	capabilities the firmware lacks but does not filter, and
@@ -465,16 +461,6 @@
 	 *	in RAID mode.
 	 */
 
-	for(i = 0; i < 2; i++) {
-		ide_drive_t *drive = &hwif->drives[i];
-		struct hd_driveid *id;
-		u16 *idbits;
-
-		if(!drive->present)
-			continue;
-		id = drive->id;
-		idbits = (u16 *)drive->id;
-
 		/* Check for RAID v native */
 		if(strstr(id->model, "Integrated Technology Express")) {
 			/* In raid mode the ident block is slightly buggy
@@ -537,6 +523,8 @@
 	struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
 	u8 conf;
 
+	hwif->quirkproc = &it821x_quirkproc;
+
 	if (idev == NULL) {
 		printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
 		return;
@@ -633,7 +621,6 @@
 		.name		= name_str,		\
 		.init_chipset	= init_chipset_it821x,	\
 		.init_hwif	= init_hwif_it821x,	\
-		.fixup	 	= it821x_fixups,	\
 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
 		.pio_mask	= ATA_PIO4,		\
 	}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ef4a99b..89d2363 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -203,14 +203,17 @@
 		return ATA_CBL_PATA80;
 }
 
-static int pdcnew_quirkproc(ide_drive_t *drive)
+static void pdcnew_quirkproc(ide_drive_t *drive)
 {
 	const char **list, *model = drive->id->model;
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL)
-			return 2;
-	return 0;
+		if (strstr(model, *list) != NULL) {
+			drive->quirk_list = 2;
+			return;
+		}
+
+	drive->quirk_list = 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 67b2781..3a1e081 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -176,14 +176,17 @@
 	outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
 }
 
-static int pdc202xx_quirkproc (ide_drive_t *drive)
+static void pdc202xx_quirkproc(ide_drive_t *drive)
 {
 	const char **list, *model = drive->id->model;
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL)
-			return 2;
-	return 0;
+		if (strstr(model, *list) != NULL) {
+			drive->quirk_list = 2;
+			return;
+		}
+
+	drive->quirk_list = 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index fef20bd..32fdf53 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -220,9 +220,9 @@
 	}
 	if (mode != -1) {
 		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
-		hwif->dma_off_quietly(drive);
-		if (ide_set_dma_mode(drive, mode) == 0)
-			hwif->dma_host_on(drive);
+		ide_dma_off_quietly(drive);
+		if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
+			hwif->dma_host_set(drive, 1);
 		return;
 	}
 
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index e9bd269..877c09b 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -164,25 +164,12 @@
 	ultra_timing	&= ~(0x0F << (4*unit));
 	ultra_enable	&= ~(0x01 << drive->dn);
 
-	switch(speed) {
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-		default:
-			break;
-	}
+	if (speed >= XFER_UDMA_0) {
+		dma_timing   |= dma_modes[2];
+		ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
+		ultra_enable |= (0x01 << drive->dn);
+	} else if (speed >= XFER_MW_DMA_0)
+		dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
 
 	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
 	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 7e9dade..9e0be7d 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -277,21 +277,6 @@
 	return dma_stat;
 }
 
-static int
-sgiioc4_ide_dma_on(ide_drive_t * drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
-static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-
-	drive->hwif->dma_host_off(drive);
-}
-
 static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
 }
@@ -303,13 +288,10 @@
 	return sgiioc4_checkirq(HWIF(drive));
 }
 
-static void sgiioc4_dma_host_on(ide_drive_t * drive)
+static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
 {
-}
-
-static void sgiioc4_dma_host_off(ide_drive_t * drive)
-{
-	sgiioc4_clearirq(drive);
+	if (!on)
+		sgiioc4_clearirq(drive);
 }
 
 static void
@@ -593,14 +575,11 @@
 
 	hwif->mwdma_mask = ATA_MWDMA2_ONLY;
 
+	hwif->dma_host_set = &sgiioc4_dma_host_set;
 	hwif->dma_setup = &sgiioc4_ide_dma_setup;
 	hwif->dma_start = &sgiioc4_ide_dma_start;
 	hwif->ide_dma_end = &sgiioc4_ide_dma_end;
-	hwif->ide_dma_on = &sgiioc4_ide_dma_on;
-	hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
 	hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
-	hwif->dma_host_on = &sgiioc4_dma_host_on;
-	hwif->dma_host_off = &sgiioc4_dma_host_off;
 	hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
 	hwif->dma_timeout = &ide_dma_timeout;
 }
@@ -614,6 +593,7 @@
 	ide_hwif_t *hwif;
 	int h;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+	hw_regs_t hw;
 
 	/*
 	 * Find an empty HWIF; if none available, return -ENOMEM.
@@ -653,21 +633,16 @@
 		return -ENOMEM;
 	}
 
-	if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
-		hw_regs_t hw;
+	/* Initialize the IO registers */
+	memset(&hw, 0, sizeof(hw));
+	sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+	hw.irq = dev->irq;
+	hw.chipset = ide_pci;
+	hw.dev = &dev->dev;
+	ide_init_port_hw(hwif, &hw);
 
-		/* Initialize the IO registers */
-		memset(&hw, 0, sizeof(hw));
-		sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-	}
-
-	hwif->irq = dev->irq;
-	hwif->chipset = ide_pci;
 	hwif->pci_dev = dev;
 	hwif->channel = 0;	/* Single Channel chip */
-	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
 
 	/* The IOC4 uses MMIO rather than Port IO. */
 	default_hwif_mmiops(hwif);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 7b45eaf..908f37b 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -713,9 +713,6 @@
 	const char *s = &drive->id->model[0];
 	unsigned len;
 
-	if (!drive->present)
-		return 0;
-
 	len = strnlen(s, sizeof(drive->id->model));
 
 	if ((len > 4) && (!memcmp(s, "ST", 2))) {
@@ -730,18 +727,20 @@
 }
 
 /**
- *	siimage_fixup		-	post probe fixups
- *	@hwif: interface to fix up
+ *	sil_quirkproc		-	post probe fixups
+ *	@drive: drive
  *
  *	Called after drive probe we use this to decide whether the
  *	Seagate fixup must be applied. This used to be in init_iops but
  *	that can occur before we know what drives are present.
  */
 
-static void __devinit siimage_fixup(ide_hwif_t *hwif)
+static void __devinit sil_quirkproc(ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = drive->hwif;
+
 	/* Try and raise the rqsize */
-	if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
+	if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
 		hwif->rqsize = 128;
 }
 
@@ -804,6 +803,7 @@
 
 	hwif->set_pio_mode = &sil_set_pio_mode;
 	hwif->set_dma_mode = &sil_set_dma_mode;
+	hwif->quirkproc = &sil_quirkproc;
 
 	if (sata) {
 		static int first = 1;
@@ -842,7 +842,6 @@
 		.init_chipset	= init_chipset_siimage,	\
 		.init_iops	= init_iops_siimage,	\
 		.init_hwif	= init_hwif_siimage,	\
-		.fixup		= siimage_fixup,	\
 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
 		.pio_mask	= ATA_PIO4,		\
 		.mwdma_mask	= ATA_MWDMA2,		\
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 069f104..c7a125b 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -13,6 +13,7 @@
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
  *
  * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  */
 
 #include <linux/types.h>
@@ -90,14 +91,8 @@
 	drive->drive_data &= 0xffff0000;
 	drive->drive_data |= drv_ctrl;
 
-	if (!drive->using_dma) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg,  drv_ctrl);
-		pci_read_config_word (dev, reg, &drv_ctrl);
-	}
+	pci_write_config_word(dev, reg,  drv_ctrl);
+	pci_read_config_word (dev, reg, &drv_ctrl);
 
 	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
 			  ide_xfer_verbose(pio + XFER_PIO_0),
@@ -123,17 +118,6 @@
 	 */
 	drive->drive_data &= 0x0000ffff;
 	drive->drive_data |= (unsigned long)drv_ctrl << 16;
-
-	/*
-	 * If we are already using DMA, we just reprogram
-	 * the drive control register.
-	 */
-	if (drive->using_dma) {
-		struct pci_dev *dev	= HWIF(drive)->pci_dev;
-		int reg 		= 0x44 + drive->dn * 4;
-
-		pci_write_config_word(dev, reg, drv_ctrl);
-	}
 }
 
 /*
@@ -201,6 +185,11 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
+	int reg 		= 0x44 + drive->dn * 4;
+
+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+
+	pci_write_config_word(dev, reg, drive->drive_data >> 16);
 
 	sl82c105_reset_host(dev);
 	ide_dma_start(drive);
@@ -214,64 +203,24 @@
 	ide_dma_timeout(drive);
 }
 
-static int sl82c105_ide_dma_on(ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	int rc, reg 		= 0x44 + drive->dn * 4;
-
-	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
-
-	rc = __ide_dma_on(drive);
-	if (rc == 0) {
-		pci_write_config_word(dev, reg, drive->drive_data >> 16);
-
-		printk(KERN_INFO "%s: DMA enabled\n", drive->name);
-	}
-	return rc;
-}
-
-static void sl82c105_dma_off_quietly(ide_drive_t *drive)
+static int sl82c105_dma_end(ide_drive_t *drive)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 	int reg 		= 0x44 + drive->dn * 4;
+	int ret;
 
-	DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+
+	ret = __ide_dma_end(drive);
 
 	pci_write_config_word(dev, reg, drive->drive_data);
 
-	ide_dma_off_quietly(drive);
-}
-
-/*
- * Ok, that is nasty, but we must make sure the DMA timings
- * won't be used for a PIO access. The solution here is
- * to make sure the 16 bits mode is diabled on the channel
- * when DMA is enabled, thus causing the chip to use PIO0
- * timings for those operations.
- */
-static void sl82c105_selectproc(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u32 val, old, mask;
-
-	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
-
-	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
-	old = val = (u32)pci_get_drvdata(dev);
-	if (drive->using_dma)
-		val &= ~mask;
-	else
-		val |= mask;
-	if (old != val) {
-		pci_write_config_dword(dev, 0x40, val);	
-		pci_set_drvdata(dev, (void *)val);
-	}
+	return ret;
 }
 
 /*
  * ATA reset will clear the 16 bits mode in the control
- * register, we need to update our cache
+ * register, we need to reprogram it
  */
 static void sl82c105_resetproc(ide_drive_t *drive)
 {
@@ -281,7 +230,8 @@
 	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
 
 	pci_read_config_dword(dev, 0x40, &val);
-	pci_set_drvdata(dev, (void *)val);
+	val |= (CTRL_P1F16 | CTRL_P0F16);
+	pci_write_config_dword(dev, 0x40, val);
 }
 
 /*
@@ -334,7 +284,6 @@
 	pci_read_config_dword(dev, 0x40, &val);
 	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
 	pci_write_config_dword(dev, 0x40, val);
-	pci_set_drvdata(dev, (void *)val);
 
 	return dev->irq;
 }
@@ -350,7 +299,6 @@
 
 	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
 	hwif->set_dma_mode	= &sl82c105_set_dma_mode;
-	hwif->selectproc	= &sl82c105_selectproc;
 	hwif->resetproc 	= &sl82c105_resetproc;
 
 	if (!hwif->dma_base)
@@ -369,10 +317,9 @@
 
 	hwif->mwdma_mask = ATA_MWDMA2;
 
-	hwif->ide_dma_on		= &sl82c105_ide_dma_on;
-	hwif->dma_off_quietly		= &sl82c105_dma_off_quietly;
 	hwif->dma_lost_irq		= &sl82c105_dma_lost_irq;
 	hwif->dma_start			= &sl82c105_dma_start;
+	hwif->ide_dma_end		= &sl82c105_dma_end;
 	hwif->dma_timeout		= &sl82c105_dma_timeout;
 
 	if (hwif->mate)
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index 0151d7f..04cd893 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -241,11 +241,7 @@
 	return (status == 0x00ff);
 }
 
-static void trm290_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static void trm290_dma_host_off(ide_drive_t *drive)
+static void trm290_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -289,8 +285,7 @@
 
 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
 
-	hwif->dma_host_off	= &trm290_dma_host_off;
-	hwif->dma_host_on	= &trm290_dma_host_on;
+	hwif->dma_host_set	= &trm290_dma_host_set;
 	hwif->dma_setup 	= &trm290_dma_setup;
 	hwif->dma_exec_cmd	= &trm290_dma_exec_cmd;
 	hwif->dma_start 	= &trm290_dma_start;
diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
new file mode 100644
index 0000000..65af584
--- /dev/null
+++ b/drivers/ide/ppc/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 5f0da35..3fd5d45 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -838,3 +838,21 @@
 	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
 	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
 }
+
+static int __init mpc8xx_ide_probe(void)
+{
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
+#ifdef IDE0_BASE_OFFSET
+	idx[0] = 0;
+#ifdef IDE1_BASE_OFFSET
+	idx[1] = 1;
+#endif
+#endif
+
+	ide_device_add(idx);
+
+	return 0;
+}
+
+module_init(mpc8xx_ide_probe);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 3dce800..736d12c 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1012,12 +1012,11 @@
  * rare machines unfortunately, but it's better this way.
  */
 static int
-pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
 {
 	struct device_node *np = pmif->node;
 	const int *bidp;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-	hw_regs_t hw;
 
 	pmif->cable_80 = 0;
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1103,11 +1102,9 @@
 	/* Tell common code _not_ to mess with resources */
 	hwif->mmio = 1;
 	hwif->hwif_data = pmif;
-	memset(&hw, 0, sizeof(hw));
-	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-	hwif->chipset = ide_pmac;
-	hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
+	hw->chipset = ide_pmac;
+	ide_init_port_hw(hwif, hw);
+	hwif->noprobe = pmif->mediabay;
 	hwif->hold = pmif->mediabay;
 	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 	hwif->drives[0].unmask = 1;
@@ -1136,8 +1133,6 @@
 		hwif->noprobe = 0;
 #endif /* CONFIG_PMAC_MEDIABAY */
 
-	hwif->sg_max_nents = MAX_DCMDS;
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* has a DBDMA controller channel */
 	if (pmif->dma_regs)
@@ -1163,6 +1158,7 @@
 	ide_hwif_t *hwif;
 	pmac_ide_hwif_t *pmif;
 	int i, rc;
+	hw_regs_t hw;
 
 	i = 0;
 	while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
@@ -1205,7 +1201,6 @@
 	regbase = (unsigned long) base;
 
 	hwif->pci_dev = mdev->bus->pdev;
-	hwif->gendev.parent = &mdev->ofdev.dev;
 
 	pmif->mdev = mdev;
 	pmif->node = mdev->ofdev.node;
@@ -1223,7 +1218,12 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 	dev_set_drvdata(&mdev->ofdev.dev, hwif);
 
-	rc = pmac_ide_setup_device(pmif, hwif);
+	memset(&hw, 0, sizeof(hw));
+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+	hw.irq = irq;
+	hw.dev = &mdev->ofdev.dev;
+
+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
 	if (rc != 0) {
 		/* The inteface is released to the common IDE layer */
 		dev_set_drvdata(&mdev->ofdev.dev, NULL);
@@ -1282,6 +1282,7 @@
 	void __iomem *base;
 	unsigned long rbase, rlen;
 	int i, rc;
+	hw_regs_t hw;
 
 	np = pci_device_to_OF_node(pdev);
 	if (np == NULL) {
@@ -1315,7 +1316,6 @@
 	}
 
 	hwif->pci_dev = pdev;
-	hwif->gendev.parent = &pdev->dev;
 	pmif->mdev = NULL;
 	pmif->node = np;
 
@@ -1332,7 +1332,12 @@
 
 	pci_set_drvdata(pdev, hwif);
 
-	rc = pmac_ide_setup_device(pmif, hwif);
+	memset(&hw, 0, sizeof(hw));
+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+	hw.irq = pdev->irq;
+	hw.dev = &pdev->dev;
+
+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
 	if (rc != 0) {
 		/* The inteface is released to the common IDE layer */
 		pci_set_drvdata(pdev, NULL);
@@ -1698,11 +1703,7 @@
 	return 1;
 }
 
-static void pmac_ide_dma_host_off(ide_drive_t *drive)
-{
-}
-
-static void pmac_ide_dma_host_on(ide_drive_t *drive)
+static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -1748,15 +1749,14 @@
 		return;
 	}
 
-	hwif->dma_off_quietly = &ide_dma_off_quietly;
-	hwif->ide_dma_on = &__ide_dma_on;
+	hwif->sg_max_nents = MAX_DCMDS;
+
+	hwif->dma_host_set = &pmac_ide_dma_host_set;
 	hwif->dma_setup = &pmac_ide_dma_setup;
 	hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
 	hwif->dma_start = &pmac_ide_dma_start;
 	hwif->ide_dma_end = &pmac_ide_dma_end;
 	hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
-	hwif->dma_host_off = &pmac_ide_dma_host_off;
-	hwif->dma_host_on = &pmac_ide_dma_host_on;
 	hwif->dma_timeout = &ide_dma_timeout;
 	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
 
@@ -1786,3 +1786,5 @@
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+module_init(pmac_ide_probe);
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index d2cd5a3..676c66e 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -165,13 +165,17 @@
 
 		dma_base = pci_resource_start(dev, baridx);
 
-		if (dma_base == 0)
+		if (dma_base == 0) {
 			printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
+			return 0;
+		}
 	}
 
-	if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
+	if (hwif->channel)
+		dma_base += 8;
+
+	if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
 		u8 simplex_stat = 0;
-		dma_base += hwif->channel ? 8 : 0;
 
 		switch(dev->device) {
 			case PCI_DEVICE_ID_AL_M5219:
@@ -359,6 +363,8 @@
 	unsigned long ctl = 0, base = 0;
 	ide_hwif_t *hwif;
 	u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
+	u8 oldnoprobe = 0;
+	struct hw_regs_s hw;
 
 	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
 		/*  Possibly we should fail if these checks report true */
@@ -381,26 +387,25 @@
 	}
 	if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
 		return NULL;	/* no room in ide_hwifs[] */
-	if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
-	    hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
-		hw_regs_t hw;
 
-		memset(&hw, 0, sizeof(hw));
-#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
-		ide_std_init_ports(&hw, base, ctl | 2);
-#else
-		ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
-#endif
-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-	}
-	hwif->chipset = d->chipset ? d->chipset : ide_pci;
+	memset(&hw, 0, sizeof(hw));
+	hw.irq = hwif->irq ? hwif->irq : irq;
+	hw.dev = &dev->dev;
+	hw.chipset = d->chipset ? d->chipset : ide_pci;
+	ide_std_init_ports(&hw, base, ctl | 2);
+
+	if (hwif->io_ports[IDE_DATA_OFFSET] == base &&
+	    hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2))
+		oldnoprobe = hwif->noprobe;
+
+	ide_init_port_hw(hwif, &hw);
+
+	hwif->noprobe = oldnoprobe;
+
 	hwif->pci_dev = dev;
 	hwif->cds = d;
 	hwif->channel = port;
 
-	if (!hwif->irq)
-		hwif->irq = irq;
 	if (mate) {
 		hwif->mate = mate;
 		mate->mate = hwif;
@@ -535,12 +540,8 @@
 		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
 			continue;
 
-		/* setup proper ancestral information */
-		hwif->gendev.parent = &dev->dev;
-
 		*(idx + port) = hwif->index;
 
-		
 		if (d->init_iops)
 			d->init_iops(hwif);
 
@@ -551,8 +552,6 @@
 		    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
 			hwif->irq = port ? 15 : 14;
 
-		hwif->fixup = d->fixup;
-
 		hwif->host_flags = d->host_flags;
 		hwif->pio_mask = d->pio_mask;
 
@@ -699,105 +698,3 @@
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
-
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-/*
- *	Module interfaces
- */
-
-static int pre_init = 1;		/* Before first ordered IDE scan */
-static LIST_HEAD(ide_pci_drivers);
-
-/*
- *	__ide_pci_register_driver	-	attach IDE driver
- *	@driver: pci driver
- *	@module: owner module of the driver
- *
- *	Registers a driver with the IDE layer. The IDE layer arranges that
- *	boot time setup is done in the expected device order and then
- *	hands the controllers off to the core PCI code to do the rest of
- *	the work.
- *
- *	Returns are the same as for pci_register_driver
- */
-
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
-			      const char *mod_name)
-{
-	if (!pre_init)
-		return __pci_register_driver(driver, module, mod_name);
-	driver->driver.owner = module;
-	list_add_tail(&driver->node, &ide_pci_drivers);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-
-/**
- *	ide_scan_pcidev		-	find an IDE driver for a device
- *	@dev: PCI device to check
- *
- *	Look for an IDE driver to handle the device we are considering.
- *	This is only used during boot up to get the ordering correct. After
- *	boot up the pci layer takes over the job.
- */
-
-static int __init ide_scan_pcidev(struct pci_dev *dev)
-{
-	struct list_head *l;
-	struct pci_driver *d;
-
-	list_for_each(l, &ide_pci_drivers) {
-		d = list_entry(l, struct pci_driver, node);
-		if (d->id_table) {
-			const struct pci_device_id *id =
-				pci_match_id(d->id_table, dev);
-
-			if (id != NULL && d->probe(dev, id) >= 0) {
-				dev->driver = d;
-				pci_dev_get(dev);
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-/**
- *	ide_scan_pcibus		-	perform the initial IDE driver scan
- *	@scan_direction: set for reverse order scanning
- *
- *	Perform the initial bus rather than driver ordered scan of the
- *	PCI drivers. After this all IDE pci handling becomes standard
- *	module ordering not traditionally ordered.
- */
- 	
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev = NULL;
-	struct pci_driver *d;
-	struct list_head *l, *n;
-
-	pre_init = 0;
-	if (!scan_direction)
-		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
-			ide_scan_pcidev(dev);
-	else
-		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
-						     dev)))
-			ide_scan_pcidev(dev);
-
-	/*
-	 *	Hand the drivers over to the PCI layer now we
-	 *	are post init.
-	 */
-
-	list_for_each_safe(l, n, &ide_pci_drivers) {
-		list_del(l);
-		d = list_entry(l, struct pci_driver, node);
-		if (__pci_register_driver(d, d->driver.owner,
-					  d->driver.mod_name))
-			printk(KERN_ERR "%s: failed to register %s driver\n",
-					__FUNCTION__, d->driver.mod_name);
-	}
-}
-#endif
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 48d647a..eaba4a9 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -563,7 +563,8 @@
 				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, 0, NULL);
+				bay->cd_index =
+					ide_register_hw(&hw, NULL, NULL);
 				pmu_resume();
 			}
 			if (bay->cd_index == -1) {
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 5452da1..b66da74 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -47,12 +47,10 @@
 
 #define LOG_TEMP		0			/* continously log temperature */
 
-#define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
-
 static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
 
 /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static unsigned short		normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+static const unsigned short	normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
 						 0x4c, 0x4d, 0x4e, 0x4f,
 						 0x2c, 0x2d, 0x2e, 0x2f,
 						 I2C_CLIENT_END };
@@ -357,7 +355,6 @@
 	.driver = {
 		.name	= "therm_windtunnel",
 	},
-	.id		= I2C_DRIVERID_G4FAN,
 	.attach_adapter = do_attach,
 	.detach_client	= do_detach,
 };
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 255dae3..566e479 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -87,11 +87,24 @@
 	int cur_input;	/* current input */
 };
 
+static int dpc_check_clients(struct device *dev, void *data)
+{
+	struct dpc* dpc = data;
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if( !client )
+		return 0;
+
+	if( I2C_SAA7111A == client->addr )
+		dpc->saa7111a = client;
+
+	return 0;
+}
+
 /* fixme: add vbi stuff here */
 static int dpc_probe(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = NULL;
-	struct i2c_client *client;
 
 	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
 	if( NULL == dpc ) {
@@ -115,9 +128,7 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
-		if( I2C_SAA7111A == client->addr )
-			dpc->saa7111a = client;
+	device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
 
 	/* check if all devices are present */
 	if( 0 == dpc->saa7111a ) {
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index b6cd21e..4895540 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -764,7 +764,6 @@
 	.addr = 0,
 	.adapter = NULL,
 	.driver = &i2c_driver_ks0127,
-	.usage_count = 0
 };
 
 static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 98ad309..add6d0d 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -149,10 +149,33 @@
 
 static struct saa7146_extension extension;
 
+static int mxb_check_clients(struct device *dev, void *data)
+{
+	struct mxb* mxb = data;
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if( !client )
+		return 0;
+
+	if( I2C_ADDR_TEA6420_1 == client->addr )
+		mxb->tea6420_1 = client;
+	if( I2C_ADDR_TEA6420_2 == client->addr )
+		mxb->tea6420_2 = client;
+	if( I2C_TEA6415C_2 == client->addr )
+		mxb->tea6415c = client;
+	if( I2C_ADDR_TDA9840 == client->addr )
+		mxb->tda9840 = client;
+	if( I2C_SAA7111 == client->addr )
+		mxb->saa7111a = client;
+	if( 0x60 == client->addr )
+		mxb->tuner = client;
+
+	return 0;
+}
+
 static int mxb_probe(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = NULL;
-	struct i2c_client *client;
 	int result;
 
 	if ((result = request_module("saa7111")) < 0) {
@@ -195,20 +218,7 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
-		if( I2C_ADDR_TEA6420_1 == client->addr )
-			mxb->tea6420_1 = client;
-		if( I2C_ADDR_TEA6420_2 == client->addr )
-			mxb->tea6420_2 = client;
-		if( I2C_TEA6415C_2 == client->addr )
-			mxb->tea6415c = client;
-		if( I2C_ADDR_TDA9840 == client->addr )
-			mxb->tda9840 = client;
-		if( I2C_SAA7111 == client->addr )
-			mxb->saa7111a = client;
-		if( 0x60 == client->addr )
-			mxb->tuner = client;
-	}
+	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
 
 	/* check if all devices are present */
 	if(    0 == mxb->tea6420_1	|| 0 == mxb->tea6420_2	|| 0 == mxb->tea6415c
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 9a03dc8..5bb7529 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2589,11 +2589,7 @@
 	/* First try D1 and then SAA7191 */
 	if (vino_drvdata->camera.driver
 	    && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
-		if (i2c_use_client(vino_drvdata->camera.driver)) {
-			ret = -ENODEV;
-			goto out;
-		}
-
+		i2c_use_client(vino_drvdata->camera.driver);
 		vino_drvdata->camera.owner = vcs->channel;
 		vcs->input = VINO_INPUT_D1;
 		vcs->data_norm = VINO_DATA_NORM_D1;
@@ -2602,11 +2598,7 @@
 		int input, data_norm;
 		int saa7191_input;
 
-		if (i2c_use_client(vino_drvdata->decoder.driver)) {
-			ret = -ENODEV;
-			goto out;
-		}
-
+		i2c_use_client(vino_drvdata->decoder.driver);
 		input = VINO_INPUT_COMPOSITE;
 
 		saa7191_input = vino_get_saa7191_input(input);
@@ -2688,10 +2680,7 @@
 		}
 
 		if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
-			if (i2c_use_client(vino_drvdata->decoder.driver)) {
-				ret = -ENODEV;
-				goto out;
-			}
+			i2c_use_client(vino_drvdata->decoder.driver);
 			vino_drvdata->decoder.owner = vcs->channel;
 		}
 
@@ -2759,10 +2748,7 @@
 		}
 
 		if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
-			if (i2c_use_client(vino_drvdata->camera.driver)) {
-				ret = -ENODEV;
-				goto out;
-			}
+			i2c_use_client(vino_drvdata->camera.driver);
 			vino_drvdata->camera.owner = vcs->channel;
 		}
 
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index b7c8e78..61aeaf7 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -20,7 +20,7 @@
 #include "ucb1x00.h"
 
 #define UCB1X00_ATTR(name,input)\
-static ssize_t name##_show(struct device *dev, struct device_attribute *attr,
+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
 			   char *buf)	\
 {								\
 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);		\
@@ -38,17 +38,17 @@
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-	device_create_file(&dev->ucb->dev, &device_attr_vbatt);
-	device_create_file(&dev->ucb->dev, &device_attr_vcharger);
-	device_create_file(&dev->ucb->dev, &device_attr_batt_temp);
+	device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
+	device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
+	device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
 	return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
-	device_remove_file(&dev->ucb->cdev, &device_attr_batt_temp);
-	device_remove_file(&dev->ucb->cdev, &device_attr_vcharger);
-	device_remove_file(&dev->ucb->cdev, &device_attr_vbatt);
+	device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
+	device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
+	device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
 }
 
 static struct ucb1x00_driver ucb1x00_assabet_driver = {
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 971e18b..c9dfeb1 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -25,6 +25,7 @@
 #include <linux/mmc/card.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -35,7 +36,6 @@
 #include <asm/arch/dma.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
-#include <asm/arch/tps65010.h>
 
 #define	OMAP_MMC_REG_CMD	0x00
 #define	OMAP_MMC_REG_ARGL	0x04
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9af05a2..a672866 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -212,7 +212,7 @@
 
 config MACB
 	tristate "Atmel MACB support"
-	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
+	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91CAP9
 	select PHYLIB
 	help
 	  The Atmel MACB ethernet interface is found on many AT32 and AT91
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index dfef163..e0900ca 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -16,7 +16,7 @@
 #define DRV_VERSION "0.3"
 
 /* Addresses to scan: none. This chip cannot be detected. */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 1c74364..725b0c7 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -61,7 +61,7 @@
 /* i2c configuration */
 #define ISL1208_I2C_ADDR 0xde
 
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
 };
 I2C_CLIENT_INSMOD; /* defines addr_data */
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index a1cd448..7683412 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -54,7 +54,7 @@
 
 #define MAX6900_I2C_ADDR		0xa0
 
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	MAX6900_I2C_ADDR >> 1,
 	I2C_CLIENT_END
 };
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0242d80..b3317fc 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -25,7 +25,7 @@
  * located at 0x51 will pass the validation routine due to
  * the way the registers are implemented.
  */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Module parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 556d0e7..c973ba9 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -40,7 +40,7 @@
 #define CTRL_ALARM	0x02
 #define CTRL_TIMER	0x01
 
-static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
 
 /* Module parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index b3fae35..b90fb18 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -32,7 +32,7 @@
  * unknown chips, the user must explicitly set the probe parameter.
  */
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index be9f22d..0a89e08 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -2,8 +2,8 @@
 # S/390 block devices
 #
 
-dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
+dasd_fba_mod-objs  := dasd_fba.o
 dasd_diag_mod-objs := dasd_diag.o
 dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
 			dasd_genhd.o dasd_erp.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index e6bfce6..1db15f3 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -48,13 +48,15 @@
 /*
  * SECTION: prototypes for static functions of dasd.c
  */
-static int  dasd_alloc_queue(struct dasd_device * device);
-static void dasd_setup_queue(struct dasd_device * device);
-static void dasd_free_queue(struct dasd_device * device);
-static void dasd_flush_request_queue(struct dasd_device *);
-static int dasd_flush_ccw_queue(struct dasd_device *, int);
-static void dasd_tasklet(struct dasd_device *);
+static int  dasd_alloc_queue(struct dasd_block *);
+static void dasd_setup_queue(struct dasd_block *);
+static void dasd_free_queue(struct dasd_block *);
+static void dasd_flush_request_queue(struct dasd_block *);
+static int dasd_flush_block_queue(struct dasd_block *);
+static void dasd_device_tasklet(struct dasd_device *);
+static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
+static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 
 /*
  * SECTION: Operations on the device structure.
@@ -65,26 +67,23 @@
 /*
  * Allocate memory for a new device structure.
  */
-struct dasd_device *
-dasd_alloc_device(void)
+struct dasd_device *dasd_alloc_device(void)
 {
 	struct dasd_device *device;
 
-	device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
-	if (device == NULL)
+	device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC);
+	if (!device)
 		return ERR_PTR(-ENOMEM);
-	/* open_count = 0 means device online but not in use */
-	atomic_set(&device->open_count, -1);
 
 	/* Get two pages for normal block device operations. */
 	device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
-	if (device->ccw_mem == NULL) {
+	if (!device->ccw_mem) {
 		kfree(device);
 		return ERR_PTR(-ENOMEM);
 	}
 	/* Get one page for error recovery. */
 	device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
-	if (device->erp_mem == NULL) {
+	if (!device->erp_mem) {
 		free_pages((unsigned long) device->ccw_mem, 1);
 		kfree(device);
 		return ERR_PTR(-ENOMEM);
@@ -93,10 +92,9 @@
 	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
 	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
 	spin_lock_init(&device->mem_lock);
-	spin_lock_init(&device->request_queue_lock);
-	atomic_set (&device->tasklet_scheduled, 0);
+	atomic_set(&device->tasklet_scheduled, 0);
 	tasklet_init(&device->tasklet,
-		     (void (*)(unsigned long)) dasd_tasklet,
+		     (void (*)(unsigned long)) dasd_device_tasklet,
 		     (unsigned long) device);
 	INIT_LIST_HEAD(&device->ccw_queue);
 	init_timer(&device->timer);
@@ -110,8 +108,7 @@
 /*
  * Free memory of a device structure.
  */
-void
-dasd_free_device(struct dasd_device *device)
+void dasd_free_device(struct dasd_device *device)
 {
 	kfree(device->private);
 	free_page((unsigned long) device->erp_mem);
@@ -120,10 +117,42 @@
 }
 
 /*
+ * Allocate memory for a new device structure.
+ */
+struct dasd_block *dasd_alloc_block(void)
+{
+	struct dasd_block *block;
+
+	block = kzalloc(sizeof(*block), GFP_ATOMIC);
+	if (!block)
+		return ERR_PTR(-ENOMEM);
+	/* open_count = 0 means device online but not in use */
+	atomic_set(&block->open_count, -1);
+
+	spin_lock_init(&block->request_queue_lock);
+	atomic_set(&block->tasklet_scheduled, 0);
+	tasklet_init(&block->tasklet,
+		     (void (*)(unsigned long)) dasd_block_tasklet,
+		     (unsigned long) block);
+	INIT_LIST_HEAD(&block->ccw_queue);
+	spin_lock_init(&block->queue_lock);
+	init_timer(&block->timer);
+
+	return block;
+}
+
+/*
+ * Free memory of a device structure.
+ */
+void dasd_free_block(struct dasd_block *block)
+{
+	kfree(block);
+}
+
+/*
  * Make a new device known to the system.
  */
-static int
-dasd_state_new_to_known(struct dasd_device *device)
+static int dasd_state_new_to_known(struct dasd_device *device)
 {
 	int rc;
 
@@ -133,12 +162,13 @@
 	 */
 	dasd_get_device(device);
 
-	rc = dasd_alloc_queue(device);
-	if (rc) {
-		dasd_put_device(device);
-		return rc;
+	if (device->block) {
+		rc = dasd_alloc_queue(device->block);
+		if (rc) {
+			dasd_put_device(device);
+			return rc;
+		}
 	}
-
 	device->state = DASD_STATE_KNOWN;
 	return 0;
 }
@@ -146,21 +176,24 @@
 /*
  * Let the system forget about a device.
  */
-static int
-dasd_state_known_to_new(struct dasd_device * device)
+static int dasd_state_known_to_new(struct dasd_device *device)
 {
 	/* Disable extended error reporting for this device. */
 	dasd_eer_disable(device);
 	/* Forget the discipline information. */
-	if (device->discipline)
+	if (device->discipline) {
+		if (device->discipline->uncheck_device)
+			device->discipline->uncheck_device(device);
 		module_put(device->discipline->owner);
+	}
 	device->discipline = NULL;
 	if (device->base_discipline)
 		module_put(device->base_discipline->owner);
 	device->base_discipline = NULL;
 	device->state = DASD_STATE_NEW;
 
-	dasd_free_queue(device);
+	if (device->block)
+		dasd_free_queue(device->block);
 
 	/* Give up reference we took in dasd_state_new_to_known. */
 	dasd_put_device(device);
@@ -170,19 +203,19 @@
 /*
  * Request the irq line for the device.
  */
-static int
-dasd_state_known_to_basic(struct dasd_device * device)
+static int dasd_state_known_to_basic(struct dasd_device *device)
 {
 	int rc;
 
 	/* Allocate and register gendisk structure. */
-	rc = dasd_gendisk_alloc(device);
-	if (rc)
-		return rc;
-
+	if (device->block) {
+		rc = dasd_gendisk_alloc(device->block);
+		if (rc)
+			return rc;
+	}
 	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
-	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
-					    8 * sizeof (long));
+	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+					    8 * sizeof(long));
 	debug_register_view(device->debug_area, &debug_sprintf_view);
 	debug_set_level(device->debug_area, DBF_WARNING);
 	DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
@@ -194,16 +227,17 @@
 /*
  * Release the irq line for the device. Terminate any running i/o.
  */
-static int
-dasd_state_basic_to_known(struct dasd_device * device)
+static int dasd_state_basic_to_known(struct dasd_device *device)
 {
 	int rc;
-
-	dasd_gendisk_free(device);
-	rc = dasd_flush_ccw_queue(device, 1);
+	if (device->block) {
+		dasd_gendisk_free(device->block);
+		dasd_block_clear_timer(device->block);
+	}
+	rc = dasd_flush_device_queue(device);
 	if (rc)
 		return rc;
-	dasd_clear_timer(device);
+	dasd_device_clear_timer(device);
 
 	DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
 	if (device->debug_area != NULL) {
@@ -228,26 +262,32 @@
  * In case the analysis returns an error, the device setup is stopped
  * (a fake disk was already added to allow formatting).
  */
-static int
-dasd_state_basic_to_ready(struct dasd_device * device)
+static int dasd_state_basic_to_ready(struct dasd_device *device)
 {
 	int rc;
+	struct dasd_block *block;
 
 	rc = 0;
-	if (device->discipline->do_analysis != NULL)
-		rc = device->discipline->do_analysis(device);
-	if (rc) {
-		if (rc != -EAGAIN)
-			device->state = DASD_STATE_UNFMT;
-		return rc;
-	}
+	block = device->block;
 	/* make disk known with correct capacity */
-	dasd_setup_queue(device);
-	set_capacity(device->gdp, device->blocks << device->s2b_shift);
-	device->state = DASD_STATE_READY;
-	rc = dasd_scan_partitions(device);
-	if (rc)
-		device->state = DASD_STATE_BASIC;
+	if (block) {
+		if (block->base->discipline->do_analysis != NULL)
+			rc = block->base->discipline->do_analysis(block);
+		if (rc) {
+			if (rc != -EAGAIN)
+				device->state = DASD_STATE_UNFMT;
+			return rc;
+		}
+		dasd_setup_queue(block);
+		set_capacity(block->gdp,
+			     block->blocks << block->s2b_shift);
+		device->state = DASD_STATE_READY;
+		rc = dasd_scan_partitions(block);
+		if (rc)
+			device->state = DASD_STATE_BASIC;
+	} else {
+		device->state = DASD_STATE_READY;
+	}
 	return rc;
 }
 
@@ -256,28 +296,31 @@
  * Forget format information. Check if the target level is basic
  * and if it is create fake disk for formatting.
  */
-static int
-dasd_state_ready_to_basic(struct dasd_device * device)
+static int dasd_state_ready_to_basic(struct dasd_device *device)
 {
 	int rc;
 
-	rc = dasd_flush_ccw_queue(device, 0);
-	if (rc)
-		return rc;
-	dasd_destroy_partitions(device);
-	dasd_flush_request_queue(device);
-	device->blocks = 0;
-	device->bp_block = 0;
-	device->s2b_shift = 0;
 	device->state = DASD_STATE_BASIC;
+	if (device->block) {
+		struct dasd_block *block = device->block;
+		rc = dasd_flush_block_queue(block);
+		if (rc) {
+			device->state = DASD_STATE_READY;
+			return rc;
+		}
+		dasd_destroy_partitions(block);
+		dasd_flush_request_queue(block);
+		block->blocks = 0;
+		block->bp_block = 0;
+		block->s2b_shift = 0;
+	}
 	return 0;
 }
 
 /*
  * Back to basic.
  */
-static int
-dasd_state_unfmt_to_basic(struct dasd_device * device)
+static int dasd_state_unfmt_to_basic(struct dasd_device *device)
 {
 	device->state = DASD_STATE_BASIC;
 	return 0;
@@ -291,17 +334,31 @@
 static int
 dasd_state_ready_to_online(struct dasd_device * device)
 {
+	int rc;
+
+	if (device->discipline->ready_to_online) {
+		rc = device->discipline->ready_to_online(device);
+		if (rc)
+			return rc;
+	}
 	device->state = DASD_STATE_ONLINE;
-	dasd_schedule_bh(device);
+	if (device->block)
+		dasd_schedule_block_bh(device->block);
 	return 0;
 }
 
 /*
  * Stop the requeueing of requests again.
  */
-static int
-dasd_state_online_to_ready(struct dasd_device * device)
+static int dasd_state_online_to_ready(struct dasd_device *device)
 {
+	int rc;
+
+	if (device->discipline->online_to_ready) {
+		rc = device->discipline->online_to_ready(device);
+		if (rc)
+			return rc;
+	}
 	device->state = DASD_STATE_READY;
 	return 0;
 }
@@ -309,8 +366,7 @@
 /*
  * Device startup state changes.
  */
-static int
-dasd_increase_state(struct dasd_device *device)
+static int dasd_increase_state(struct dasd_device *device)
 {
 	int rc;
 
@@ -345,8 +401,7 @@
 /*
  * Device shutdown state changes.
  */
-static int
-dasd_decrease_state(struct dasd_device *device)
+static int dasd_decrease_state(struct dasd_device *device)
 {
 	int rc;
 
@@ -381,8 +436,7 @@
 /*
  * This is the main startup/shutdown routine.
  */
-static void
-dasd_change_state(struct dasd_device *device)
+static void dasd_change_state(struct dasd_device *device)
 {
         int rc;
 
@@ -409,17 +463,15 @@
  * dasd_kick_device will schedule a call do do_kick_device to the kernel
  * event daemon.
  */
-static void
-do_kick_device(struct work_struct *work)
+static void do_kick_device(struct work_struct *work)
 {
 	struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
 	dasd_change_state(device);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	dasd_put_device(device);
 }
 
-void
-dasd_kick_device(struct dasd_device *device)
+void dasd_kick_device(struct dasd_device *device)
 {
 	dasd_get_device(device);
 	/* queue call to dasd_kick_device to the kernel event daemon. */
@@ -429,8 +481,7 @@
 /*
  * Set the target state for a device and starts the state change.
  */
-void
-dasd_set_target_state(struct dasd_device *device, int target)
+void dasd_set_target_state(struct dasd_device *device, int target)
 {
 	/* If we are in probeonly mode stop at DASD_STATE_READY. */
 	if (dasd_probeonly && target > DASD_STATE_READY)
@@ -447,14 +498,12 @@
 /*
  * Enable devices with device numbers in [from..to].
  */
-static inline int
-_wait_for_device(struct dasd_device *device)
+static inline int _wait_for_device(struct dasd_device *device)
 {
 	return (device->state == device->target);
 }
 
-void
-dasd_enable_device(struct dasd_device *device)
+void dasd_enable_device(struct dasd_device *device)
 {
 	dasd_set_target_state(device, DASD_STATE_ONLINE);
 	if (device->state <= DASD_STATE_KNOWN)
@@ -475,20 +524,20 @@
 /*
  * Increments counter in global and local profiling structures.
  */
-#define dasd_profile_counter(value, counter, device) \
+#define dasd_profile_counter(value, counter, block) \
 { \
 	int index; \
 	for (index = 0; index < 31 && value >> (2+index); index++); \
 	dasd_global_profile.counter[index]++; \
-	device->profile.counter[index]++; \
+	block->profile.counter[index]++; \
 }
 
 /*
  * Add profiling information for cqr before execution.
  */
-static void
-dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
-		   struct request *req)
+static void dasd_profile_start(struct dasd_block *block,
+			       struct dasd_ccw_req *cqr,
+			       struct request *req)
 {
 	struct list_head *l;
 	unsigned int counter;
@@ -498,19 +547,19 @@
 
 	/* count the length of the chanq for statistics */
 	counter = 0;
-	list_for_each(l, &device->ccw_queue)
+	list_for_each(l, &block->ccw_queue)
 		if (++counter >= 31)
 			break;
 	dasd_global_profile.dasd_io_nr_req[counter]++;
-	device->profile.dasd_io_nr_req[counter]++;
+	block->profile.dasd_io_nr_req[counter]++;
 }
 
 /*
  * Add profiling information for cqr after execution.
  */
-static void
-dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
-		 struct request *req)
+static void dasd_profile_end(struct dasd_block *block,
+			     struct dasd_ccw_req *cqr,
+			     struct request *req)
 {
 	long strtime, irqtime, endtime, tottime;	/* in microseconds */
 	long tottimeps, sectors;
@@ -532,27 +581,27 @@
 
 	if (!dasd_global_profile.dasd_io_reqs)
 		memset(&dasd_global_profile, 0,
-		       sizeof (struct dasd_profile_info_t));
+		       sizeof(struct dasd_profile_info_t));
 	dasd_global_profile.dasd_io_reqs++;
 	dasd_global_profile.dasd_io_sects += sectors;
 
-	if (!device->profile.dasd_io_reqs)
-		memset(&device->profile, 0,
-		       sizeof (struct dasd_profile_info_t));
-	device->profile.dasd_io_reqs++;
-	device->profile.dasd_io_sects += sectors;
+	if (!block->profile.dasd_io_reqs)
+		memset(&block->profile, 0,
+		       sizeof(struct dasd_profile_info_t));
+	block->profile.dasd_io_reqs++;
+	block->profile.dasd_io_sects += sectors;
 
-	dasd_profile_counter(sectors, dasd_io_secs, device);
-	dasd_profile_counter(tottime, dasd_io_times, device);
-	dasd_profile_counter(tottimeps, dasd_io_timps, device);
-	dasd_profile_counter(strtime, dasd_io_time1, device);
-	dasd_profile_counter(irqtime, dasd_io_time2, device);
-	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
-	dasd_profile_counter(endtime, dasd_io_time3, device);
+	dasd_profile_counter(sectors, dasd_io_secs, block);
+	dasd_profile_counter(tottime, dasd_io_times, block);
+	dasd_profile_counter(tottimeps, dasd_io_timps, block);
+	dasd_profile_counter(strtime, dasd_io_time1, block);
+	dasd_profile_counter(irqtime, dasd_io_time2, block);
+	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block);
+	dasd_profile_counter(endtime, dasd_io_time3, block);
 }
 #else
-#define dasd_profile_start(device, cqr, req) do {} while (0)
-#define dasd_profile_end(device, cqr, req) do {} while (0)
+#define dasd_profile_start(block, cqr, req) do {} while (0)
+#define dasd_profile_end(block, cqr, req) do {} while (0)
 #endif				/* CONFIG_DASD_PROFILE */
 
 /*
@@ -562,9 +611,9 @@
  * memory and 2) dasd_smalloc_request uses the static ccw memory
  * that gets allocated for each device.
  */
-struct dasd_ccw_req *
-dasd_kmalloc_request(char *magic, int cplength, int datasize,
-		   struct dasd_device * device)
+struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
+					  int datasize,
+					  struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
@@ -600,9 +649,9 @@
 	return cqr;
 }
 
-struct dasd_ccw_req *
-dasd_smalloc_request(char *magic, int cplength, int datasize,
-		   struct dasd_device * device)
+struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
+					  int datasize,
+					  struct dasd_device *device)
 {
 	unsigned long flags;
 	struct dasd_ccw_req *cqr;
@@ -649,8 +698,7 @@
  * idal lists that might have been created by dasd_set_cda and the
  * struct dasd_ccw_req itself.
  */
-void
-dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 #ifdef CONFIG_64BIT
 	struct ccw1 *ccw;
@@ -667,8 +715,7 @@
 	dasd_put_device(device);
 }
 
-void
-dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 	unsigned long flags;
 
@@ -681,14 +728,13 @@
 /*
  * Check discipline magic in cqr.
  */
-static inline int
-dasd_check_cqr(struct dasd_ccw_req *cqr)
+static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 
 	if (cqr == NULL)
 		return -EINVAL;
-	device = cqr->device;
+	device = cqr->startdev;
 	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    " dasd_ccw_req 0x%08x magic doesn't match"
@@ -706,8 +752,7 @@
  * ccw_device_clear can fail if the i/o subsystem
  * is in a bad mood.
  */
-int
-dasd_term_IO(struct dasd_ccw_req * cqr)
+int dasd_term_IO(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int retries, rc;
@@ -717,13 +762,13 @@
 	if (rc)
 		return rc;
 	retries = 0;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
 		rc = ccw_device_clear(device->cdev, (long) cqr);
 		switch (rc) {
 		case 0:	/* termination successful */
 			cqr->retries--;
-			cqr->status = DASD_CQR_CLEAR;
+			cqr->status = DASD_CQR_CLEAR_PENDING;
 			cqr->stopclk = get_clock();
 			cqr->starttime = 0;
 			DBF_DEV_EVENT(DBF_DEBUG, device,
@@ -753,7 +798,7 @@
 		}
 		retries++;
 	}
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	return rc;
 }
 
@@ -761,8 +806,7 @@
  * Start the i/o. This start_IO can fail if the channel is really busy.
  * In that case set up a timer to start the request later.
  */
-int
-dasd_start_IO(struct dasd_ccw_req * cqr)
+int dasd_start_IO(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int rc;
@@ -771,12 +815,12 @@
 	rc = dasd_check_cqr(cqr);
 	if (rc)
 		return rc;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (cqr->retries < 0) {
 		DEV_MESSAGE(KERN_DEBUG, device,
 			    "start_IO: request %p (%02x/%i) - no retry left.",
 			    cqr, cqr->status, cqr->retries);
-		cqr->status = DASD_CQR_FAILED;
+		cqr->status = DASD_CQR_ERROR;
 		return -EIO;
 	}
 	cqr->startclk = get_clock();
@@ -833,8 +877,7 @@
  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
  * DASD_CQR_QUEUED for 2) and 3).
  */
-static void
-dasd_timeout_device(unsigned long ptr)
+static void dasd_device_timeout(unsigned long ptr)
 {
 	unsigned long flags;
 	struct dasd_device *device;
@@ -844,14 +887,13 @@
 	/* re-activate request queue */
         device->stopped &= ~DASD_STOPPED_PENDING;
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 }
 
 /*
  * Setup timeout for a device in jiffies.
  */
-void
-dasd_set_timer(struct dasd_device *device, int expires)
+void dasd_device_set_timer(struct dasd_device *device, int expires)
 {
 	if (expires == 0) {
 		if (timer_pending(&device->timer))
@@ -862,7 +904,7 @@
 		if (mod_timer(&device->timer, jiffies + expires))
 			return;
 	}
-	device->timer.function = dasd_timeout_device;
+	device->timer.function = dasd_device_timeout;
 	device->timer.data = (unsigned long) device;
 	device->timer.expires = jiffies + expires;
 	add_timer(&device->timer);
@@ -871,15 +913,14 @@
 /*
  * Clear timeout for a device.
  */
-void
-dasd_clear_timer(struct dasd_device *device)
+void dasd_device_clear_timer(struct dasd_device *device)
 {
 	if (timer_pending(&device->timer))
 		del_timer(&device->timer);
 }
 
-static void
-dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
+static void dasd_handle_killed_request(struct ccw_device *cdev,
+				       unsigned long intparm)
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_device *device;
@@ -893,7 +934,7 @@
 		return;
 	}
 
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (device == NULL ||
 	    device != dasd_device_from_cdev_locked(cdev) ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
@@ -905,46 +946,32 @@
 	/* Schedule request to be retried. */
 	cqr->status = DASD_CQR_QUEUED;
 
-	dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+	dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 	dasd_put_device(device);
 }
 
-static void
-dasd_handle_state_change_pending(struct dasd_device *device)
+void dasd_generic_handle_state_change(struct dasd_device *device)
 {
-	struct dasd_ccw_req *cqr;
-	struct list_head *l, *n;
-
 	/* First of all start sense subsystem status request. */
 	dasd_eer_snss(device);
 
 	device->stopped &= ~DASD_STOPPED_PENDING;
-
-        /* restart all 'running' IO on queue */
-	list_for_each_safe(l, n, &device->ccw_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
-                if (cqr->status == DASD_CQR_IN_IO) {
-                        cqr->status = DASD_CQR_QUEUED;
-		}
-        }
-	dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
+	if (device->block)
+		dasd_schedule_block_bh(device->block);
 }
 
 /*
  * Interrupt handler for "normal" ssch-io based dasd devices.
  */
-void
-dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
-		 struct irb *irb)
+void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+		      struct irb *irb)
 {
 	struct dasd_ccw_req *cqr, *next;
 	struct dasd_device *device;
 	unsigned long long now;
 	int expires;
-	dasd_era_t era;
-	char mask;
 
 	if (IS_ERR(irb)) {
 		switch (PTR_ERR(irb)) {
@@ -969,29 +996,25 @@
 		  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
 		  (unsigned int) intparm);
 
-	/* first of all check for state change pending interrupt */
-	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-	if ((irb->scsw.dstat & mask) == mask) {
+	/* check for unsolicited interrupts */
+	cqr = (struct dasd_ccw_req *) intparm;
+	if (!cqr || ((irb->scsw.cc == 1) &&
+		     (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
+		     (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
+		if (cqr && cqr->status == DASD_CQR_IN_IO)
+			cqr->status = DASD_CQR_QUEUED;
 		device = dasd_device_from_cdev_locked(cdev);
 		if (!IS_ERR(device)) {
-			dasd_handle_state_change_pending(device);
+			dasd_device_clear_timer(device);
+			device->discipline->handle_unsolicited_interrupt(device,
+									 irb);
 			dasd_put_device(device);
 		}
 		return;
 	}
 
-	cqr = (struct dasd_ccw_req *) intparm;
-
-	/* check for unsolicited interrupts */
-	if (cqr == NULL) {
-		MESSAGE(KERN_DEBUG,
-			"unsolicited interrupt received: bus_id %s",
-			cdev->dev.bus_id);
-		return;
-	}
-
-	device = (struct dasd_device *) cqr->device;
-	if (device == NULL ||
+	device = (struct dasd_device *) cqr->startdev;
+	if (!device ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
 			cdev->dev.bus_id);
@@ -999,12 +1022,12 @@
 	}
 
 	/* Check for clear pending */
-	if (cqr->status == DASD_CQR_CLEAR &&
+	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
 	    irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
-		cqr->status = DASD_CQR_QUEUED;
-		dasd_clear_timer(device);
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_device_clear_timer(device);
 		wake_up(&dasd_flush_wq);
-		dasd_schedule_bh(device);
+		dasd_schedule_device_bh(device);
 		return;
 	}
 
@@ -1017,277 +1040,170 @@
 	}
 	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
 		      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
-
- 	/* Find out the appropriate era_action. */
-	if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
-		era = dasd_era_fatal;
-	else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-		 irb->scsw.cstat == 0 &&
-		 !irb->esw.esw0.erw.cons)
-		era = dasd_era_none;
-	else if (irb->esw.esw0.erw.cons)
-		era = device->discipline->examine_error(cqr, irb);
-	else
-		era = dasd_era_recover;
-
-	DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
+	next = NULL;
 	expires = 0;
-	if (era == dasd_era_none) {
-		cqr->status = DASD_CQR_DONE;
+	if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+	    irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
+		/* request was completed successfully */
+		cqr->status = DASD_CQR_SUCCESS;
 		cqr->stopclk = now;
 		/* Start first request on queue if possible -> fast_io. */
-		if (cqr->list.next != &device->ccw_queue) {
-			next = list_entry(cqr->list.next,
-					  struct dasd_ccw_req, list);
-			if ((next->status == DASD_CQR_QUEUED) &&
-			    (!device->stopped)) {
-				if (device->discipline->start_IO(next) == 0)
-					expires = next->expires;
-				else
-					DEV_MESSAGE(KERN_DEBUG, device, "%s",
-						    "Interrupt fastpath "
-						    "failed!");
-			}
+		if (cqr->devlist.next != &device->ccw_queue) {
+			next = list_entry(cqr->devlist.next,
+					  struct dasd_ccw_req, devlist);
 		}
-	} else {		/* error */
-		memcpy(&cqr->irb, irb, sizeof (struct irb));
+	} else {  /* error */
+		memcpy(&cqr->irb, irb, sizeof(struct irb));
 		if (device->features & DASD_FEATURE_ERPLOG) {
-			/* dump sense data */
 			dasd_log_sense(cqr, irb);
 		}
-		switch (era) {
-		case dasd_era_fatal:
-			cqr->status = DASD_CQR_FAILED;
-			cqr->stopclk = now;
-			break;
-		case dasd_era_recover:
+		/* If we have no sense data, or we just don't want complex ERP
+		 * for this request, but if we have retries left, then just
+		 * reset this request and retry it in the fastpath
+		 */
+		if (!(cqr->irb.esw.esw0.erw.cons &&
+		      test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
+		    cqr->retries > 0) {
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "default ERP in fastpath (%i retries left)",
+				    cqr->retries);
+			cqr->lpm    = LPM_ANYPATH;
+			cqr->status = DASD_CQR_QUEUED;
+			next = cqr;
+		} else
 			cqr->status = DASD_CQR_ERROR;
-			break;
-		default:
-			BUG();
-		}
+	}
+	if (next && (next->status == DASD_CQR_QUEUED) &&
+	    (!device->stopped)) {
+		if (device->discipline->start_IO(next) == 0)
+			expires = next->expires;
+		else
+			DEV_MESSAGE(KERN_DEBUG, device, "%s",
+				    "Interrupt fastpath "
+				    "failed!");
 	}
 	if (expires != 0)
-		dasd_set_timer(device, expires);
+		dasd_device_set_timer(device, expires);
 	else
-		dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+		dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 }
 
 /*
- * posts the buffer_cache about a finalized request
+ * If we have an error on a dasd_block layer request then we cancel
+ * and return all further requests from the same dasd_block as well.
  */
-static inline void
-dasd_end_request(struct request *req, int uptodate)
-{
-	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
-		BUG();
-	add_disk_randomness(req->rq_disk);
-	end_that_request_last(req, uptodate);
-}
-
-/*
- * Process finished error recovery ccw.
- */
-static inline void
-__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
-{
-	dasd_erp_fn_t erp_fn;
-
-	if (cqr->status == DASD_CQR_DONE)
-		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
-	else
-		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
-	erp_fn = device->discipline->erp_postaction(cqr);
-	erp_fn(cqr);
-}
-
-/*
- * Process ccw request queue.
- */
-static void
-__dasd_process_ccw_queue(struct dasd_device * device,
-			 struct list_head *final_queue)
+static void __dasd_device_recovery(struct dasd_device *device,
+				   struct dasd_ccw_req *ref_cqr)
 {
 	struct list_head *l, *n;
 	struct dasd_ccw_req *cqr;
-	dasd_erp_fn_t erp_fn;
-
-restart:
-	/* Process request with final status. */
-	list_for_each_safe(l, n, &device->ccw_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
-		/* Stop list processing at the first non-final request. */
-		if (cqr->status != DASD_CQR_DONE &&
-		    cqr->status != DASD_CQR_FAILED &&
-		    cqr->status != DASD_CQR_ERROR)
-			break;
-		/*  Process requests with DASD_CQR_ERROR */
-		if (cqr->status == DASD_CQR_ERROR) {
-			if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) {
-				cqr->status = DASD_CQR_FAILED;
-				cqr->stopclk = get_clock();
-			} else {
-				if (cqr->irb.esw.esw0.erw.cons &&
-				    test_bit(DASD_CQR_FLAGS_USE_ERP,
-					     &cqr->flags)) {
-					erp_fn = device->discipline->
-						erp_action(cqr);
-					erp_fn(cqr);
-				} else
-					dasd_default_erp_action(cqr);
-			}
-			goto restart;
-		}
-
-		/* First of all call extended error reporting. */
-		if (dasd_eer_enabled(device) &&
-		    cqr->status == DASD_CQR_FAILED) {
-			dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
-
-			/* restart request  */
-			cqr->status = DASD_CQR_QUEUED;
-			cqr->retries = 255;
-			device->stopped |= DASD_STOPPED_QUIESCE;
-			goto restart;
-		}
-
-		/* Process finished ERP request. */
-		if (cqr->refers) {
-			__dasd_process_erp(device, cqr);
-			goto restart;
-		}
-
-		/* Rechain finished requests to final queue */
-		cqr->endclk = get_clock();
-		list_move_tail(&cqr->list, final_queue);
-	}
-}
-
-static void
-dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
-{
-	struct request *req;
-	struct dasd_device *device;
-	int status;
-
-	req = (struct request *) data;
-	device = cqr->device;
-	dasd_profile_end(device, cqr, req);
-	status = cqr->device->discipline->free_cp(cqr,req);
-	spin_lock_irq(&device->request_queue_lock);
-	dasd_end_request(req, status);
-	spin_unlock_irq(&device->request_queue_lock);
-}
-
-
-/*
- * Fetch requests from the block device queue.
- */
-static void
-__dasd_process_blk_queue(struct dasd_device * device)
-{
-	struct request_queue *queue;
-	struct request *req;
-	struct dasd_ccw_req *cqr;
-	int nr_queued;
-
-	queue = device->request_queue;
-	/* No queue ? Then there is nothing to do. */
-	if (queue == NULL)
-		return;
 
 	/*
-	 * We requeue request from the block device queue to the ccw
-	 * queue only in two states. In state DASD_STATE_READY the
-	 * partition detection is done and we need to requeue requests
-	 * for that. State DASD_STATE_ONLINE is normal block device
-	 * operation.
+	 * only requeue request that came from the dasd_block layer
 	 */
-	if (device->state != DASD_STATE_READY &&
-	    device->state != DASD_STATE_ONLINE)
+	if (!ref_cqr->block)
 		return;
-	nr_queued = 0;
-	/* Now we try to fetch requests from the request queue */
-	list_for_each_entry(cqr, &device->ccw_queue, list)
-		if (cqr->status == DASD_CQR_QUEUED)
-			nr_queued++;
-	while (!blk_queue_plugged(queue) &&
-	       elv_next_request(queue) &&
-		nr_queued < DASD_CHANQ_MAX_SIZE) {
-		req = elv_next_request(queue);
 
-		if (device->features & DASD_FEATURE_READONLY &&
-		    rq_data_dir(req) == WRITE) {
-			DBF_DEV_EVENT(DBF_ERR, device,
-				      "Rejecting write request %p",
-				      req);
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+		if (cqr->status == DASD_CQR_QUEUED &&
+		    ref_cqr->block == cqr->block) {
+			cqr->status = DASD_CQR_CLEARED;
 		}
-		if (device->stopped & DASD_STOPPED_DC_EIO) {
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
+	}
+};
+
+/*
+ * Remove those ccw requests from the queue that need to be returned
+ * to the upper layer.
+ */
+static void __dasd_device_process_ccw_queue(struct dasd_device *device,
+					    struct list_head *final_queue)
+{
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+
+	/* Process request with final status. */
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+
+		/* Stop list processing at the first non-final request. */
+		if (cqr->status == DASD_CQR_QUEUED ||
+		    cqr->status == DASD_CQR_IN_IO ||
+		    cqr->status == DASD_CQR_CLEAR_PENDING)
+			break;
+		if (cqr->status == DASD_CQR_ERROR) {
+			__dasd_device_recovery(device, cqr);
 		}
-		cqr = device->discipline->build_cp(device, req);
-		if (IS_ERR(cqr)) {
-			if (PTR_ERR(cqr) == -ENOMEM)
-				break;	/* terminate request queue loop */
-			if (PTR_ERR(cqr) == -EAGAIN) {
-				/*
-				 * The current request cannot be build right
-				 * now, we have to try later. If this request
-				 * is the head-of-queue we stop the device
-				 * for 1/2 second.
-				 */
-				if (!list_empty(&device->ccw_queue))
-					break;
-				device->stopped |= DASD_STOPPED_PENDING;
-				dasd_set_timer(device, HZ/2);
-				break;
-			}
-			DBF_DEV_EVENT(DBF_ERR, device,
-				      "CCW creation failed (rc=%ld) "
-				      "on request %p",
-				      PTR_ERR(cqr), req);
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
-		}
-		cqr->callback = dasd_end_request_cb;
-		cqr->callback_data = (void *) req;
-		cqr->status = DASD_CQR_QUEUED;
-		blkdev_dequeue_request(req);
-		list_add_tail(&cqr->list, &device->ccw_queue);
-		dasd_profile_start(device, cqr, req);
-		nr_queued++;
+		/* Rechain finished requests to final queue */
+		list_move_tail(&cqr->devlist, final_queue);
 	}
 }
 
 /*
+ * the cqrs from the final queue are returned to the upper layer
+ * by setting a dasd_block state and calling the callback function
+ */
+static void __dasd_device_process_final_queue(struct dasd_device *device,
+					      struct list_head *final_queue)
+{
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+
+	list_for_each_safe(l, n, final_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+		list_del_init(&cqr->devlist);
+		if (cqr->block)
+			spin_lock_bh(&cqr->block->queue_lock);
+		switch (cqr->status) {
+		case DASD_CQR_SUCCESS:
+			cqr->status = DASD_CQR_DONE;
+			break;
+		case DASD_CQR_ERROR:
+			cqr->status = DASD_CQR_NEED_ERP;
+			break;
+		case DASD_CQR_CLEARED:
+			cqr->status = DASD_CQR_TERMINATED;
+			break;
+		default:
+			DEV_MESSAGE(KERN_ERR, device,
+				    "wrong cqr status in __dasd_process_final_queue "
+				    "for cqr %p, status %x",
+				    cqr, cqr->status);
+			BUG();
+		}
+		if (cqr->block)
+			spin_unlock_bh(&cqr->block->queue_lock);
+		if (cqr->callback != NULL)
+			(cqr->callback)(cqr, cqr->callback_data);
+	}
+}
+
+
+
+/*
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  */
-static void
-__dasd_check_expire(struct dasd_device * device)
+static void __dasd_device_check_expire(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
 	if (list_empty(&device->ccw_queue))
 		return;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
 	    (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
 		if (device->discipline->term_IO(cqr) != 0) {
 			/* Hmpf, try again in 5 sec */
-			dasd_set_timer(device, 5*HZ);
 			DEV_MESSAGE(KERN_ERR, device,
 				    "internal error - timeout (%is) expired "
 				    "for cqr %p, termination failed, "
 				    "retrying in 5s",
 				    (cqr->expires/HZ), cqr);
+			cqr->expires += 5*HZ;
+			dasd_device_set_timer(device, 5*HZ);
 		} else {
 			DEV_MESSAGE(KERN_ERR, device,
 				    "internal error - timeout (%is) expired "
@@ -1301,77 +1217,53 @@
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  */
-static void
-__dasd_start_head(struct dasd_device * device)
+static void __dasd_device_start_head(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 	int rc;
 
 	if (list_empty(&device->ccw_queue))
 		return;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	if (cqr->status != DASD_CQR_QUEUED)
 		return;
-	/* Non-temporary stop condition will trigger fail fast */
-	if (device->stopped & ~DASD_STOPPED_PENDING &&
-	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
-	    (!dasd_eer_enabled(device))) {
-		cqr->status = DASD_CQR_FAILED;
-		dasd_schedule_bh(device);
+	/* when device is stopped, return request to previous layer */
+	if (device->stopped) {
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_schedule_device_bh(device);
 		return;
 	}
-	/* Don't try to start requests if device is stopped */
-	if (device->stopped)
-		return;
 
 	rc = device->discipline->start_IO(cqr);
 	if (rc == 0)
-		dasd_set_timer(device, cqr->expires);
+		dasd_device_set_timer(device, cqr->expires);
 	else if (rc == -EACCES) {
-		dasd_schedule_bh(device);
+		dasd_schedule_device_bh(device);
 	} else
 		/* Hmpf, try again in 1/2 sec */
-		dasd_set_timer(device, 50);
-}
-
-static inline int
-_wait_for_clear(struct dasd_ccw_req *cqr)
-{
-	return (cqr->status == DASD_CQR_QUEUED);
+		dasd_device_set_timer(device, 50);
 }
 
 /*
- * Remove all requests from the ccw queue (all = '1') or only block device
- * requests in case all = '0'.
- * Take care of the erp-chain (chained via cqr->refers) and remove either
- * the whole erp-chain or none of the erp-requests.
- * If a request is currently running, term_IO is called and the request
- * is re-queued. Prior to removing the terminated request we need to wait
- * for the clear-interrupt.
- * In case termination is not possible we stop processing and just finishing
- * the already moved requests.
+ * Go through all request on the dasd_device request queue,
+ * terminate them on the cdev if necessary, and return them to the
+ * submitting layer via callback.
+ * Note:
+ * Make sure that all 'submitting layers' still exist when
+ * this function is called!. In other words, when 'device' is a base
+ * device then all block layer requests must have been removed before
+ * via dasd_flush_block_queue.
  */
-static int
-dasd_flush_ccw_queue(struct dasd_device * device, int all)
+int dasd_flush_device_queue(struct dasd_device *device)
 {
-	struct dasd_ccw_req *cqr, *orig, *n;
-	int rc, i;
-
+	struct dasd_ccw_req *cqr, *n;
+	int rc;
 	struct list_head flush_queue;
 
 	INIT_LIST_HEAD(&flush_queue);
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = 0;
-restart:
-	list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
-		/* get original request of erp request-chain */
-		for (orig = cqr; orig->refers != NULL; orig = orig->refers);
-
-		/* Flush all request or only block device requests? */
-		if (all == 0 && cqr->callback != dasd_end_request_cb &&
-		    orig->callback != dasd_end_request_cb) {
-			continue;
-		}
+	list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
 		/* Check status and move request to flush_queue */
 		switch (cqr->status) {
 		case DASD_CQR_IN_IO:
@@ -1387,90 +1279,60 @@
 			}
 			break;
 		case DASD_CQR_QUEUED:
-		case DASD_CQR_ERROR:
-			/* set request to FAILED */
 			cqr->stopclk = get_clock();
-			cqr->status = DASD_CQR_FAILED;
+			cqr->status = DASD_CQR_CLEARED;
 			break;
-		default: /* do not touch the others */
+		default: /* no need to modify the others */
 			break;
 		}
-		/* Rechain request (including erp chain) */
-		for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
-			cqr->endclk = get_clock();
-			list_move_tail(&cqr->list, &flush_queue);
-		}
-		if (i > 1)
-			/* moved more than one request - need to restart */
-			goto restart;
+		list_move_tail(&cqr->devlist, &flush_queue);
 	}
-
 finished:
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-	/* Now call the callback function of flushed requests */
-restart_cb:
-	list_for_each_entry_safe(cqr, n, &flush_queue, list) {
-		if (cqr->status == DASD_CQR_CLEAR) {
-			/* wait for clear interrupt! */
-			wait_event(dasd_flush_wq, _wait_for_clear(cqr));
-			cqr->status = DASD_CQR_FAILED;
-		}
-		/* Process finished ERP request. */
-		if (cqr->refers) {
-			__dasd_process_erp(device, cqr);
-			/* restart list_for_xx loop since dasd_process_erp
-			 * might remove multiple elements */
-			goto restart_cb;
-		}
-		/* call the callback function */
-		cqr->endclk = get_clock();
-		if (cqr->callback != NULL)
-			(cqr->callback)(cqr, cqr->callback_data);
-	}
+	/*
+	 * After this point all requests must be in state CLEAR_PENDING,
+	 * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become
+	 * one of the others.
+	 */
+	list_for_each_entry_safe(cqr, n, &flush_queue, devlist)
+		wait_event(dasd_flush_wq,
+			   (cqr->status != DASD_CQR_CLEAR_PENDING));
+	/*
+	 * Now set each request back to TERMINATED, DONE or NEED_ERP
+	 * and call the callback function of flushed requests
+	 */
+	__dasd_device_process_final_queue(device, &flush_queue);
 	return rc;
 }
 
 /*
  * Acquire the device lock and process queues for the device.
  */
-static void
-dasd_tasklet(struct dasd_device * device)
+static void dasd_device_tasklet(struct dasd_device *device)
 {
 	struct list_head final_queue;
-	struct list_head *l, *n;
-	struct dasd_ccw_req *cqr;
 
 	atomic_set (&device->tasklet_scheduled, 0);
 	INIT_LIST_HEAD(&final_queue);
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	/* Check expire time of first request on the ccw queue. */
-	__dasd_check_expire(device);
-	/* Finish off requests on ccw queue */
-	__dasd_process_ccw_queue(device, &final_queue);
+	__dasd_device_check_expire(device);
+	/* find final requests on ccw queue */
+	__dasd_device_process_ccw_queue(device, &final_queue);
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	/* Now call the callback function of requests with final status */
-	list_for_each_safe(l, n, &final_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
-		list_del_init(&cqr->list);
-		if (cqr->callback != NULL)
-			(cqr->callback)(cqr, cqr->callback_data);
-	}
-	spin_lock_irq(&device->request_queue_lock);
-	spin_lock(get_ccwdev_lock(device->cdev));
-	/* Get new request from the block device request queue */
-	__dasd_process_blk_queue(device);
+	__dasd_device_process_final_queue(device, &final_queue);
+	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	/* Now check if the head of the ccw queue needs to be started. */
-	__dasd_start_head(device);
-	spin_unlock(get_ccwdev_lock(device->cdev));
-	spin_unlock_irq(&device->request_queue_lock);
+	__dasd_device_start_head(device);
+	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	dasd_put_device(device);
 }
 
 /*
  * Schedules a call to dasd_tasklet over the device tasklet.
  */
-void
-dasd_schedule_bh(struct dasd_device * device)
+void dasd_schedule_device_bh(struct dasd_device *device)
 {
 	/* Protect against rescheduling. */
 	if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0)
@@ -1480,160 +1342,109 @@
 }
 
 /*
- * Queue a request to the head of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the head of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_head(struct dasd_ccw_req *req)
+void dasd_add_request_head(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	unsigned long flags;
 
-	device = req->device;
+	device = cqr->startdev;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	req->status = DASD_CQR_QUEUED;
-	req->device = device;
-	list_add(&req->list, &device->ccw_queue);
+	cqr->status = DASD_CQR_QUEUED;
+	list_add(&cqr->devlist, &device->ccw_queue);
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Queue a request to the tail of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the tail of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_tail(struct dasd_ccw_req *req)
+void dasd_add_request_tail(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	unsigned long flags;
 
-	device = req->device;
+	device = cqr->startdev;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	req->status = DASD_CQR_QUEUED;
-	req->device = device;
-	list_add_tail(&req->list, &device->ccw_queue);
+	cqr->status = DASD_CQR_QUEUED;
+	list_add_tail(&cqr->devlist, &device->ccw_queue);
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Wakeup callback.
+ * Wakeup helper for the 'sleep_on' functions.
  */
-static void
-dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
+static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
 {
 	wake_up((wait_queue_head_t *) data);
 }
 
-static inline int
-_wait_for_wakeup(struct dasd_ccw_req *cqr)
+static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = ((cqr->status == DASD_CQR_DONE ||
-	       cqr->status == DASD_CQR_FAILED) &&
-	      list_empty(&cqr->list));
+	       cqr->status == DASD_CQR_NEED_ERP ||
+	       cqr->status == DASD_CQR_TERMINATED) &&
+	      list_empty(&cqr->devlist));
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and waits for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait for
+ * it's completion.
  */
-int
-dasd_sleep_on(struct dasd_ccw_req * cqr)
+int dasd_sleep_on(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
-	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	device = cqr->startdev;
 
 	init_waitqueue_head (&wait_q);
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
-	cqr->status = DASD_CQR_QUEUED;
-	list_add_tail(&cqr->list, &device->ccw_queue);
-
-	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
-
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
+	dasd_add_request_tail(cqr);
 	wait_event(wait_q, _wait_for_wakeup(cqr));
 
 	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and wait interruptible
- * for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait
+ * interruptible for it's completion.
  */
-int
-dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
-	int rc, finished;
+	int rc;
 
-	device = cqr->device;
-	spin_lock_irq(get_ccwdev_lock(device->cdev));
-
+	device = cqr->startdev;
 	init_waitqueue_head (&wait_q);
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
-	cqr->status = DASD_CQR_QUEUED;
-	list_add_tail(&cqr->list, &device->ccw_queue);
-
-	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
-	finished = 0;
-	while (!finished) {
-		rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
-		if (rc != -ERESTARTSYS) {
-			/* Request is final (done or failed) */
-			rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-			break;
-		}
-		spin_lock_irq(get_ccwdev_lock(device->cdev));
-		switch (cqr->status) {
-		case DASD_CQR_IN_IO:
-                        /* terminate runnig cqr */
-			if (device->discipline->term_IO) {
-				cqr->retries = -1;
-				device->discipline->term_IO(cqr);
-				/* wait (non-interruptible) for final status
-				 * because signal ist still pending */
-				spin_unlock_irq(get_ccwdev_lock(device->cdev));
-				wait_event(wait_q, _wait_for_wakeup(cqr));
-				spin_lock_irq(get_ccwdev_lock(device->cdev));
-				rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-				finished = 1;
-			}
-			break;
-		case DASD_CQR_QUEUED:
-			/* request  */
-			list_del_init(&cqr->list);
-			rc = -EIO;
-			finished = 1;
-			break;
-		default:
-			/* cqr with 'non-interruptable' status - just wait */
-			break;
-		}
-		spin_unlock_irq(get_ccwdev_lock(device->cdev));
+	dasd_add_request_tail(cqr);
+	rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+	if (rc == -ERESTARTSYS) {
+		dasd_cancel_req(cqr);
+		/* wait (non-interruptible) for final status */
+		wait_event(wait_q, _wait_for_wakeup(cqr));
 	}
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
@@ -1643,25 +1454,23 @@
  * and be put back to status queued, before the special request is added
  * to the head of the queue. Then the special request is waited on normally.
  */
-static inline int
-_dasd_term_running_cqr(struct dasd_device *device)
+static inline int _dasd_term_running_cqr(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
 	if (list_empty(&device->ccw_queue))
 		return 0;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	return device->discipline->term_IO(cqr);
 }
 
-int
-dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = _dasd_term_running_cqr(device);
 	if (rc) {
@@ -1673,17 +1482,17 @@
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
 	cqr->status = DASD_CQR_QUEUED;
-	list_add(&cqr->list, &device->ccw_queue);
+	list_add(&cqr->devlist, &device->ccw_queue);
 
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
 	wait_event(wait_q, _wait_for_wakeup(cqr));
 
 	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
@@ -1692,11 +1501,14 @@
  * This is useful to timeout requests. The request will be
  * terminated if it is currently in i/o.
  * Returns 1 if the request has been terminated.
+ *	   0 if there was no need to terminate the request (not started yet)
+ *	   negative error code if termination failed
+ * Cancellation of a request is an asynchronous operation! The calling
+ * function has to wait until the request is properly returned via callback.
  */
-int
-dasd_cancel_req(struct dasd_ccw_req *cqr)
+int dasd_cancel_req(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	unsigned long flags;
 	int rc;
 
@@ -1704,74 +1516,453 @@
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	switch (cqr->status) {
 	case DASD_CQR_QUEUED:
-		/* request was not started - just set to failed */
-		cqr->status = DASD_CQR_FAILED;
+		/* request was not started - just set to cleared */
+		cqr->status = DASD_CQR_CLEARED;
 		break;
 	case DASD_CQR_IN_IO:
 		/* request in IO - terminate IO and release again */
-		if (device->discipline->term_IO(cqr) != 0)
-			/* what to do if unable to terminate ??????
-			   e.g. not _IN_IO */
-			cqr->status = DASD_CQR_FAILED;
-		cqr->stopclk = get_clock();
-		rc = 1;
+		rc = device->discipline->term_IO(cqr);
+		if (rc) {
+			DEV_MESSAGE(KERN_ERR, device,
+				    "dasd_cancel_req is unable "
+				    " to terminate request %p, rc = %d",
+				    cqr, rc);
+		} else {
+			cqr->stopclk = get_clock();
+			rc = 1;
+		}
 		break;
-	case DASD_CQR_DONE:
-	case DASD_CQR_FAILED:
-		/* already finished - do nothing */
+	default: /* already finished or clear pending - do nothing */
 		break;
-	default:
-		DEV_MESSAGE(KERN_ALERT, device,
-			    "invalid status %02x in request",
-			    cqr->status);
-		BUG();
-
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
+	return rc;
+}
+
+
+/*
+ * SECTION: Operations of the dasd_block layer.
+ */
+
+/*
+ * Timeout function for dasd_block. This is used when the block layer
+ * is waiting for something that may not come reliably, (e.g. a state
+ * change interrupt)
+ */
+static void dasd_block_timeout(unsigned long ptr)
+{
+	unsigned long flags;
+	struct dasd_block *block;
+
+	block = (struct dasd_block *) ptr;
+	spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
+	/* re-activate request queue */
+	block->base->stopped &= ~DASD_STOPPED_PENDING;
+	spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
+	dasd_schedule_block_bh(block);
+}
+
+/*
+ * Setup timeout for a dasd_block in jiffies.
+ */
+void dasd_block_set_timer(struct dasd_block *block, int expires)
+{
+	if (expires == 0) {
+		if (timer_pending(&block->timer))
+			del_timer(&block->timer);
+		return;
+	}
+	if (timer_pending(&block->timer)) {
+		if (mod_timer(&block->timer, jiffies + expires))
+			return;
+	}
+	block->timer.function = dasd_block_timeout;
+	block->timer.data = (unsigned long) block;
+	block->timer.expires = jiffies + expires;
+	add_timer(&block->timer);
+}
+
+/*
+ * Clear timeout for a dasd_block.
+ */
+void dasd_block_clear_timer(struct dasd_block *block)
+{
+	if (timer_pending(&block->timer))
+		del_timer(&block->timer);
+}
+
+/*
+ * posts the buffer_cache about a finalized request
+ */
+static inline void dasd_end_request(struct request *req, int uptodate)
+{
+	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+		BUG();
+	add_disk_randomness(req->rq_disk);
+	end_that_request_last(req, uptodate);
+}
+
+/*
+ * Process finished error recovery ccw.
+ */
+static inline void __dasd_block_process_erp(struct dasd_block *block,
+					    struct dasd_ccw_req *cqr)
+{
+	dasd_erp_fn_t erp_fn;
+	struct dasd_device *device = block->base;
+
+	if (cqr->status == DASD_CQR_DONE)
+		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
+	else
+		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+	erp_fn = device->discipline->erp_postaction(cqr);
+	erp_fn(cqr);
+}
+
+/*
+ * Fetch requests from the block device queue.
+ */
+static void __dasd_process_request_queue(struct dasd_block *block)
+{
+	struct request_queue *queue;
+	struct request *req;
+	struct dasd_ccw_req *cqr;
+	struct dasd_device *basedev;
+	unsigned long flags;
+	queue = block->request_queue;
+	basedev = block->base;
+	/* No queue ? Then there is nothing to do. */
+	if (queue == NULL)
+		return;
+
+	/*
+	 * We requeue request from the block device queue to the ccw
+	 * queue only in two states. In state DASD_STATE_READY the
+	 * partition detection is done and we need to requeue requests
+	 * for that. State DASD_STATE_ONLINE is normal block device
+	 * operation.
+	 */
+	if (basedev->state < DASD_STATE_READY)
+		return;
+	/* Now we try to fetch requests from the request queue */
+	while (!blk_queue_plugged(queue) &&
+	       elv_next_request(queue)) {
+
+		req = elv_next_request(queue);
+
+		if (basedev->features & DASD_FEATURE_READONLY &&
+		    rq_data_dir(req) == WRITE) {
+			DBF_DEV_EVENT(DBF_ERR, basedev,
+				      "Rejecting write request %p",
+				      req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, 0);
+			continue;
+		}
+		cqr = basedev->discipline->build_cp(basedev, block, req);
+		if (IS_ERR(cqr)) {
+			if (PTR_ERR(cqr) == -EBUSY)
+				break;	/* normal end condition */
+			if (PTR_ERR(cqr) == -ENOMEM)
+				break;	/* terminate request queue loop */
+			if (PTR_ERR(cqr) == -EAGAIN) {
+				/*
+				 * The current request cannot be build right
+				 * now, we have to try later. If this request
+				 * is the head-of-queue we stop the device
+				 * for 1/2 second.
+				 */
+				if (!list_empty(&block->ccw_queue))
+					break;
+				spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
+				basedev->stopped |= DASD_STOPPED_PENDING;
+				spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
+				dasd_block_set_timer(block, HZ/2);
+				break;
+			}
+			DBF_DEV_EVENT(DBF_ERR, basedev,
+				      "CCW creation failed (rc=%ld) "
+				      "on request %p",
+				      PTR_ERR(cqr), req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, 0);
+			continue;
+		}
+		/*
+		 *  Note: callback is set to dasd_return_cqr_cb in
+		 * __dasd_block_start_head to cover erp requests as well
+		 */
+		cqr->callback_data = (void *) req;
+		cqr->status = DASD_CQR_FILLED;
+		blkdev_dequeue_request(req);
+		list_add_tail(&cqr->blocklist, &block->ccw_queue);
+		dasd_profile_start(block, cqr, req);
+	}
+}
+
+static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
+{
+	struct request *req;
+	int status;
+
+	req = (struct request *) cqr->callback_data;
+	dasd_profile_end(cqr->block, cqr, req);
+	status = cqr->memdev->discipline->free_cp(cqr, req);
+	dasd_end_request(req, status);
+}
+
+/*
+ * Process ccw request queue.
+ */
+static void __dasd_process_block_ccw_queue(struct dasd_block *block,
+					   struct list_head *final_queue)
+{
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+	dasd_erp_fn_t erp_fn;
+	unsigned long flags;
+	struct dasd_device *base = block->base;
+
+restart:
+	/* Process request with final status. */
+	list_for_each_safe(l, n, &block->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+		if (cqr->status != DASD_CQR_DONE &&
+		    cqr->status != DASD_CQR_FAILED &&
+		    cqr->status != DASD_CQR_NEED_ERP &&
+		    cqr->status != DASD_CQR_TERMINATED)
+			continue;
+
+		if (cqr->status == DASD_CQR_TERMINATED) {
+			base->discipline->handle_terminated_request(cqr);
+			goto restart;
+		}
+
+		/*  Process requests that may be recovered */
+		if (cqr->status == DASD_CQR_NEED_ERP) {
+			if (cqr->irb.esw.esw0.erw.cons &&
+			    test_bit(DASD_CQR_FLAGS_USE_ERP,
+				     &cqr->flags)) {
+				erp_fn = base->discipline->erp_action(cqr);
+				erp_fn(cqr);
+			}
+			goto restart;
+		}
+
+		/* First of all call extended error reporting. */
+		if (dasd_eer_enabled(base) &&
+		    cqr->status == DASD_CQR_FAILED) {
+			dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
+
+			/* restart request  */
+			cqr->status = DASD_CQR_FILLED;
+			cqr->retries = 255;
+			spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+			base->stopped |= DASD_STOPPED_QUIESCE;
+			spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
+					       flags);
+			goto restart;
+		}
+
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_block_process_erp(block, cqr);
+			goto restart;
+		}
+
+		/* Rechain finished requests to final queue */
+		cqr->endclk = get_clock();
+		list_move_tail(&cqr->blocklist, final_queue);
+	}
+}
+
+static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data)
+{
+	dasd_schedule_block_bh(cqr->block);
+}
+
+static void __dasd_block_start_head(struct dasd_block *block)
+{
+	struct dasd_ccw_req *cqr;
+
+	if (list_empty(&block->ccw_queue))
+		return;
+	/* We allways begin with the first requests on the queue, as some
+	 * of previously started requests have to be enqueued on a
+	 * dasd_device again for error recovery.
+	 */
+	list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
+		if (cqr->status != DASD_CQR_FILLED)
+			continue;
+		/* Non-temporary stop condition will trigger fail fast */
+		if (block->base->stopped & ~DASD_STOPPED_PENDING &&
+		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+		    (!dasd_eer_enabled(block->base))) {
+			cqr->status = DASD_CQR_FAILED;
+			dasd_schedule_block_bh(block);
+			continue;
+		}
+		/* Don't try to start requests if device is stopped */
+		if (block->base->stopped)
+			return;
+
+		/* just a fail safe check, should not happen */
+		if (!cqr->startdev)
+			cqr->startdev = block->base;
+
+		/* make sure that the requests we submit find their way back */
+		cqr->callback = dasd_return_cqr_cb;
+
+		dasd_add_request_tail(cqr);
+	}
+}
+
+/*
+ * Central dasd_block layer routine. Takes requests from the generic
+ * block layer request queue, creates ccw requests, enqueues them on
+ * a dasd_device and processes ccw requests that have been returned.
+ */
+static void dasd_block_tasklet(struct dasd_block *block)
+{
+	struct list_head final_queue;
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+
+	atomic_set(&block->tasklet_scheduled, 0);
+	INIT_LIST_HEAD(&final_queue);
+	spin_lock(&block->queue_lock);
+	/* Finish off requests on ccw queue */
+	__dasd_process_block_ccw_queue(block, &final_queue);
+	spin_unlock(&block->queue_lock);
+	/* Now call the callback function of requests with final status */
+	spin_lock_irq(&block->request_queue_lock);
+	list_for_each_safe(l, n, &final_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+		list_del_init(&cqr->blocklist);
+		__dasd_cleanup_cqr(cqr);
+	}
+	spin_lock(&block->queue_lock);
+	/* Get new request from the block device request queue */
+	__dasd_process_request_queue(block);
+	/* Now check if the head of the ccw queue needs to be started. */
+	__dasd_block_start_head(block);
+	spin_unlock(&block->queue_lock);
+	spin_unlock_irq(&block->request_queue_lock);
+	dasd_put_device(block->base);
+}
+
+static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
+{
+	wake_up(&dasd_flush_wq);
+}
+
+/*
+ * Go through all request on the dasd_block request queue, cancel them
+ * on the respective dasd_device, and return them to the generic
+ * block layer.
+ */
+static int dasd_flush_block_queue(struct dasd_block *block)
+{
+	struct dasd_ccw_req *cqr, *n;
+	int rc, i;
+	struct list_head flush_queue;
+
+	INIT_LIST_HEAD(&flush_queue);
+	spin_lock_bh(&block->queue_lock);
+	rc = 0;
+restart:
+	list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
+		/* if this request currently owned by a dasd_device cancel it */
+		if (cqr->status >= DASD_CQR_QUEUED)
+			rc = dasd_cancel_req(cqr);
+		if (rc < 0)
+			break;
+		/* Rechain request (including erp chain) so it won't be
+		 * touched by the dasd_block_tasklet anymore.
+		 * Replace the callback so we notice when the request
+		 * is returned from the dasd_device layer.
+		 */
+		cqr->callback = _dasd_wake_block_flush_cb;
+		for (i = 0; cqr != NULL; cqr = cqr->refers, i++)
+			list_move_tail(&cqr->blocklist, &flush_queue);
+		if (i > 1)
+			/* moved more than one request - need to restart */
+			goto restart;
+	}
+	spin_unlock_bh(&block->queue_lock);
+	/* Now call the callback function of flushed requests */
+restart_cb:
+	list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) {
+		wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_block_process_erp(block, cqr);
+			/* restart list_for_xx loop since dasd_process_erp
+			 * might remove multiple elements */
+			goto restart_cb;
+		}
+		/* call the callback function */
+		cqr->endclk = get_clock();
+		list_del_init(&cqr->blocklist);
+		__dasd_cleanup_cqr(cqr);
+	}
 	return rc;
 }
 
 /*
- * SECTION: Block device operations (request queue, partitions, open, release).
+ * Schedules a call to dasd_tasklet over the device tasklet.
+ */
+void dasd_schedule_block_bh(struct dasd_block *block)
+{
+	/* Protect against rescheduling. */
+	if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0)
+		return;
+	/* life cycle of block is bound to it's base device */
+	dasd_get_device(block->base);
+	tasklet_hi_schedule(&block->tasklet);
+}
+
+
+/*
+ * SECTION: external block device operations
+ * (request queue handling, open, release, etc.)
  */
 
 /*
  * Dasd request queue function. Called from ll_rw_blk.c
  */
-static void
-do_dasd_request(struct request_queue * queue)
+static void do_dasd_request(struct request_queue *queue)
 {
-	struct dasd_device *device;
+	struct dasd_block *block;
 
-	device = (struct dasd_device *) queue->queuedata;
-	spin_lock(get_ccwdev_lock(device->cdev));
+	block = queue->queuedata;
+	spin_lock(&block->queue_lock);
 	/* Get new request from the block device request queue */
-	__dasd_process_blk_queue(device);
+	__dasd_process_request_queue(block);
 	/* Now check if the head of the ccw queue needs to be started. */
-	__dasd_start_head(device);
-	spin_unlock(get_ccwdev_lock(device->cdev));
+	__dasd_block_start_head(block);
+	spin_unlock(&block->queue_lock);
 }
 
 /*
  * Allocate and initialize request queue and default I/O scheduler.
  */
-static int
-dasd_alloc_queue(struct dasd_device * device)
+static int dasd_alloc_queue(struct dasd_block *block)
 {
 	int rc;
 
-	device->request_queue = blk_init_queue(do_dasd_request,
-					       &device->request_queue_lock);
-	if (device->request_queue == NULL)
+	block->request_queue = blk_init_queue(do_dasd_request,
+					       &block->request_queue_lock);
+	if (block->request_queue == NULL)
 		return -ENOMEM;
 
-	device->request_queue->queuedata = device;
+	block->request_queue->queuedata = block;
 
-	elevator_exit(device->request_queue->elevator);
-	rc = elevator_init(device->request_queue, "deadline");
+	elevator_exit(block->request_queue->elevator);
+	rc = elevator_init(block->request_queue, "deadline");
 	if (rc) {
-		blk_cleanup_queue(device->request_queue);
+		blk_cleanup_queue(block->request_queue);
 		return rc;
 	}
 	return 0;
@@ -1780,79 +1971,76 @@
 /*
  * Allocate and initialize request queue.
  */
-static void
-dasd_setup_queue(struct dasd_device * device)
+static void dasd_setup_queue(struct dasd_block *block)
 {
 	int max;
 
-	blk_queue_hardsect_size(device->request_queue, device->bp_block);
-	max = device->discipline->max_blocks << device->s2b_shift;
-	blk_queue_max_sectors(device->request_queue, max);
-	blk_queue_max_phys_segments(device->request_queue, -1L);
-	blk_queue_max_hw_segments(device->request_queue, -1L);
-	blk_queue_max_segment_size(device->request_queue, -1L);
-	blk_queue_segment_boundary(device->request_queue, -1L);
-	blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
+	blk_queue_hardsect_size(block->request_queue, block->bp_block);
+	max = block->base->discipline->max_blocks << block->s2b_shift;
+	blk_queue_max_sectors(block->request_queue, max);
+	blk_queue_max_phys_segments(block->request_queue, -1L);
+	blk_queue_max_hw_segments(block->request_queue, -1L);
+	blk_queue_max_segment_size(block->request_queue, -1L);
+	blk_queue_segment_boundary(block->request_queue, -1L);
+	blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
 }
 
 /*
  * Deactivate and free request queue.
  */
-static void
-dasd_free_queue(struct dasd_device * device)
+static void dasd_free_queue(struct dasd_block *block)
 {
-	if (device->request_queue) {
-		blk_cleanup_queue(device->request_queue);
-		device->request_queue = NULL;
+	if (block->request_queue) {
+		blk_cleanup_queue(block->request_queue);
+		block->request_queue = NULL;
 	}
 }
 
 /*
  * Flush request on the request queue.
  */
-static void
-dasd_flush_request_queue(struct dasd_device * device)
+static void dasd_flush_request_queue(struct dasd_block *block)
 {
 	struct request *req;
 
-	if (!device->request_queue)
+	if (!block->request_queue)
 		return;
 
-	spin_lock_irq(&device->request_queue_lock);
-	while ((req = elv_next_request(device->request_queue))) {
+	spin_lock_irq(&block->request_queue_lock);
+	while ((req = elv_next_request(block->request_queue))) {
 		blkdev_dequeue_request(req);
 		dasd_end_request(req, 0);
 	}
-	spin_unlock_irq(&device->request_queue_lock);
+	spin_unlock_irq(&block->request_queue_lock);
 }
 
-static int
-dasd_open(struct inode *inp, struct file *filp)
+static int dasd_open(struct inode *inp, struct file *filp)
 {
 	struct gendisk *disk = inp->i_bdev->bd_disk;
-	struct dasd_device *device = disk->private_data;
+	struct dasd_block *block = disk->private_data;
+	struct dasd_device *base = block->base;
 	int rc;
 
-        atomic_inc(&device->open_count);
-	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+	atomic_inc(&block->open_count);
+	if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
 		rc = -ENODEV;
 		goto unlock;
 	}
 
-	if (!try_module_get(device->discipline->owner)) {
+	if (!try_module_get(base->discipline->owner)) {
 		rc = -EINVAL;
 		goto unlock;
 	}
 
 	if (dasd_probeonly) {
-		DEV_MESSAGE(KERN_INFO, device, "%s",
+		DEV_MESSAGE(KERN_INFO, base, "%s",
 			    "No access to device due to probeonly mode");
 		rc = -EPERM;
 		goto out;
 	}
 
-	if (device->state <= DASD_STATE_BASIC) {
-		DBF_DEV_EVENT(DBF_ERR, device, " %s",
+	if (base->state <= DASD_STATE_BASIC) {
+		DBF_DEV_EVENT(DBF_ERR, base, " %s",
 			      " Cannot open unrecognized device");
 		rc = -ENODEV;
 		goto out;
@@ -1861,41 +2049,41 @@
 	return 0;
 
 out:
-	module_put(device->discipline->owner);
+	module_put(base->discipline->owner);
 unlock:
-	atomic_dec(&device->open_count);
+	atomic_dec(&block->open_count);
 	return rc;
 }
 
-static int
-dasd_release(struct inode *inp, struct file *filp)
+static int dasd_release(struct inode *inp, struct file *filp)
 {
 	struct gendisk *disk = inp->i_bdev->bd_disk;
-	struct dasd_device *device = disk->private_data;
+	struct dasd_block *block = disk->private_data;
 
-	atomic_dec(&device->open_count);
-	module_put(device->discipline->owner);
+	atomic_dec(&block->open_count);
+	module_put(block->base->discipline->owner);
 	return 0;
 }
 
 /*
  * Return disk geometry.
  */
-static int
-dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-	struct dasd_device *device;
+	struct dasd_block *block;
+	struct dasd_device *base;
 
-	device = bdev->bd_disk->private_data;
-	if (!device)
+	block = bdev->bd_disk->private_data;
+	base = block->base;
+	if (!block)
 		return -ENODEV;
 
-	if (!device->discipline ||
-	    !device->discipline->fill_geometry)
+	if (!base->discipline ||
+	    !base->discipline->fill_geometry)
 		return -EINVAL;
 
-	device->discipline->fill_geometry(device, geo);
-	geo->start = get_start_sect(bdev) >> device->s2b_shift;
+	base->discipline->fill_geometry(block, geo);
+	geo->start = get_start_sect(bdev) >> block->s2b_shift;
 	return 0;
 }
 
@@ -1909,6 +2097,9 @@
 	.getgeo		= dasd_getgeo,
 };
 
+/*******************************************************************************
+ * end of block device operations
+ */
 
 static void
 dasd_exit(void)
@@ -1937,9 +2128,8 @@
  * Initial attempt at a probe function. this can be simplified once
  * the other detection code is gone.
  */
-int
-dasd_generic_probe (struct ccw_device *cdev,
-		    struct dasd_discipline *discipline)
+int dasd_generic_probe(struct ccw_device *cdev,
+		       struct dasd_discipline *discipline)
 {
 	int ret;
 
@@ -1969,19 +2159,20 @@
 		ret = ccw_device_set_online(cdev);
 	if (ret)
 		printk(KERN_WARNING
-		       "dasd_generic_probe: could not initially online "
-		       "ccw-device %s\n", cdev->dev.bus_id);
-	return ret;
+		       "dasd_generic_probe: could not initially "
+		       "online ccw-device %s; return code: %d\n",
+		       cdev->dev.bus_id, ret);
+	return 0;
 }
 
 /*
  * This will one day be called from a global not_oper handler.
  * It is also used by driver_unregister during module unload.
  */
-void
-dasd_generic_remove (struct ccw_device *cdev)
+void dasd_generic_remove(struct ccw_device *cdev)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 
 	cdev->handler = NULL;
 
@@ -2001,7 +2192,15 @@
 	 */
 	dasd_set_target_state(device, DASD_STATE_NEW);
 	/* dasd_delete_device destroys the device reference. */
+	block = device->block;
+	device->block = NULL;
 	dasd_delete_device(device);
+	/*
+	 * life cycle of block is bound to device, so delete it after
+	 * device was safely removed
+	 */
+	if (block)
+		dasd_free_block(block);
 }
 
 /*
@@ -2009,10 +2208,8 @@
  * the device is detected for the first time and is supposed to be used
  * or the user has started activation through sysfs.
  */
-int
-dasd_generic_set_online (struct ccw_device *cdev,
-			 struct dasd_discipline *base_discipline)
-
+int dasd_generic_set_online(struct ccw_device *cdev,
+			    struct dasd_discipline *base_discipline)
 {
 	struct dasd_discipline *discipline;
 	struct dasd_device *device;
@@ -2048,6 +2245,7 @@
 	device->base_discipline = base_discipline;
 	device->discipline = discipline;
 
+	/* check_device will allocate block device if necessary */
 	rc = discipline->check_device(device);
 	if (rc) {
 		printk (KERN_WARNING
@@ -2067,6 +2265,8 @@
 			cdev->dev.bus_id);
 		rc = -ENODEV;
 		dasd_set_target_state(device, DASD_STATE_NEW);
+		if (device->block)
+			dasd_free_block(device->block);
 		dasd_delete_device(device);
 	} else
 		pr_debug("dasd_generic device %s found\n",
@@ -2081,10 +2281,10 @@
 	return rc;
 }
 
-int
-dasd_generic_set_offline (struct ccw_device *cdev)
+int dasd_generic_set_offline(struct ccw_device *cdev)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 	int max_count, open_count;
 
 	device = dasd_device_from_cdev(cdev);
@@ -2101,30 +2301,39 @@
 	 * the blkdev_get in dasd_scan_partitions. We are only interested
 	 * in the other openers.
 	 */
-	max_count = device->bdev ? 0 : -1;
-	open_count = (int) atomic_read(&device->open_count);
-	if (open_count > max_count) {
-		if (open_count > 0)
-			printk (KERN_WARNING "Can't offline dasd device with "
-				"open count = %i.\n",
-				open_count);
-		else
-			printk (KERN_WARNING "%s",
-				"Can't offline dasd device due to internal "
-				"use\n");
-		clear_bit(DASD_FLAG_OFFLINE, &device->flags);
-		dasd_put_device(device);
-		return -EBUSY;
+	if (device->block) {
+		struct dasd_block *block = device->block;
+		max_count = block->bdev ? 0 : -1;
+		open_count = (int) atomic_read(&block->open_count);
+		if (open_count > max_count) {
+			if (open_count > 0)
+				printk(KERN_WARNING "Can't offline dasd "
+				       "device with open count = %i.\n",
+				       open_count);
+			else
+				printk(KERN_WARNING "%s",
+				       "Can't offline dasd device due "
+				       "to internal use\n");
+			clear_bit(DASD_FLAG_OFFLINE, &device->flags);
+			dasd_put_device(device);
+			return -EBUSY;
+		}
 	}
 	dasd_set_target_state(device, DASD_STATE_NEW);
 	/* dasd_delete_device destroys the device reference. */
+	block = device->block;
+	device->block = NULL;
 	dasd_delete_device(device);
-
+	/*
+	 * life cycle of block is bound to device, so delete it after
+	 * device was safely removed
+	 */
+	if (block)
+		dasd_free_block(block);
 	return 0;
 }
 
-int
-dasd_generic_notify(struct ccw_device *cdev, int event)
+int dasd_generic_notify(struct ccw_device *cdev, int event)
 {
 	struct dasd_device *device;
 	struct dasd_ccw_req *cqr;
@@ -2145,27 +2354,22 @@
 		if (device->state < DASD_STATE_BASIC)
 			break;
 		/* Device is active. We want to keep it. */
-		if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
-			list_for_each_entry(cqr, &device->ccw_queue, list)
-				if (cqr->status == DASD_CQR_IN_IO)
-					cqr->status = DASD_CQR_FAILED;
-			device->stopped |= DASD_STOPPED_DC_EIO;
-		} else {
-			list_for_each_entry(cqr, &device->ccw_queue, list)
-				if (cqr->status == DASD_CQR_IN_IO) {
-					cqr->status = DASD_CQR_QUEUED;
-					cqr->retries++;
-				}
-			device->stopped |= DASD_STOPPED_DC_WAIT;
-			dasd_set_timer(device, 0);
-		}
-		dasd_schedule_bh(device);
+		list_for_each_entry(cqr, &device->ccw_queue, devlist)
+			if (cqr->status == DASD_CQR_IN_IO) {
+				cqr->status = DASD_CQR_QUEUED;
+				cqr->retries++;
+			}
+		device->stopped |= DASD_STOPPED_DC_WAIT;
+		dasd_device_clear_timer(device);
+		dasd_schedule_device_bh(device);
 		ret = 1;
 		break;
 	case CIO_OPER:
 		/* FIXME: add a sanity check. */
-		device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
-		dasd_schedule_bh(device);
+		device->stopped &= ~DASD_STOPPED_DC_WAIT;
+		dasd_schedule_device_bh(device);
+		if (device->block)
+			dasd_schedule_block_bh(device->block);
 		ret = 1;
 		break;
 	}
@@ -2195,7 +2399,8 @@
 	ccw->cda = (__u32)(addr_t)rdc_buffer;
 	ccw->count = rdc_buffer_size;
 
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->expires = 10*HZ;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	cqr->retries = 2;
@@ -2217,13 +2422,12 @@
 		return PTR_ERR(cqr);
 
 	ret = dasd_sleep_on(cqr);
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
 
-static int __init
-dasd_init(void)
+static int __init dasd_init(void)
 {
 	int rc;
 
@@ -2231,7 +2435,7 @@
 	init_waitqueue_head(&dasd_flush_wq);
 
 	/* register 'common' DASD debug area, used for all DBF_XXX calls */
-	dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
+	dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
 	if (dasd_debug_area == NULL) {
 		rc = -ENOMEM;
 		goto failed;
@@ -2277,15 +2481,18 @@
 EXPORT_SYMBOL(dasd_add_request_head);
 EXPORT_SYMBOL(dasd_add_request_tail);
 EXPORT_SYMBOL(dasd_cancel_req);
-EXPORT_SYMBOL(dasd_clear_timer);
+EXPORT_SYMBOL(dasd_device_clear_timer);
+EXPORT_SYMBOL(dasd_block_clear_timer);
 EXPORT_SYMBOL(dasd_enable_device);
 EXPORT_SYMBOL(dasd_int_handler);
 EXPORT_SYMBOL(dasd_kfree_request);
 EXPORT_SYMBOL(dasd_kick_device);
 EXPORT_SYMBOL(dasd_kmalloc_request);
-EXPORT_SYMBOL(dasd_schedule_bh);
+EXPORT_SYMBOL(dasd_schedule_device_bh);
+EXPORT_SYMBOL(dasd_schedule_block_bh);
 EXPORT_SYMBOL(dasd_set_target_state);
-EXPORT_SYMBOL(dasd_set_timer);
+EXPORT_SYMBOL(dasd_device_set_timer);
+EXPORT_SYMBOL(dasd_block_set_timer);
 EXPORT_SYMBOL(dasd_sfree_request);
 EXPORT_SYMBOL(dasd_sleep_on);
 EXPORT_SYMBOL(dasd_sleep_on_immediatly);
@@ -2299,4 +2506,7 @@
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-
+EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
+EXPORT_SYMBOL_GPL(dasd_flush_device_queue);
+EXPORT_SYMBOL_GPL(dasd_alloc_block);
+EXPORT_SYMBOL_GPL(dasd_free_block);
diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
deleted file mode 100644
index 1ddab89..0000000
--- a/drivers/s390/block/dasd_3370_erp.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_3370_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(3370)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_3370_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 3370 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	char *sense = irb->ecw;
-
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-	if (sense[0] & 0x80) {	/* CMD reject */
-		return dasd_era_fatal;
-	}
-	if (sense[0] & 0x40) {	/* Drive offline */
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x20) {	/* Bus out parity */
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x10) {	/* equipment check */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x08) {	/* data check */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x04) {	/* overrun */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[1] & 0x40) {	/* invalid blocksize */
-		return dasd_era_fatal;
-	}
-	if (sense[1] & 0x04) {	/* file protected */
-		return dasd_era_recover;
-	}
-	if (sense[1] & 0x01) {	/* operation incomplete */
-		return dasd_era_recover;
-	}
-	if (sense[2] & 0x80) {	/* check data erroor */
-		return dasd_era_recover;
-	}
-	if (sense[2] & 0x10) {	/* Env. data present */
-		return dasd_era_recover;
-	}
-	/* examine the 24 byte sense data */
-	return dasd_era_recover;
-
-}				/* END dasd_3370_erp_examine */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 5b7385e..c361ab6 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -26,158 +26,6 @@
 
 /*
  *****************************************************************************
- * SECTION ERP EXAMINATION
- *****************************************************************************
- */
-
-/*
- * DASD_3990_ERP_EXAMINE_24
- *
- * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   Each bit configuration leading to an action code 2 (Exit with
- *   programming error or unusual condition indication)
- *   are handled as fatal errors.
- *
- *   All other configurations are handled as recoverable errors.
- *
- * RETURN VALUES
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
-{
-
-	struct dasd_device *device = cqr->device;
-
-	/* check for 'Command Reject' */
-	if ((sense[0] & SNS0_CMD_REJECT) &&
-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "EXAMINE 24: Command Reject detected - "
-			    "fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* check for 'Invalid Track Format' */
-	if ((sense[1] & SNS1_INV_TRACK_FORMAT) &&
-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "EXAMINE 24: Invalid Track Format detected "
-			    "- fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* check for 'No Record Found' */
-	if (sense[1] & SNS1_NO_REC_FOUND) {
-
-                /* FIXME: fatal error ?!? */
-		DEV_MESSAGE(KERN_ERR, device,
-			    "EXAMINE 24: No Record Found detected %s",
-                            device->state <= DASD_STATE_BASIC ?
-			    " " : "- fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* return recoverable for all others */
-	return dasd_era_recover;
-}				/* END dasd_3990_erp_examine_24 */
-
-/*
- * DASD_3990_ERP_EXAMINE_32
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recoverable error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for recoverable others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
-{
-
-	struct dasd_device *device = cqr->device;
-
-	switch (sense[25]) {
-	case 0x00:
-		return dasd_era_none;
-
-	case 0x01:
-		DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
-
-		return dasd_era_fatal;
-
-	default:
-
-		return dasd_era_recover;
-	}
-
-}				/* end dasd_3990_erp_examine_32 */
-
-/*
- * DASD_3990_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3990 Storage Control  Reference' manual
- *   'Chapter 7. Error Recovery Procedures'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-
-	char *sense = irb->ecw;
-	dasd_era_t era = dasd_era_recover;
-	struct dasd_device *device = cqr->device;
-
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	/* distinguish between 24 and 32 byte sense data */
-	if (sense[27] & DASD_SENSE_BIT_0) {
-
-		era = dasd_3990_erp_examine_24(cqr, sense);
-
-	} else {
-
-		era = dasd_3990_erp_examine_32(cqr, sense);
-
-	}
-
-	/* log the erp chain if fatal error occurred */
-	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
-		dasd_log_sense(cqr, irb);
-	}
-
-	return era;
-
-}				/* END dasd_3990_erp_examine */
-
-/*
- *****************************************************************************
  * SECTION ERP HANDLING
  *****************************************************************************
  */
@@ -206,7 +54,7 @@
 {
 	struct dasd_ccw_req *cqr = erp->refers;
 
-	dasd_free_erp_request(erp, erp->device);
+	dasd_free_erp_request(erp, erp->memdev);
 	cqr->status = final_status;
 	return cqr;
 
@@ -224,15 +72,17 @@
 dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
+	unsigned long flags;
 
 	DEV_MESSAGE(KERN_INFO, device,
 		    "blocking request queue for %is", expires/HZ);
 
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	device->stopped |= DASD_STOPPED_PENDING;
-	erp->status = DASD_CQR_QUEUED;
-
-	dasd_set_timer(device, expires);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	erp->status = DASD_CQR_FILLED;
+	dasd_block_set_timer(device->block, expires);
 }
 
 /*
@@ -251,7 +101,7 @@
 dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function */
 	/* and retry once without blocking queue		 */
@@ -292,11 +142,14 @@
 static void
 dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 {
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	__u8 opm;
+	unsigned long flags;
 
 	/* try alternate valid path */
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	opm = ccw_device_get_path_mask(device->cdev);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	//FIXME: start with get_opm ?
 	if (erp->lpm == 0)
 		erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
@@ -309,9 +162,8 @@
 			    "try alternate lpm=%x (lpum=%x / opm=%x)",
 			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
 
-		/* reset status to queued to handle the request again... */
-		if (erp->status > DASD_CQR_QUEUED)
-			erp->status = DASD_CQR_QUEUED;
+		/* reset status to submit the request again... */
+		erp->status = DASD_CQR_FILLED;
 		erp->retries = 1;
 	} else {
 		DEV_MESSAGE(KERN_ERR, device,
@@ -320,8 +172,7 @@
 			    erp->irb.esw.esw0.sublog.lpum, opm);
 
 		/* post request with permanent error */
-		if (erp->status > DASD_CQR_QUEUED)
-			erp->status = DASD_CQR_FAILED;
+		erp->status = DASD_CQR_FAILED;
 	}
 }				/* end dasd_3990_erp_alternate_path */
 
@@ -344,14 +195,14 @@
 dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	struct DCTL_data *DCTL_data;
 	struct ccw1 *ccw;
 	struct dasd_ccw_req *dctl_cqr;
 
 	dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
-					  sizeof (struct DCTL_data),
-					  erp->device);
+					  sizeof(struct DCTL_data),
+					  device);
 	if (IS_ERR(dctl_cqr)) {
 		DEV_MESSAGE(KERN_ERR, device, "%s",
 			    "Unable to allocate DCTL-CQR");
@@ -365,13 +216,14 @@
 	DCTL_data->modifier = modifier;
 
 	ccw = dctl_cqr->cpaddr;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = CCW_CMD_DCTL;
 	ccw->count = 4;
 	ccw->cda = (__u32)(addr_t) DCTL_data;
 	dctl_cqr->function = dasd_3990_erp_DCTL;
 	dctl_cqr->refers = erp;
-	dctl_cqr->device = erp->device;
+	dctl_cqr->startdev = device;
+	dctl_cqr->memdev = device;
 	dctl_cqr->magic = erp->magic;
 	dctl_cqr->expires = 5 * 60 * HZ;
 	dctl_cqr->retries = 2;
@@ -435,7 +287,7 @@
 dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function    */
 	/* and retry once without waiting for state change pending  */
@@ -472,7 +324,7 @@
 				     "redriving request immediately, "
 				     "%d retries left",
 				     erp->retries);
-			erp->status = DASD_CQR_QUEUED;
+			erp->status = DASD_CQR_FILLED;
 		}
 	}
 
@@ -530,7 +382,7 @@
 dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	char msg_format = (sense[7] & 0xF0);
 	char msg_no = (sense[7] & 0x0F);
 
@@ -1157,7 +1009,7 @@
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_com_rej;
 
@@ -1198,7 +1050,7 @@
 dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function */
 	/* and retry once without blocking queue		 */
@@ -1237,7 +1089,7 @@
 dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_equip_check;
 
@@ -1279,7 +1131,6 @@
 
 		erp = dasd_3990_erp_action_5(erp);
 	}
-
 	return erp;
 
 }				/* end dasd_3990_erp_equip_check */
@@ -1299,7 +1150,7 @@
 dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_data_check;
 
@@ -1358,7 +1209,7 @@
 dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_overrun;
 
@@ -1387,7 +1238,7 @@
 dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_inv_format;
 
@@ -1403,8 +1254,7 @@
 
 	} else {
 		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "Invalid Track Format - Fatal error should have "
-			    "been handled within the interrupt handler");
+			    "Invalid Track Format - Fatal error");
 
 		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 	}
@@ -1428,7 +1278,7 @@
 dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s",
 		    "End-of-Cylinder - must never happen");
@@ -1453,7 +1303,7 @@
 dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_env_data;
 
@@ -1463,11 +1313,9 @@
 
 	/* don't retry on disabled interface */
 	if (sense[7] != 0x0F) {
-
 		erp = dasd_3990_erp_action_4(erp, sense);
 	} else {
-
-		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
+		erp->status = DASD_CQR_FILLED;
 	}
 
 	return erp;
@@ -1490,11 +1338,10 @@
 dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s",
-		    "No Record Found - Fatal error should "
-		    "have been handled within the interrupt handler");
+		    "No Record Found - Fatal error ");
 
 	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 
@@ -1517,7 +1364,7 @@
 dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
 
@@ -1526,6 +1373,43 @@
 }				/* end dasd_3990_erp_file_prot */
 
 /*
+ * DASD_3990_ERP_INSPECT_ALIAS
+ *
+ * DESCRIPTION
+ *   Checks if the original request was started on an alias device.
+ *   If yes, it modifies the original and the erp request so that
+ *   the erp request can be started on a base device.
+ *
+ * PARAMETER
+ *   erp		pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp		pointer to the modified ERP, or NULL
+ */
+
+static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
+						struct dasd_ccw_req *erp)
+{
+	struct dasd_ccw_req *cqr = erp->refers;
+
+	if (cqr->block &&
+	    (cqr->block->base != cqr->startdev)) {
+		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
+			DEV_MESSAGE(KERN_ERR, cqr->startdev,
+				    "ERP on alias device for request %p,"
+				    " recover on base device %s", cqr,
+				    cqr->block->base->cdev->dev.bus_id);
+		}
+		dasd_eckd_reset_ccw_to_base_io(cqr);
+		erp->startdev = cqr->block->base;
+		erp->function = dasd_3990_erp_inspect_alias;
+		return erp;
+	} else
+		return NULL;
+}
+
+
+/*
  * DASD_3990_ERP_INSPECT_24
  *
  * DESCRIPTION
@@ -1623,7 +1507,7 @@
 dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->retries = 256;
 	erp->function = dasd_3990_erp_action_10_32;
@@ -1657,13 +1541,14 @@
 dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 	__u32 cpa = 0;
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *erp;
 	struct DE_eckd_data *DE_data;
+	struct PFX_eckd_data *PFX_data;
 	char *LO_data;		/* LO_eckd_data_t */
-	struct ccw1 *ccw;
+	struct ccw1 *ccw, *oldccw;
 
 	DEV_MESSAGE(KERN_DEBUG, device, "%s",
 		    "Write not finished because of unexpected condition");
@@ -1702,8 +1587,8 @@
 	/* Build new ERP request including DE/LO */
 	erp = dasd_alloc_erp_request((char *) &cqr->magic,
 				     2 + 1,/* DE/LO + TIC */
-				     sizeof (struct DE_eckd_data) +
-				     sizeof (struct LO_eckd_data), device);
+				     sizeof(struct DE_eckd_data) +
+				     sizeof(struct LO_eckd_data), device);
 
 	if (IS_ERR(erp)) {
 		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
@@ -1712,10 +1597,16 @@
 
 	/* use original DE */
 	DE_data = erp->data;
-	memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data));
+	oldccw = cqr->cpaddr;
+	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
+		PFX_data = cqr->data;
+		memcpy(DE_data, &PFX_data->define_extend,
+		       sizeof(struct DE_eckd_data));
+	} else
+		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
 
 	/* create LO */
-	LO_data = erp->data + sizeof (struct DE_eckd_data);
+	LO_data = erp->data + sizeof(struct DE_eckd_data);
 
 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1748,7 +1639,7 @@
 
 	/* create DE ccw */
 	ccw = erp->cpaddr;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 16;
@@ -1756,7 +1647,7 @@
 
 	/* create LO ccw */
 	ccw++;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 16;
@@ -1770,7 +1661,8 @@
 	/* fill erp related fields */
 	erp->function = dasd_3990_erp_action_1B_32;
 	erp->refers = default_erp->refers;
-	erp->device = device;
+	erp->startdev = device;
+	erp->memdev = device;
 	erp->magic = default_erp->magic;
 	erp->expires = 0;
 	erp->retries = 256;
@@ -1803,7 +1695,7 @@
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 {
 
-	struct dasd_device *device = previous_erp->device;
+	struct dasd_device *device = previous_erp->startdev;
 	__u32 cpa = 0;
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *erp;
@@ -1827,7 +1719,7 @@
 		DEV_MESSAGE(KERN_DEBUG, device, "%s",
 			    "Imprecise ending is set - just retry");
 
-		previous_erp->status = DASD_CQR_QUEUED;
+		previous_erp->status = DASD_CQR_FILLED;
 
 		return previous_erp;
 	}
@@ -1850,7 +1742,7 @@
 	erp = previous_erp;
 
 	/* update the LO with the new returned sense data  */
-	LO_data = erp->data + sizeof (struct DE_eckd_data);
+	LO_data = erp->data + sizeof(struct DE_eckd_data);
 
 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1889,7 +1781,7 @@
 	ccw++;			/* addr of TIC ccw */
 	ccw->cda = cpa;
 
-	erp->status = DASD_CQR_QUEUED;
+	erp->status = DASD_CQR_FILLED;
 
 	return erp;
 
@@ -1968,9 +1860,7 @@
 			 * try further actions. */
 
 			erp->lpm = 0;
-
-			erp->status = DASD_CQR_ERROR;
-
+			erp->status = DASD_CQR_NEED_ERP;
 		}
 	}
 
@@ -2047,7 +1937,7 @@
 	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
 
 		/* set to suspended duplex state then restart */
-		struct dasd_device *device = erp->device;
+		struct dasd_device *device = erp->startdev;
 
 		DEV_MESSAGE(KERN_ERR, device, "%s",
 			    "Set device to suspended duplex state should be "
@@ -2081,28 +1971,26 @@
 {
 
 	if ((erp->function == dasd_3990_erp_compound_retry) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		dasd_3990_erp_compound_path(erp, sense);
 	}
 
 	if ((erp->function == dasd_3990_erp_compound_path) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		erp = dasd_3990_erp_compound_code(erp, sense);
 	}
 
 	if ((erp->function == dasd_3990_erp_compound_code) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		dasd_3990_erp_compound_config(erp, sense);
 	}
 
 	/* if no compound action ERP specified, the request failed */
-	if (erp->status == DASD_CQR_ERROR) {
-
+	if (erp->status == DASD_CQR_NEED_ERP)
 		erp->status = DASD_CQR_FAILED;
-	}
 
 	return erp;
 
@@ -2127,7 +2015,7 @@
 dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_inspect_32;
 
@@ -2149,8 +2037,7 @@
 
 		case 0x01:	/* fatal error */
 			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Fatal error should have been "
-				    "handled within the interrupt handler");
+				    "Retry not recommended - Fatal error");
 
 			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 			break;
@@ -2253,6 +2140,11 @@
 	/* already set up new ERP !			      */
 	char *sense = erp->refers->irb.ecw;
 
+	/* if this problem occured on an alias retry on base */
+	erp_new = dasd_3990_erp_inspect_alias(erp);
+	if (erp_new)
+		return erp_new;
+
 	/* distinguish between 24 and 32 byte sense data */
 	if (sense[27] & DASD_SENSE_BIT_0) {
 
@@ -2287,13 +2179,13 @@
 dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 {
 
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	struct ccw1 *ccw;
 
 	/* allocate additional request block */
 	struct dasd_ccw_req *erp;
 
-	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device);
+	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device);
 	if (IS_ERR(erp)) {
                 if (cqr->retries <= 0) {
 		        DEV_MESSAGE(KERN_ERR, device, "%s",
@@ -2305,7 +2197,7 @@
                                      "Unable to allocate ERP request "
 				     "(%i retries left)",
                                      cqr->retries);
-			dasd_set_timer(device, (HZ << 3));
+			dasd_block_set_timer(device->block, (HZ << 3));
                 }
 		return cqr;
 	}
@@ -2319,7 +2211,9 @@
 	ccw->cda      = (long)(cqr->cpaddr);
 	erp->function = dasd_3990_erp_add_erp;
 	erp->refers   = cqr;
-	erp->device   = cqr->device;
+	erp->startdev = device;
+	erp->memdev   = device;
+	erp->block    = cqr->block;
 	erp->magic    = cqr->magic;
 	erp->expires  = 0;
 	erp->retries  = 256;
@@ -2466,7 +2360,7 @@
 dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	char *sense = erp->irb.ecw;
 
 	/* check for 24 byte sense ERP */
@@ -2557,7 +2451,7 @@
 			       struct dasd_ccw_req *erp)
 {
 
-	struct dasd_device *device = erp_head->device;
+	struct dasd_device *device = erp_head->startdev;
 	struct dasd_ccw_req *erp_done = erp_head;	/* finished req */
 	struct dasd_ccw_req *erp_free = NULL;	/* req to be freed */
 
@@ -2569,13 +2463,13 @@
 			      "original request was lost\n");
 
 		/* remove the request from the device queue */
-		list_del(&erp_done->list);
+		list_del(&erp_done->blocklist);
 
 		erp_free = erp_done;
 		erp_done = erp_done->refers;
 
 		/* free the finished erp request */
-		dasd_free_erp_request(erp_free, erp_free->device);
+		dasd_free_erp_request(erp_free, erp_free->memdev);
 
 	}			/* end while */
 
@@ -2603,7 +2497,7 @@
 				    erp->retries, erp);
 
 			/* handle the request again... */
-			erp->status = DASD_CQR_QUEUED;
+			erp->status = DASD_CQR_FILLED;
 		}
 
 	} else {
@@ -2620,7 +2514,7 @@
  * DASD_3990_ERP_ACTION
  *
  * DESCRIPTION
- *   controll routine for 3990 erp actions.
+ *   control routine for 3990 erp actions.
  *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
  *
  * PARAMETER
@@ -2636,9 +2530,8 @@
 struct dasd_ccw_req *
 dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 {
-
 	struct dasd_ccw_req *erp = NULL;
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	struct dasd_ccw_req *temp_erp = NULL;
 
 	if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2704,10 +2597,11 @@
 		}
 	}
 
-	/* enqueue added ERP request */
-	if (erp->status == DASD_CQR_FILLED) {
-		erp->status = DASD_CQR_QUEUED;
-		list_add(&erp->list, &device->ccw_queue);
+	/* enqueue ERP request if it's a new one */
+	if (list_empty(&erp->blocklist)) {
+		cqr->status = DASD_CQR_IN_ERP;
+		/* add erp request before the cqr */
+		list_add_tail(&erp->blocklist, &cqr->blocklist);
 	}
 
 	return erp;
diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
deleted file mode 100644
index 6e08268..0000000
--- a/drivers/s390/block/dasd_9336_erp.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9336_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9336)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_9336_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 9336 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	/* examine the 24 byte sense data */
-	return dasd_era_recover;
-
-}				/* END dasd_9336_erp_examine */
diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
deleted file mode 100644
index ddecb98..0000000
--- a/drivers/s390/block/dasd_9343_erp.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9345_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9343)"
-
-#include "dasd_int.h"
-
-dasd_era_t
-dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	return dasd_era_recover;
-}
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
new file mode 100644
index 0000000..3a40bee
--- /dev/null
+++ b/drivers/s390/block/dasd_alias.c
@@ -0,0 +1,903 @@
+/*
+ * PAV alias management for the DASD ECKD discipline
+ *
+ * Copyright IBM Corporation, 2007
+ * Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ */
+
+#include <linux/list.h>
+#include <asm/ebcdic.h>
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eckd):"
+
+
+/*
+ * General concept of alias management:
+ * - PAV and DASD alias management is specific to the eckd discipline.
+ * - A device is connected to an lcu as long as the device exists.
+ *   dasd_alias_make_device_known_to_lcu will be called wenn the
+ *   device is checked by the eckd discipline and
+ *   dasd_alias_disconnect_device_from_lcu will be called
+ *   before the device is deleted.
+ * - The dasd_alias_add_device / dasd_alias_remove_device
+ *   functions mark the point when a device is 'ready for service'.
+ * - A summary unit check is a rare occasion, but it is mandatory to
+ *   support it. It requires some complex recovery actions before the
+ *   devices can be used again (see dasd_alias_handle_summary_unit_check).
+ * - dasd_alias_get_start_dev will find an alias device that can be used
+ *   instead of the base device and does some (very simple) load balancing.
+ *   This is the function that gets called for each I/O, so when improving
+ *   something, this function should get faster or better, the rest has just
+ *   to be correct.
+ */
+
+
+static void summary_unit_check_handling_work(struct work_struct *);
+static void lcu_update_work(struct work_struct *);
+static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);
+
+static struct alias_root aliastree = {
+	.serverlist = LIST_HEAD_INIT(aliastree.serverlist),
+	.lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),
+};
+
+static struct alias_server *_find_server(struct dasd_uid *uid)
+{
+	struct alias_server *pos;
+	list_for_each_entry(pos, &aliastree.serverlist, server) {
+		if (!strncmp(pos->uid.vendor, uid->vendor,
+			     sizeof(uid->vendor))
+		    && !strncmp(pos->uid.serial, uid->serial,
+				sizeof(uid->serial)))
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_lcu *_find_lcu(struct alias_server *server,
+				   struct dasd_uid *uid)
+{
+	struct alias_lcu *pos;
+	list_for_each_entry(pos, &server->lculist, lcu) {
+		if (pos->uid.ssid == uid->ssid)
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
+					   struct dasd_uid *uid)
+{
+	struct alias_pav_group *pos;
+	__u8 search_unit_addr;
+
+	/* for hyper pav there is only one group */
+	if (lcu->pav == HYPER_PAV) {
+		if (list_empty(&lcu->grouplist))
+			return NULL;
+		else
+			return list_first_entry(&lcu->grouplist,
+						struct alias_pav_group, group);
+	}
+
+	/* for base pav we have to find the group that matches the base */
+	if (uid->type == UA_BASE_DEVICE)
+		search_unit_addr = uid->real_unit_addr;
+	else
+		search_unit_addr = uid->base_unit_addr;
+	list_for_each_entry(pos, &lcu->grouplist, group) {
+		if (pos->uid.base_unit_addr == search_unit_addr)
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_server *_allocate_server(struct dasd_uid *uid)
+{
+	struct alias_server *server;
+
+	server = kzalloc(sizeof(*server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+	memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));
+	memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));
+	INIT_LIST_HEAD(&server->server);
+	INIT_LIST_HEAD(&server->lculist);
+	return server;
+}
+
+static void _free_server(struct alias_server *server)
+{
+	kfree(server);
+}
+
+static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
+{
+	struct alias_lcu *lcu;
+
+	lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);
+	if (!lcu)
+		return ERR_PTR(-ENOMEM);
+	lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);
+	if (!lcu->uac)
+		goto out_err1;
+	lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr)
+		goto out_err2;
+	lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),
+				       GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr->cpaddr)
+		goto out_err3;
+	lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr->data)
+		goto out_err4;
+
+	memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));
+	memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));
+	lcu->uid.ssid = uid->ssid;
+	lcu->pav = NO_PAV;
+	lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;
+	INIT_LIST_HEAD(&lcu->lcu);
+	INIT_LIST_HEAD(&lcu->inactive_devices);
+	INIT_LIST_HEAD(&lcu->active_devices);
+	INIT_LIST_HEAD(&lcu->grouplist);
+	INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
+	INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
+	spin_lock_init(&lcu->lock);
+	return lcu;
+
+out_err4:
+	kfree(lcu->rsu_cqr->cpaddr);
+out_err3:
+	kfree(lcu->rsu_cqr);
+out_err2:
+	kfree(lcu->uac);
+out_err1:
+	kfree(lcu);
+	return ERR_PTR(-ENOMEM);
+}
+
+static void _free_lcu(struct alias_lcu *lcu)
+{
+	kfree(lcu->rsu_cqr->data);
+	kfree(lcu->rsu_cqr->cpaddr);
+	kfree(lcu->rsu_cqr);
+	kfree(lcu->uac);
+	kfree(lcu);
+}
+
+/*
+ * This is the function that will allocate all the server and lcu data,
+ * so this function must be called first for a new device.
+ * If the return value is 1, the lcu was already known before, if it
+ * is 0, this is a new lcu.
+ * Negative return code indicates that something went wrong (e.g. -ENOMEM)
+ */
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+	struct alias_server *server, *newserver;
+	struct alias_lcu *lcu, *newlcu;
+	int is_lcu_known;
+	struct dasd_uid *uid;
+
+	private = (struct dasd_eckd_private *) device->private;
+	uid = &private->uid;
+	spin_lock_irqsave(&aliastree.lock, flags);
+	is_lcu_known = 1;
+	server = _find_server(uid);
+	if (!server) {
+		spin_unlock_irqrestore(&aliastree.lock, flags);
+		newserver = _allocate_server(uid);
+		if (IS_ERR(newserver))
+			return PTR_ERR(newserver);
+		spin_lock_irqsave(&aliastree.lock, flags);
+		server = _find_server(uid);
+		if (!server) {
+			list_add(&newserver->server, &aliastree.serverlist);
+			server = newserver;
+			is_lcu_known = 0;
+		} else {
+			/* someone was faster */
+			_free_server(newserver);
+		}
+	}
+
+	lcu = _find_lcu(server, uid);
+	if (!lcu) {
+		spin_unlock_irqrestore(&aliastree.lock, flags);
+		newlcu = _allocate_lcu(uid);
+		if (IS_ERR(newlcu))
+			return PTR_ERR(lcu);
+		spin_lock_irqsave(&aliastree.lock, flags);
+		lcu = _find_lcu(server, uid);
+		if (!lcu) {
+			list_add(&newlcu->lcu, &server->lculist);
+			lcu = newlcu;
+			is_lcu_known = 0;
+		} else {
+			/* someone was faster */
+			_free_lcu(newlcu);
+		}
+		is_lcu_known = 0;
+	}
+	spin_lock(&lcu->lock);
+	list_add(&device->alias_list, &lcu->inactive_devices);
+	private->lcu = lcu;
+	spin_unlock(&lcu->lock);
+	spin_unlock_irqrestore(&aliastree.lock, flags);
+
+	return is_lcu_known;
+}
+
+/*
+ * This function removes a device from the scope of alias management.
+ * The complicated part is to make sure that it is not in use by
+ * any of the workers. If necessary cancel the work.
+ */
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+	struct alias_lcu *lcu;
+	struct alias_server *server;
+	int was_pending;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_del_init(&device->alias_list);
+	/* make sure that the workers don't use this device */
+	if (device == lcu->suc_data.device) {
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		cancel_work_sync(&lcu->suc_data.worker);
+		spin_lock_irqsave(&lcu->lock, flags);
+		if (device == lcu->suc_data.device)
+			lcu->suc_data.device = NULL;
+	}
+	was_pending = 0;
+	if (device == lcu->ruac_data.device) {
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		was_pending = 1;
+		cancel_delayed_work_sync(&lcu->ruac_data.dwork);
+		spin_lock_irqsave(&lcu->lock, flags);
+		if (device == lcu->ruac_data.device)
+			lcu->ruac_data.device = NULL;
+	}
+	private->lcu = NULL;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	spin_lock_irqsave(&aliastree.lock, flags);
+	spin_lock(&lcu->lock);
+	if (list_empty(&lcu->grouplist) &&
+	    list_empty(&lcu->active_devices) &&
+	    list_empty(&lcu->inactive_devices)) {
+		list_del(&lcu->lcu);
+		spin_unlock(&lcu->lock);
+		_free_lcu(lcu);
+		lcu = NULL;
+	} else {
+		if (was_pending)
+			_schedule_lcu_update(lcu, NULL);
+		spin_unlock(&lcu->lock);
+	}
+	server = _find_server(&private->uid);
+	if (server && list_empty(&server->lculist)) {
+		list_del(&server->server);
+		_free_server(server);
+	}
+	spin_unlock_irqrestore(&aliastree.lock, flags);
+}
+
+/*
+ * This function assumes that the unit address configuration stored
+ * in the lcu is up to date and will update the device uid before
+ * adding it to a pav group.
+ */
+static int _add_device_to_lcu(struct alias_lcu *lcu,
+			      struct dasd_device *device)
+{
+
+	struct dasd_eckd_private *private;
+	struct alias_pav_group *group;
+	struct dasd_uid *uid;
+
+	private = (struct dasd_eckd_private *) device->private;
+	uid = &private->uid;
+	uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
+	uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
+	dasd_set_uid(device->cdev, &private->uid);
+
+	/* if we have no PAV anyway, we don't need to bother with PAV groups */
+	if (lcu->pav == NO_PAV) {
+		list_move(&device->alias_list, &lcu->active_devices);
+		return 0;
+	}
+
+	group = _find_group(lcu, uid);
+	if (!group) {
+		group = kzalloc(sizeof(*group), GFP_ATOMIC);
+		if (!group)
+			return -ENOMEM;
+		memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
+		memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
+		group->uid.ssid = uid->ssid;
+		if (uid->type == UA_BASE_DEVICE)
+			group->uid.base_unit_addr = uid->real_unit_addr;
+		else
+			group->uid.base_unit_addr = uid->base_unit_addr;
+		INIT_LIST_HEAD(&group->group);
+		INIT_LIST_HEAD(&group->baselist);
+		INIT_LIST_HEAD(&group->aliaslist);
+		list_add(&group->group, &lcu->grouplist);
+	}
+	if (uid->type == UA_BASE_DEVICE)
+		list_move(&device->alias_list, &group->baselist);
+	else
+		list_move(&device->alias_list, &group->aliaslist);
+	private->pavgroup = group;
+	return 0;
+};
+
+static void _remove_device_from_lcu(struct alias_lcu *lcu,
+				    struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_pav_group *group;
+
+	private = (struct dasd_eckd_private *) device->private;
+	list_move(&device->alias_list, &lcu->inactive_devices);
+	group = private->pavgroup;
+	if (!group)
+		return;
+	private->pavgroup = NULL;
+	if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {
+		list_del(&group->group);
+		kfree(group);
+		return;
+	}
+	if (group->next == device)
+		group->next = NULL;
+};
+
+static int read_unit_address_configuration(struct dasd_device *device,
+					   struct alias_lcu *lcu)
+{
+	struct dasd_psf_prssd_data *prssdp;
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+	int rc;
+	unsigned long flags;
+
+	cqr = dasd_kmalloc_request("ECKD",
+				   1 /* PSF */	+ 1 /* RSSD */ ,
+				   (sizeof(struct dasd_psf_prssd_data)),
+				   device);
+	if (IS_ERR(cqr))
+		return PTR_ERR(cqr);
+	cqr->startdev = device;
+	cqr->memdev = device;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 10;
+	cqr->expires = 20 * HZ;
+
+	/* Prepare for Read Subsystem Data */
+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+	prssdp->order = PSF_ORDER_PRSSD;
+	prssdp->suborder = 0x0e;	/* Read unit address configuration */
+	/* all other bytes of prssdp must be zero */
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) prssdp;
+
+	/* Read Subsystem Data - feature codes */
+	memset(lcu->uac, 0, sizeof(*(lcu->uac)));
+
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = sizeof(*(lcu->uac));
+	ccw->cda = (__u32)(addr_t) lcu->uac;
+
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+
+	/* need to unset flag here to detect race with summary unit check */
+	spin_lock_irqsave(&lcu->lock, flags);
+	lcu->flags &= ~NEED_UAC_UPDATE;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	do {
+		rc = dasd_sleep_on(cqr);
+	} while (rc && (cqr->retries > 0));
+	if (rc) {
+		spin_lock_irqsave(&lcu->lock, flags);
+		lcu->flags |= NEED_UAC_UPDATE;
+		spin_unlock_irqrestore(&lcu->lock, flags);
+	}
+	dasd_kfree_request(cqr, cqr->memdev);
+	return rc;
+}
+
+static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
+{
+	unsigned long flags;
+	struct alias_pav_group *pavgroup, *tempgroup;
+	struct dasd_device *device, *tempdev;
+	int i, rc;
+	struct dasd_eckd_private *private;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {
+		list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
+					 alias_list) {
+			list_move(&device->alias_list, &lcu->active_devices);
+			private = (struct dasd_eckd_private *) device->private;
+			private->pavgroup = NULL;
+		}
+		list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
+					 alias_list) {
+			list_move(&device->alias_list, &lcu->active_devices);
+			private = (struct dasd_eckd_private *) device->private;
+			private->pavgroup = NULL;
+		}
+		list_del(&pavgroup->group);
+		kfree(pavgroup);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	rc = read_unit_address_configuration(refdev, lcu);
+	if (rc)
+		return rc;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	lcu->pav = NO_PAV;
+	for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
+		switch (lcu->uac->unit[i].ua_type) {
+		case UA_BASE_PAV_ALIAS:
+			lcu->pav = BASE_PAV;
+			break;
+		case UA_HYPER_PAV_ALIAS:
+			lcu->pav = HYPER_PAV;
+			break;
+		}
+		if (lcu->pav != NO_PAV)
+			break;
+	}
+
+	list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
+				 alias_list) {
+		_add_device_to_lcu(lcu, device);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return 0;
+}
+
+static void lcu_update_work(struct work_struct *work)
+{
+	struct alias_lcu *lcu;
+	struct read_uac_work_data *ruac_data;
+	struct dasd_device *device;
+	unsigned long flags;
+	int rc;
+
+	ruac_data = container_of(work, struct read_uac_work_data, dwork.work);
+	lcu = container_of(ruac_data, struct alias_lcu, ruac_data);
+	device = ruac_data->device;
+	rc = _lcu_update(device, lcu);
+	/*
+	 * Need to check flags again, as there could have been another
+	 * prepare_update or a new device a new device while we were still
+	 * processing the data
+	 */
+	spin_lock_irqsave(&lcu->lock, flags);
+	if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
+		DEV_MESSAGE(KERN_WARNING, device, "could not update"
+			    " alias data in lcu (rc = %d), retry later", rc);
+		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+	} else {
+		lcu->ruac_data.device = NULL;
+		lcu->flags &= ~UPDATE_PENDING;
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+static int _schedule_lcu_update(struct alias_lcu *lcu,
+				struct dasd_device *device)
+{
+	struct dasd_device *usedev = NULL;
+	struct alias_pav_group *group;
+
+	lcu->flags |= NEED_UAC_UPDATE;
+	if (lcu->ruac_data.device) {
+		/* already scheduled or running */
+		return 0;
+	}
+	if (device && !list_empty(&device->alias_list))
+		usedev = device;
+
+	if (!usedev && !list_empty(&lcu->grouplist)) {
+		group = list_first_entry(&lcu->grouplist,
+					 struct alias_pav_group, group);
+		if (!list_empty(&group->baselist))
+			usedev = list_first_entry(&group->baselist,
+						  struct dasd_device,
+						  alias_list);
+		else if (!list_empty(&group->aliaslist))
+			usedev = list_first_entry(&group->aliaslist,
+						  struct dasd_device,
+						  alias_list);
+	}
+	if (!usedev && !list_empty(&lcu->active_devices)) {
+		usedev = list_first_entry(&lcu->active_devices,
+					  struct dasd_device, alias_list);
+	}
+	/*
+	 * if we haven't found a proper device yet, give up for now, the next
+	 * device that will be set active will trigger an lcu update
+	 */
+	if (!usedev)
+		return -EINVAL;
+	lcu->ruac_data.device = usedev;
+	schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+	return 0;
+}
+
+int dasd_alias_add_device(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_lcu *lcu;
+	unsigned long flags;
+	int rc;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	rc = 0;
+	spin_lock_irqsave(&lcu->lock, flags);
+	if (!(lcu->flags & UPDATE_PENDING)) {
+		rc = _add_device_to_lcu(lcu, device);
+		if (rc)
+			lcu->flags |= UPDATE_PENDING;
+	}
+	if (lcu->flags & UPDATE_PENDING) {
+		list_move(&device->alias_list, &lcu->active_devices);
+		_schedule_lcu_update(lcu, device);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return rc;
+}
+
+int dasd_alias_remove_device(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_lcu *lcu;
+	unsigned long flags;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	spin_lock_irqsave(&lcu->lock, flags);
+	_remove_device_from_lcu(lcu, device);
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return 0;
+}
+
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
+{
+
+	struct dasd_device *alias_device;
+	struct alias_pav_group *group;
+	struct alias_lcu *lcu;
+	struct dasd_eckd_private *private, *alias_priv;
+	unsigned long flags;
+
+	private = (struct dasd_eckd_private *) base_device->private;
+	group = private->pavgroup;
+	lcu = private->lcu;
+	if (!group || !lcu)
+		return NULL;
+	if (lcu->pav == NO_PAV ||
+	    lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
+		return NULL;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	alias_device = group->next;
+	if (!alias_device) {
+		if (list_empty(&group->aliaslist)) {
+			spin_unlock_irqrestore(&lcu->lock, flags);
+			return NULL;
+		} else {
+			alias_device = list_first_entry(&group->aliaslist,
+							struct dasd_device,
+							alias_list);
+		}
+	}
+	if (list_is_last(&alias_device->alias_list, &group->aliaslist))
+		group->next = list_first_entry(&group->aliaslist,
+					       struct dasd_device, alias_list);
+	else
+		group->next = list_first_entry(&alias_device->alias_list,
+					       struct dasd_device, alias_list);
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	alias_priv = (struct dasd_eckd_private *) alias_device->private;
+	if ((alias_priv->count < private->count) && !alias_device->stopped)
+		return alias_device;
+	else
+		return NULL;
+}
+
+/*
+ * Summary unit check handling depends on the way alias devices
+ * are handled so it is done here rather then in dasd_eckd.c
+ */
+static int reset_summary_unit_check(struct alias_lcu *lcu,
+				    struct dasd_device *device,
+				    char reason)
+{
+	struct dasd_ccw_req *cqr;
+	int rc = 0;
+
+	cqr = lcu->rsu_cqr;
+	strncpy((char *) &cqr->magic, "ECKD", 4);
+	ASCEBC((char *) &cqr->magic, 4);
+	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
+	cqr->cpaddr->flags = 0 ;
+	cqr->cpaddr->count = 16;
+	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+	((char *)cqr->data)[0] = reason;
+
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 255;	/* set retry counter to enable basic ERP */
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	cqr->expires = 5 * HZ;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+
+	rc = dasd_sleep_on_immediatly(cqr);
+	return rc;
+}
+
+static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device;
+	struct dasd_eckd_private *private;
+
+	/* active and inactive list can contain alias as well as base devices */
+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type != UA_BASE_DEVICE)
+			continue;
+		dasd_schedule_block_bh(device->block);
+		dasd_schedule_device_bh(device);
+	}
+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type != UA_BASE_DEVICE)
+			continue;
+		dasd_schedule_block_bh(device->block);
+		dasd_schedule_device_bh(device);
+	}
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+			dasd_schedule_block_bh(device->block);
+			dasd_schedule_device_bh(device);
+		}
+	}
+}
+
+static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device, *temp;
+	struct dasd_eckd_private *private;
+	int rc;
+	unsigned long flags;
+	LIST_HEAD(active);
+
+	/*
+	 * Problem here ist that dasd_flush_device_queue may wait
+	 * for termination of a request to complete. We can't keep
+	 * the lcu lock during that time, so we must assume that
+	 * the lists may have changed.
+	 * Idea: first gather all active alias devices in a separate list,
+	 * then flush the first element of this list unlocked, and afterwards
+	 * check if it is still on the list before moving it to the
+	 * active_devices list.
+	 */
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_for_each_entry_safe(device, temp, &lcu->active_devices,
+				 alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type == UA_BASE_DEVICE)
+			continue;
+		list_move(&device->alias_list, &active);
+	}
+
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_splice_init(&pavgroup->aliaslist, &active);
+	}
+	while (!list_empty(&active)) {
+		device = list_first_entry(&active, struct dasd_device,
+					  alias_list);
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		rc = dasd_flush_device_queue(device);
+		spin_lock_irqsave(&lcu->lock, flags);
+		/*
+		 * only move device around if it wasn't moved away while we
+		 * were waiting for the flush
+		 */
+		if (device == list_first_entry(&active,
+					       struct dasd_device, alias_list))
+			list_move(&device->alias_list, &lcu->active_devices);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * This function is called in interrupt context, so the
+ * cdev lock for device is already locked!
+ */
+static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
+				     struct dasd_device *device)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *pos;
+
+	list_for_each_entry(pos, &lcu->active_devices, alias_list) {
+		if (pos != device)
+			spin_lock(get_ccwdev_lock(pos->cdev));
+		pos->stopped |= DASD_STOPPED_SU;
+		if (pos != device)
+			spin_unlock(get_ccwdev_lock(pos->cdev));
+	}
+	list_for_each_entry(pos, &lcu->inactive_devices, alias_list) {
+		if (pos != device)
+			spin_lock(get_ccwdev_lock(pos->cdev));
+		pos->stopped |= DASD_STOPPED_SU;
+		if (pos != device)
+			spin_unlock(get_ccwdev_lock(pos->cdev));
+	}
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(pos, &pavgroup->baselist, alias_list) {
+			if (pos != device)
+				spin_lock(get_ccwdev_lock(pos->cdev));
+			pos->stopped |= DASD_STOPPED_SU;
+			if (pos != device)
+				spin_unlock(get_ccwdev_lock(pos->cdev));
+		}
+		list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) {
+			if (pos != device)
+				spin_lock(get_ccwdev_lock(pos->cdev));
+			pos->stopped |= DASD_STOPPED_SU;
+			if (pos != device)
+				spin_unlock(get_ccwdev_lock(pos->cdev));
+		}
+	}
+}
+
+static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device;
+	unsigned long flags;
+
+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+		device->stopped &= ~DASD_STOPPED_SU;
+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	}
+
+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+		device->stopped &= ~DASD_STOPPED_SU;
+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	}
+
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+			device->stopped &= ~DASD_STOPPED_SU;
+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+					       flags);
+		}
+		list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+			device->stopped &= ~DASD_STOPPED_SU;
+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+					       flags);
+		}
+	}
+}
+
+static void summary_unit_check_handling_work(struct work_struct *work)
+{
+	struct alias_lcu *lcu;
+	struct summary_unit_check_work_data *suc_data;
+	unsigned long flags;
+	struct dasd_device *device;
+
+	suc_data = container_of(work, struct summary_unit_check_work_data,
+				worker);
+	lcu = container_of(suc_data, struct alias_lcu, suc_data);
+	device = suc_data->device;
+
+	/* 1. flush alias devices */
+	flush_all_alias_devices_on_lcu(lcu);
+
+	/* 2. reset summary unit check */
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+	device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	reset_summary_unit_check(lcu, device, suc_data->reason);
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	_unstop_all_devices_on_lcu(lcu);
+	_restart_all_base_devices_on_lcu(lcu);
+	/* 3. read new alias configuration */
+	_schedule_lcu_update(lcu, device);
+	lcu->suc_data.device = NULL;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * note: this will be called from int handler context (cdev locked)
+ */
+void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
+					  struct irb *irb)
+{
+	struct alias_lcu *lcu;
+	char reason;
+	struct dasd_eckd_private *private;
+
+	private = (struct dasd_eckd_private *) device->private;
+
+	reason = irb->ecw[8];
+	DEV_MESSAGE(KERN_WARNING, device, "%s %x",
+		    "eckd handle summary unit check: reason", reason);
+
+	lcu = private->lcu;
+	if (!lcu) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "device not ready to handle summary"
+			    " unit check (no lcu structure)");
+		return;
+	}
+	spin_lock(&lcu->lock);
+	_stop_all_devices_on_lcu(lcu, device);
+	/* prepare for lcu_update */
+	private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
+	/* If this device is about to be removed just return and wait for
+	 * the next interrupt on a different device
+	 */
+	if (list_empty(&device->alias_list)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "device is in offline processing,"
+			    " don't do summary unit check handling");
+		spin_unlock(&lcu->lock);
+		return;
+	}
+	if (lcu->suc_data.device) {
+		/* already scheduled or running */
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "previous instance of summary unit check worker"
+			    " still pending");
+		spin_unlock(&lcu->lock);
+		return ;
+	}
+	lcu->suc_data.reason = reason;
+	lcu->suc_data.device = device;
+	spin_unlock(&lcu->lock);
+	schedule_work(&lcu->suc_data.worker);
+};
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 0c67258f..f4fb402 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -49,22 +49,6 @@
 };
 
 /*
- * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
- * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
- * the DASD device driver.
- */
-struct dasd_server_ssid_map {
-	struct list_head list;
-	struct system_id {
-		char vendor[4];
-		char serial[15];
-		__u16 ssid;
-	} sid;
-};
-
-static struct list_head dasd_server_ssid_list;
-
-/*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>		: (0x)?[0-9a-fA-F]+
  *   <busid>		: [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
@@ -721,8 +705,9 @@
 		devmap->features &= ~DASD_FEATURE_READONLY;
 	if (devmap->device)
 		devmap->device->features = devmap->features;
-	if (devmap->device && devmap->device->gdp)
-		set_disk_ro(devmap->device->gdp, val);
+	if (devmap->device && devmap->device->block
+	    && devmap->device->block->gdp)
+		set_disk_ro(devmap->device->block->gdp, val);
 	spin_unlock(&dasd_devmap_lock);
 	return count;
 }
@@ -893,12 +878,16 @@
 
 	devmap = dasd_find_busid(dev->bus_id);
 	spin_lock(&dasd_devmap_lock);
-	if (!IS_ERR(devmap))
-		alias = devmap->uid.alias;
+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+		spin_unlock(&dasd_devmap_lock);
+		return sprintf(buf, "0\n");
+	}
+	if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
+	    devmap->uid.type == UA_HYPER_PAV_ALIAS)
+		alias = 1;
 	else
 		alias = 0;
 	spin_unlock(&dasd_devmap_lock);
-
 	return sprintf(buf, alias ? "1\n" : "0\n");
 }
 
@@ -930,19 +919,36 @@
 dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct dasd_devmap *devmap;
-	char uid[UID_STRLEN];
+	char uid_string[UID_STRLEN];
+	char ua_string[3];
+	struct dasd_uid *uid;
 
 	devmap = dasd_find_busid(dev->bus_id);
 	spin_lock(&dasd_devmap_lock);
-	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
-		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
-			 devmap->uid.vendor, devmap->uid.serial,
-			 devmap->uid.ssid, devmap->uid.unit_addr);
-	else
-		uid[0] = 0;
+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+		spin_unlock(&dasd_devmap_lock);
+		return sprintf(buf, "\n");
+	}
+	uid = &devmap->uid;
+	switch (uid->type) {
+	case UA_BASE_DEVICE:
+		sprintf(ua_string, "%02x", uid->real_unit_addr);
+		break;
+	case UA_BASE_PAV_ALIAS:
+		sprintf(ua_string, "%02x", uid->base_unit_addr);
+		break;
+	case UA_HYPER_PAV_ALIAS:
+		sprintf(ua_string, "xx");
+		break;
+	default:
+		/* should not happen, treat like base device */
+		sprintf(ua_string, "%02x", uid->real_unit_addr);
+		break;
+	}
+	snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
+		 uid->vendor, uid->serial, uid->ssid, ua_string);
 	spin_unlock(&dasd_devmap_lock);
-
-	return snprintf(buf, PAGE_SIZE, "%s\n", uid);
+	return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
 }
 
 static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
@@ -1040,39 +1046,16 @@
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
 	struct dasd_devmap *devmap;
-	struct dasd_server_ssid_map *srv, *tmp;
 
 	devmap = dasd_find_busid(cdev->dev.bus_id);
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
-	/* generate entry for server_ssid_map */
-	srv = (struct dasd_server_ssid_map *)
-		kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
-	if (!srv)
-		return -ENOMEM;
-	strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
-	strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
-	srv->sid.ssid = uid->ssid;
-
-	/* server is already contained ? */
 	spin_lock(&dasd_devmap_lock);
 	devmap->uid = *uid;
-	list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
-		if (!memcmp(&srv->sid, &tmp->sid,
-			    sizeof(struct system_id))) {
-			kfree(srv);
-			srv = NULL;
-			break;
-		}
-	}
-
-	/* add servermap to serverlist */
-	if (srv)
-		list_add(&srv->list, &dasd_server_ssid_list);
 	spin_unlock(&dasd_devmap_lock);
 
-	return (srv ? 1 : 0);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(dasd_set_uid);
 
@@ -1138,9 +1121,6 @@
 	dasd_max_devindex = 0;
 	for (i = 0; i < 256; i++)
 		INIT_LIST_HEAD(&dasd_hashlists[i]);
-
-	/* Initialize servermap structure. */
-	INIT_LIST_HEAD(&dasd_server_ssid_list);
 	return 0;
 }
 
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 571320ab..d91df38 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -142,7 +142,7 @@
 	int rc;
 
 	mdsk_term_io(device);
-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
 	if (rc)
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
 			    "rc=%d", rc);
@@ -158,11 +158,11 @@
 	struct dasd_diag_req *dreq;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	if (cqr->retries < 0) {
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
 			    "- no retry left)", cqr);
-		cqr->status = DASD_CQR_FAILED;
+		cqr->status = DASD_CQR_ERROR;
 		return -EIO;
 	}
 	private = (struct dasd_diag_private *) device->private;
@@ -184,7 +184,7 @@
 	switch (rc) {
 	case 0: /* Synchronous I/O finished successfully */
 		cqr->stopclk = get_clock();
-		cqr->status = DASD_CQR_DONE;
+		cqr->status = DASD_CQR_SUCCESS;
 		/* Indicate to calling function that only a dasd_schedule_bh()
 		   and no timer is needed */
                 rc = -EACCES;
@@ -209,12 +209,12 @@
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	mdsk_term_io(device);
-	mdsk_init_io(device, device->bp_block, 0, NULL);
-	cqr->status = DASD_CQR_CLEAR;
+	mdsk_init_io(device, device->block->bp_block, 0, NULL);
+	cqr->status = DASD_CQR_CLEAR_PENDING;
 	cqr->stopclk = get_clock();
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	return 0;
 }
 
@@ -247,7 +247,7 @@
 		return;
 	}
 	cqr = (struct dasd_ccw_req *) ip;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    " magic number of dasd_ccw_req 0x%08X doesn't"
@@ -260,10 +260,10 @@
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 
 	/* Check for a pending clear operation */
-	if (cqr->status == DASD_CQR_CLEAR) {
-		cqr->status = DASD_CQR_QUEUED;
-		dasd_clear_timer(device);
-		dasd_schedule_bh(device);
+	if (cqr->status == DASD_CQR_CLEAR_PENDING) {
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_device_clear_timer(device);
+		dasd_schedule_device_bh(device);
 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 		return;
 	}
@@ -272,11 +272,11 @@
 
 	expires = 0;
 	if (status == 0) {
-		cqr->status = DASD_CQR_DONE;
+		cqr->status = DASD_CQR_SUCCESS;
 		/* Start first request on queue if possible -> fast_io. */
 		if (!list_empty(&device->ccw_queue)) {
 			next = list_entry(device->ccw_queue.next,
-					  struct dasd_ccw_req, list);
+					  struct dasd_ccw_req, devlist);
 			if (next->status == DASD_CQR_QUEUED) {
 				rc = dasd_start_diag(next);
 				if (rc == 0)
@@ -296,10 +296,10 @@
 	}
 
 	if (expires != 0)
-		dasd_set_timer(device, expires);
+		dasd_device_set_timer(device, expires);
 	else
-		dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+		dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
@@ -309,6 +309,7 @@
 static int
 dasd_diag_check_device(struct dasd_device *device)
 {
+	struct dasd_block *block;
 	struct dasd_diag_private *private;
 	struct dasd_diag_characteristics *rdc_data;
 	struct dasd_diag_bio bio;
@@ -328,6 +329,16 @@
 		ccw_device_get_id(device->cdev, &private->dev_id);
 		device->private = (void *) private;
 	}
+	block = dasd_alloc_block();
+	if (IS_ERR(block)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "could not allocate dasd block structure");
+		kfree(device->private);
+		return PTR_ERR(block);
+	}
+	device->block = block;
+	block->base = device;
+
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	rdc_data->dev_nr = private->dev_id.devno;
@@ -409,14 +420,14 @@
 		  sizeof(DASD_DIAG_CMS1)) == 0) {
 		/* get formatted blocksize from label block */
 		bsize = (unsigned int) label->block_size;
-		device->blocks = (unsigned long) label->block_count;
+		block->blocks = (unsigned long) label->block_count;
 	} else
-		device->blocks = end_block;
-	device->bp_block = bsize;
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+		block->blocks = end_block;
+	block->bp_block = bsize;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < bsize; sb = sb << 1)
-		device->s2b_shift++;
-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+		block->s2b_shift++;
+	rc = mdsk_init_io(device, block->bp_block, 0, NULL);
 	if (rc) {
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
 			"failed (rc=%d)", rc);
@@ -424,9 +435,9 @@
 	} else {
 		DEV_MESSAGE(KERN_INFO, device,
 			    "(%ld B/blk): %ldkB",
-			    (unsigned long) device->bp_block,
-			    (unsigned long) (device->blocks <<
-				device->s2b_shift) >> 1);
+			    (unsigned long) block->bp_block,
+			    (unsigned long) (block->blocks <<
+				block->s2b_shift) >> 1);
 	}
 out:
 	free_page((long) label);
@@ -436,22 +447,16 @@
 /* Fill in virtual disk geometry for device. Return zero on success, non-zero
  * otherwise. */
 static int
-dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
-	if (dasd_check_blocksize(device->bp_block) != 0)
+	if (dasd_check_blocksize(block->bp_block) != 0)
 		return -EINVAL;
-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->s2b_shift;
+	geo->sectors = 128 >> block->s2b_shift;
 	return 0;
 }
 
-static dasd_era_t
-dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
-{
-	return dasd_era_fatal;
-}
-
 static dasd_erp_fn_t
 dasd_diag_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -466,8 +471,9 @@
 
 /* Create DASD request from block device request. Return pointer to new
  * request on success, ERR_PTR otherwise. */
-static struct dasd_ccw_req *
-dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
+					       struct dasd_block *block,
+					       struct request *req)
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_diag_req *dreq;
@@ -486,17 +492,17 @@
 		rw_cmd = MDSK_WRITE_REQ;
 	else
 		return ERR_PTR(-EINVAL);
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	/* Calculate record id of first and last block. */
-	first_rec = req->sector >> device->s2b_shift;
-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	first_rec = req->sector >> block->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	rq_for_each_segment(bv, req, iter) {
 		if (bv->bv_len & (blksize - 1))
 			/* Fba can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
@@ -505,7 +511,7 @@
 	datasize = sizeof(struct dasd_diag_req) +
 		count*sizeof(struct dasd_diag_bio);
 	cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
-				   datasize, device);
+				   datasize, memdev);
 	if (IS_ERR(cqr))
 		return cqr;
 
@@ -529,7 +535,9 @@
 	cqr->buildclk = get_clock();
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = memdev;
+	cqr->memdev = memdev;
+	cqr->block = block;
 	cqr->expires = DIAG_TIMEOUT;
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
@@ -543,10 +551,15 @@
 	int status;
 
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+	cqr->status = DASD_CQR_FILLED;
+};
+
 /* Fill in IOCTL data for device. */
 static int
 dasd_diag_fill_info(struct dasd_device * device,
@@ -583,7 +596,7 @@
 	.fill_geometry = dasd_diag_fill_geometry,
 	.start_IO = dasd_start_diag,
 	.term_IO = dasd_diag_term_IO,
-	.examine_error = dasd_diag_examine_error,
+	.handle_terminated_request = dasd_diag_handle_terminated_request,
 	.erp_action = dasd_diag_erp_action,
 	.erp_postaction = dasd_diag_erp_postaction,
 	.build_cp = dasd_diag_build_cp,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 44adf84..61f1693 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -52,16 +52,6 @@
 
 static struct dasd_discipline dasd_eckd_discipline;
 
-struct dasd_eckd_private {
-	struct dasd_eckd_characteristics rdc_data;
-	struct dasd_eckd_confdata conf_data;
-	struct dasd_eckd_path path_data;
-	struct eckd_count count_area[5];
-	int init_cqr_status;
-	int uses_cdl;
-	struct attrib_data_t attrib;	/* e.g. cache operations */
-};
-
 /* The ccw bus type uses this table to find devices that it sends to
  * dasd_eckd_probe */
 static struct ccw_device_id dasd_eckd_ids[] = {
@@ -188,7 +178,7 @@
 	if (rc == -ENOSYS || rc == -EACCES)
 		rc = 0;
 
-	de_ccw->count = sizeof (struct DE_eckd_data);
+	de_ccw->count = sizeof(struct DE_eckd_data);
 	de_ccw->flags |= CCW_FLAG_SLI;
 	return rc;
 }
@@ -208,7 +198,7 @@
 	ccw->count = 16;
 	ccw->cda = (__u32) __pa(data);
 
-	memset(data, 0, sizeof (struct DE_eckd_data));
+	memset(data, 0, sizeof(struct DE_eckd_data));
 	switch (cmd) {
 	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
 	case DASD_ECKD_CCW_READ_RECORD_ZERO:
@@ -280,6 +270,132 @@
 	return rc;
 }
 
+static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
+			       struct dasd_device  *device)
+{
+	struct dasd_eckd_private *private;
+	int rc;
+
+	private = (struct dasd_eckd_private *) device->private;
+	if (!private->rdc_data.facilities.XRC_supported)
+		return 0;
+
+	/* switch on System Time Stamp - needed for XRC Support */
+	pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
+	pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */
+	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */
+
+	rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time);
+	/* Ignore return code if sync clock is switched off. */
+	if (rc == -ENOSYS || rc == -EACCES)
+		rc = 0;
+	return rc;
+}
+
+static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
+		  int totrk, int cmd, struct dasd_device *basedev,
+		  struct dasd_device *startdev)
+{
+	struct dasd_eckd_private *basepriv, *startpriv;
+	struct DE_eckd_data *data;
+	struct ch_t geo, beg, end;
+	int rc = 0;
+
+	basepriv = (struct dasd_eckd_private *) basedev->private;
+	startpriv = (struct dasd_eckd_private *) startdev->private;
+	data = &pfxdata->define_extend;
+
+	ccw->cmd_code = DASD_ECKD_CCW_PFX;
+	ccw->flags = 0;
+	ccw->count = sizeof(*pfxdata);
+	ccw->cda = (__u32) __pa(pfxdata);
+
+	memset(pfxdata, 0, sizeof(*pfxdata));
+	/* prefix data */
+	pfxdata->format = 0;
+	pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
+	pfxdata->base_lss = basepriv->conf_data.ned1.ID;
+	pfxdata->validity.define_extend = 1;
+
+	/* private uid is kept up to date, conf_data may be outdated */
+	if (startpriv->uid.type != UA_BASE_DEVICE) {
+		pfxdata->validity.verify_base = 1;
+		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
+			pfxdata->validity.hyper_pav = 1;
+	}
+
+	/* define extend data (mostly)*/
+	switch (cmd) {
+	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+	case DASD_ECKD_CCW_READ_RECORD_ZERO:
+	case DASD_ECKD_CCW_READ:
+	case DASD_ECKD_CCW_READ_MT:
+	case DASD_ECKD_CCW_READ_CKD:
+	case DASD_ECKD_CCW_READ_CKD_MT:
+	case DASD_ECKD_CCW_READ_KD:
+	case DASD_ECKD_CCW_READ_KD_MT:
+	case DASD_ECKD_CCW_READ_COUNT:
+		data->mask.perm = 0x1;
+		data->attributes.operation = basepriv->attrib.operation;
+		break;
+	case DASD_ECKD_CCW_WRITE:
+	case DASD_ECKD_CCW_WRITE_MT:
+	case DASD_ECKD_CCW_WRITE_KD:
+	case DASD_ECKD_CCW_WRITE_KD_MT:
+		data->mask.perm = 0x02;
+		data->attributes.operation = basepriv->attrib.operation;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	case DASD_ECKD_CCW_WRITE_CKD:
+	case DASD_ECKD_CCW_WRITE_CKD_MT:
+		data->attributes.operation = DASD_BYPASS_CACHE;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	case DASD_ECKD_CCW_ERASE:
+	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
+	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
+		data->mask.perm = 0x3;
+		data->mask.auth = 0x1;
+		data->attributes.operation = DASD_BYPASS_CACHE;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	default:
+		DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd);
+		break;
+	}
+
+	data->attributes.mode = 0x3;	/* ECKD */
+
+	if ((basepriv->rdc_data.cu_type == 0x2105 ||
+	     basepriv->rdc_data.cu_type == 0x2107 ||
+	     basepriv->rdc_data.cu_type == 0x1750)
+	    && !(basepriv->uses_cdl && trk < 2))
+		data->ga_extended |= 0x40; /* Regular Data Format Mode */
+
+	geo.cyl = basepriv->rdc_data.no_cyl;
+	geo.head = basepriv->rdc_data.trk_per_cyl;
+	beg.cyl = trk / geo.head;
+	beg.head = trk % geo.head;
+	end.cyl = totrk / geo.head;
+	end.head = totrk % geo.head;
+
+	/* check for sequential prestage - enhance cylinder range */
+	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
+	    data->attributes.operation == DASD_SEQ_ACCESS) {
+
+		if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl)
+			end.cyl += basepriv->attrib.nr_cyl;
+		else
+			end.cyl = (geo.cyl - 1);
+	}
+
+	data->beg_ext.cyl = beg.cyl;
+	data->beg_ext.head = beg.head;
+	data->end_ext.cyl = end.cyl;
+	data->end_ext.head = end.head;
+	return rc;
+}
+
 static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 	      int rec_on_trk, int no_rec, int cmd,
@@ -300,7 +416,7 @@
 	ccw->count = 16;
 	ccw->cda = (__u32) __pa(data);
 
-	memset(data, 0, sizeof (struct LO_eckd_data));
+	memset(data, 0, sizeof(struct LO_eckd_data));
 	sector = 0;
 	if (rec_on_trk) {
 		switch (private->rdc_data.dev_type) {
@@ -441,12 +557,15 @@
 	       sizeof(uid->serial) - 1);
 	EBCASC(uid->serial, sizeof(uid->serial) - 1);
 	uid->ssid = confdata->neq.subsystemID;
-	if (confdata->ned2.sneq.flags == 0x40) {
-		uid->alias = 1;
-		uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
-	} else
-		uid->unit_addr = confdata->ned1.unit_addr;
-
+	uid->real_unit_addr = confdata->ned1.unit_addr;
+	if (confdata->ned2.sneq.flags == 0x40 &&
+	    confdata->ned2.sneq.format == 0x0001) {
+		uid->type = confdata->ned2.sneq.sua_flags;
+		if (uid->type == UA_BASE_PAV_ALIAS)
+			uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
+	} else {
+		uid->type = UA_BASE_DEVICE;
+	}
 	return 0;
 }
 
@@ -470,7 +589,9 @@
 	ccw->cda = (__u32)(addr_t)rcd_buffer;
 	ccw->count = ciw->count;
 
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
 	cqr->expires = 10*HZ;
 	cqr->lpm = lpm;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -511,7 +632,7 @@
 	/*
 	 * on success we update the user input parms
 	 */
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	if (ret)
 		goto out_error;
 
@@ -557,19 +678,19 @@
 					"data retrieved");
 				continue;	/* no error */
 			}
-			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+			if (conf_len != sizeof(struct dasd_eckd_confdata)) {
 				MESSAGE(KERN_WARNING,
 					"sizes of configuration data mismatch"
 					"%d (read) vs %ld (expected)",
 					conf_len,
-					sizeof (struct dasd_eckd_confdata));
+					sizeof(struct dasd_eckd_confdata));
 				kfree(conf_data);
 				continue;	/* no error */
 			}
 			/* save first valid configuration data */
 			if (!conf_data_saved){
 				memcpy(&private->conf_data, conf_data,
-				       sizeof (struct dasd_eckd_confdata));
+				       sizeof(struct dasd_eckd_confdata));
 				conf_data_saved++;
 			}
 			switch (((char *)conf_data)[242] & 0x07){
@@ -586,39 +707,104 @@
 	return 0;
 }
 
+static int dasd_eckd_read_features(struct dasd_device *device)
+{
+	struct dasd_psf_prssd_data *prssdp;
+	struct dasd_rssd_features *features;
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+	int rc;
+	struct dasd_eckd_private *private;
+
+	private = (struct dasd_eckd_private *) device->private;
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1 /* PSF */	+ 1 /* RSSD */ ,
+				   (sizeof(struct dasd_psf_prssd_data) +
+				    sizeof(struct dasd_rssd_features)),
+				   device);
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Could not allocate initialization request");
+		return PTR_ERR(cqr);
+	}
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 5;
+	cqr->expires = 10 * HZ;
+
+	/* Prepare for Read Subsystem Data */
+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+	prssdp->order = PSF_ORDER_PRSSD;
+	prssdp->suborder = 0x41;	/* Read Feature Codes */
+	/* all other bytes of prssdp must be zero */
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) prssdp;
+
+	/* Read Subsystem Data - feature codes */
+	features = (struct dasd_rssd_features *) (prssdp + 1);
+	memset(features, 0, sizeof(struct dasd_rssd_features));
+
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = sizeof(struct dasd_rssd_features);
+	ccw->cda = (__u32)(addr_t) features;
+
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	rc = dasd_sleep_on(cqr);
+	if (rc == 0) {
+		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+		features = (struct dasd_rssd_features *) (prssdp + 1);
+		memcpy(&private->features, features,
+		       sizeof(struct dasd_rssd_features));
+	}
+	dasd_sfree_request(cqr, cqr->memdev);
+	return rc;
+}
+
+
 /*
  * Build CP for Perform Subsystem Function - SSC.
  */
-static struct dasd_ccw_req *
-dasd_eckd_build_psf_ssc(struct dasd_device *device)
+static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       struct dasd_psf_ssc_data *psf_ssc_data;
-       struct ccw1 *ccw;
+	struct dasd_ccw_req *cqr;
+	struct dasd_psf_ssc_data *psf_ssc_data;
+	struct ccw1 *ccw;
 
-       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+	cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
 				  sizeof(struct dasd_psf_ssc_data),
 				  device);
 
-       if (IS_ERR(cqr)) {
-	       DEV_MESSAGE(KERN_WARNING, device, "%s",
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			   "Could not allocate PSF-SSC request");
-	       return cqr;
-       }
-       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
-       psf_ssc_data->order = PSF_ORDER_SSC;
-       psf_ssc_data->suborder = 0x08;
+		return cqr;
+	}
+	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+	psf_ssc_data->order = PSF_ORDER_SSC;
+	psf_ssc_data->suborder = 0x88;
+	psf_ssc_data->reserved[0] = 0x88;
 
-       ccw = cqr->cpaddr;
-       ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)(addr_t)psf_ssc_data;
-       ccw->count = 66;
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->cda = (__u32)(addr_t)psf_ssc_data;
+	ccw->count = 66;
 
-       cqr->device = device;
-       cqr->expires = 10*HZ;
-       cqr->buildclk = get_clock();
-       cqr->status = DASD_CQR_FILLED;
-       return cqr;
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	cqr->expires = 10*HZ;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
 }
 
 /*
@@ -629,28 +815,28 @@
 static int
 dasd_eckd_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       int rc;
+	struct dasd_ccw_req *cqr;
+	int rc;
 
-       cqr = dasd_eckd_build_psf_ssc(device);
-       if (IS_ERR(cqr))
-	       return PTR_ERR(cqr);
+	cqr = dasd_eckd_build_psf_ssc(device);
+	if (IS_ERR(cqr))
+		return PTR_ERR(cqr);
 
-       rc = dasd_sleep_on(cqr);
-       if (!rc)
-	       /* trigger CIO to reprobe devices */
-	       css_schedule_reprobe();
-       dasd_sfree_request(cqr, cqr->device);
-       return rc;
+	rc = dasd_sleep_on(cqr);
+	if (!rc)
+		/* trigger CIO to reprobe devices */
+		css_schedule_reprobe();
+	dasd_sfree_request(cqr, cqr->memdev);
+	return rc;
 }
 
 /*
  * Valide storage server of current device.
  */
-static int
-dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
+static int dasd_eckd_validate_server(struct dasd_device *device)
 {
 	int rc;
+	struct dasd_eckd_private *private;
 
 	/* Currently PAV is the only reason to 'validate' server on LPAR */
 	if (dasd_nopav || MACHINE_IS_VM)
@@ -659,9 +845,11 @@
 	rc = dasd_eckd_psf_ssc(device);
 	/* may be requested feature is not available on server,
 	 * therefore just report error and go ahead */
+	private = (struct dasd_eckd_private *) device->private;
 	DEV_MESSAGE(KERN_INFO, device,
 		    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
-		    uid->vendor, uid->serial, uid->ssid, rc);
+		    private->uid.vendor, private->uid.serial,
+		    private->uid.ssid, rc);
 	/* RE-Read Configuration Data */
 	return dasd_eckd_read_conf(device);
 }
@@ -674,9 +862,9 @@
 dasd_eckd_check_characteristics(struct dasd_device *device)
 {
 	struct dasd_eckd_private *private;
-	struct dasd_uid uid;
+	struct dasd_block *block;
 	void *rdc_data;
-	int rc;
+	int is_known, rc;
 
 	private = (struct dasd_eckd_private *) device->private;
 	if (private == NULL) {
@@ -699,27 +887,54 @@
 	/* Read Configuration Data */
 	rc = dasd_eckd_read_conf(device);
 	if (rc)
-		return rc;
+		goto out_err1;
 
 	/* Generate device unique id and register in devmap */
-	rc = dasd_eckd_generate_uid(device, &uid);
+	rc = dasd_eckd_generate_uid(device, &private->uid);
 	if (rc)
-		return rc;
-	rc = dasd_set_uid(device->cdev, &uid);
-	if (rc == 1)	/* new server found */
-		rc = dasd_eckd_validate_server(device, &uid);
+		goto out_err1;
+	dasd_set_uid(device->cdev, &private->uid);
+
+	if (private->uid.type == UA_BASE_DEVICE) {
+		block = dasd_alloc_block();
+		if (IS_ERR(block)) {
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "could not allocate dasd block structure");
+			rc = PTR_ERR(block);
+			goto out_err1;
+		}
+		device->block = block;
+		block->base = device;
+	}
+
+	/* register lcu with alias handling, enable PAV if this is a new lcu */
+	is_known = dasd_alias_make_device_known_to_lcu(device);
+	if (is_known < 0) {
+		rc = is_known;
+		goto out_err2;
+	}
+	if (!is_known) {
+		/* new lcu found */
+		rc = dasd_eckd_validate_server(device); /* will switch pav on */
+		if (rc)
+			goto out_err3;
+	}
+
+	/* Read Feature Codes */
+	rc = dasd_eckd_read_features(device);
 	if (rc)
-		return rc;
+		goto out_err3;
 
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	memset(rdc_data, 0, sizeof(rdc_data));
 	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
-	if (rc)
+	if (rc) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    "Read device characteristics returned "
 			    "rc=%d", rc);
-
+		goto out_err3;
+	}
 	DEV_MESSAGE(KERN_INFO, device,
 		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
 		    private->rdc_data.dev_type,
@@ -729,9 +944,24 @@
 		    private->rdc_data.no_cyl,
 		    private->rdc_data.trk_per_cyl,
 		    private->rdc_data.sec_per_trk);
+	return 0;
+
+out_err3:
+	dasd_alias_disconnect_device_from_lcu(device);
+out_err2:
+	dasd_free_block(device->block);
+	device->block = NULL;
+out_err1:
+	kfree(device->private);
+	device->private = NULL;
 	return rc;
 }
 
+static void dasd_eckd_uncheck_device(struct dasd_device *device)
+{
+	dasd_alias_disconnect_device_from_lcu(device);
+}
+
 static struct dasd_ccw_req *
 dasd_eckd_analysis_ccw(struct dasd_device *device)
 {
@@ -755,7 +985,7 @@
 	/* Define extent for the first 3 tracks. */
 	define_extent(ccw++, cqr->data, 0, 2,
 		      DASD_ECKD_CCW_READ_COUNT, device);
-	LO_data = cqr->data + sizeof (struct DE_eckd_data);
+	LO_data = cqr->data + sizeof(struct DE_eckd_data);
 	/* Locate record for the first 4 records on track 0. */
 	ccw[-1].flags |= CCW_FLAG_CC;
 	locate_record(ccw++, LO_data++, 0, 0, 4,
@@ -783,7 +1013,9 @@
 	ccw->count = 8;
 	ccw->cda = (__u32)(addr_t) count_data;
 
-	cqr->device = device;
+	cqr->block = NULL;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->retries = 0;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -803,7 +1035,7 @@
 	struct dasd_eckd_private *private;
 	struct dasd_device *device;
 
-	device = init_cqr->device;
+	device = init_cqr->startdev;
 	private = (struct dasd_eckd_private *) device->private;
 	private->init_cqr_status = init_cqr->status;
 	dasd_sfree_request(init_cqr, device);
@@ -811,13 +1043,13 @@
 }
 
 static int
-dasd_eckd_start_analysis(struct dasd_device *device)
+dasd_eckd_start_analysis(struct dasd_block *block)
 {
 	struct dasd_eckd_private *private;
 	struct dasd_ccw_req *init_cqr;
 
-	private = (struct dasd_eckd_private *) device->private;
-	init_cqr = dasd_eckd_analysis_ccw(device);
+	private = (struct dasd_eckd_private *) block->base->private;
+	init_cqr = dasd_eckd_analysis_ccw(block->base);
 	if (IS_ERR(init_cqr))
 		return PTR_ERR(init_cqr);
 	init_cqr->callback = dasd_eckd_analysis_callback;
@@ -828,13 +1060,15 @@
 }
 
 static int
-dasd_eckd_end_analysis(struct dasd_device *device)
+dasd_eckd_end_analysis(struct dasd_block *block)
 {
+	struct dasd_device *device;
 	struct dasd_eckd_private *private;
 	struct eckd_count *count_area;
 	unsigned int sb, blk_per_trk;
 	int status, i;
 
+	device = block->base;
 	private = (struct dasd_eckd_private *) device->private;
 	status = private->init_cqr_status;
 	private->init_cqr_status = -1;
@@ -846,7 +1080,7 @@
 
 	private->uses_cdl = 1;
 	/* Calculate number of blocks/records per track. */
-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
 	/* Check Track 0 for Compatible Disk Layout */
 	count_area = NULL;
 	for (i = 0; i < 3; i++) {
@@ -876,56 +1110,65 @@
 	if (count_area != NULL && count_area->kl == 0) {
 		/* we found notthing violating our disk layout */
 		if (dasd_check_blocksize(count_area->dl) == 0)
-			device->bp_block = count_area->dl;
+			block->bp_block = count_area->dl;
 	}
-	if (device->bp_block == 0) {
+	if (block->bp_block == 0) {
 		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			    "Volume has incompatible disk layout");
 		return -EMEDIUMTYPE;
 	}
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < device->bp_block; sb = sb << 1)
-		device->s2b_shift++;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	for (sb = 512; sb < block->bp_block; sb = sb << 1)
+		block->s2b_shift++;
 
-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
-	device->blocks = (private->rdc_data.no_cyl *
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
+	block->blocks = (private->rdc_data.no_cyl *
 			  private->rdc_data.trk_per_cyl *
 			  blk_per_trk);
 
 	DEV_MESSAGE(KERN_INFO, device,
 		    "(%dkB blks): %dkB at %dkB/trk %s",
-		    (device->bp_block >> 10),
+		    (block->bp_block >> 10),
 		    ((private->rdc_data.no_cyl *
 		      private->rdc_data.trk_per_cyl *
-		      blk_per_trk * (device->bp_block >> 9)) >> 1),
-		    ((blk_per_trk * device->bp_block) >> 10),
+		      blk_per_trk * (block->bp_block >> 9)) >> 1),
+		    ((blk_per_trk * block->bp_block) >> 10),
 		    private->uses_cdl ?
 		    "compatible disk layout" : "linux disk layout");
 
 	return 0;
 }
 
-static int
-dasd_eckd_do_analysis(struct dasd_device *device)
+static int dasd_eckd_do_analysis(struct dasd_block *block)
 {
 	struct dasd_eckd_private *private;
 
-	private = (struct dasd_eckd_private *) device->private;
+	private = (struct dasd_eckd_private *) block->base->private;
 	if (private->init_cqr_status < 0)
-		return dasd_eckd_start_analysis(device);
+		return dasd_eckd_start_analysis(block);
 	else
-		return dasd_eckd_end_analysis(device);
+		return dasd_eckd_end_analysis(block);
 }
 
+static int dasd_eckd_ready_to_online(struct dasd_device *device)
+{
+	return dasd_alias_add_device(device);
+};
+
+static int dasd_eckd_online_to_ready(struct dasd_device *device)
+{
+	return dasd_alias_remove_device(device);
+};
+
 static int
-dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
 	struct dasd_eckd_private *private;
 
-	private = (struct dasd_eckd_private *) device->private;
-	if (dasd_check_blocksize(device->bp_block) == 0) {
+	private = (struct dasd_eckd_private *) block->base->private;
+	if (dasd_check_blocksize(block->bp_block) == 0) {
 		geo->sectors = recs_per_track(&private->rdc_data,
-					      0, device->bp_block);
+					      0, block->bp_block);
 	}
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
@@ -1037,7 +1280,7 @@
 		locate_record(ccw++, (struct LO_eckd_data *) data,
 			      fdata->start_unit, 0, rpt + 1,
 			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
-			      device->bp_block);
+			      device->block->bp_block);
 		data += sizeof(struct LO_eckd_data);
 		break;
 	case 0x04: /* Invalidate track. */
@@ -1110,43 +1353,28 @@
 			ccw++;
 		}
 	}
-	fcp->device = device;
-	fcp->retries = 2;	/* set retry counter to enable ERP */
+	fcp->startdev = device;
+	fcp->memdev = device;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
+	fcp->retries = 5;	/* set retry counter to enable default ERP */
 	fcp->buildclk = get_clock();
 	fcp->status = DASD_CQR_FILLED;
 	return fcp;
 }
 
-static dasd_era_t
-dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
+static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device = (struct dasd_device *) cqr->device;
-	struct ccw_device *cdev = device->cdev;
-
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	switch (cdev->id.cu_type) {
-	case 0x3990:
-	case 0x2105:
-	case 0x2107:
-	case 0x1750:
-		return dasd_3990_erp_examine(cqr, irb);
-	case 0x9343:
-		return dasd_9343_erp_examine(cqr, irb);
-	case 0x3880:
-	default:
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
-			    "default (unknown CU type) - RECOVERABLE return");
-		return dasd_era_recover;
+	cqr->status = DASD_CQR_FILLED;
+	if (cqr->block && (cqr->startdev != cqr->block->base)) {
+		dasd_eckd_reset_ccw_to_base_io(cqr);
+		cqr->startdev = cqr->block->base;
 	}
-}
+};
 
 static dasd_erp_fn_t
 dasd_eckd_erp_action(struct dasd_ccw_req * cqr)
 {
-	struct dasd_device *device = (struct dasd_device *) cqr->device;
+	struct dasd_device *device = (struct dasd_device *) cqr->startdev;
 	struct ccw_device *cdev = device->cdev;
 
 	switch (cdev->id.cu_type) {
@@ -1168,8 +1396,37 @@
 	return dasd_default_erp_postaction;
 }
 
-static struct dasd_ccw_req *
-dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+
+static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
+						   struct irb *irb)
+{
+	char mask;
+
+	/* first of all check for state change pending interrupt */
+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+	if ((irb->scsw.dstat & mask) == mask) {
+		dasd_generic_handle_state_change(device);
+		return;
+	}
+
+	/* summary unit check */
+	if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
+		dasd_alias_handle_summary_unit_check(device, irb);
+		return;
+	}
+
+	/* just report other unsolicited interrupts */
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "unsolicited interrupt received");
+	device->discipline->dump_sense(device, NULL, irb);
+	dasd_schedule_device_bh(device);
+
+	return;
+};
+
+static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
+					       struct dasd_block *block,
+					       struct request *req)
 {
 	struct dasd_eckd_private *private;
 	unsigned long *idaws;
@@ -1185,8 +1442,11 @@
 	sector_t first_trk, last_trk;
 	unsigned int first_offs, last_offs;
 	unsigned char cmd, rcmd;
+	int use_prefix;
+	struct dasd_device *basedev;
 
-	private = (struct dasd_eckd_private *) device->private;
+	basedev = block->base;
+	private = (struct dasd_eckd_private *) basedev->private;
 	if (rq_data_dir(req) == READ)
 		cmd = DASD_ECKD_CCW_READ_MT;
 	else if (rq_data_dir(req) == WRITE)
@@ -1194,13 +1454,13 @@
 	else
 		return ERR_PTR(-EINVAL);
 	/* Calculate number of blocks/records per track. */
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
 	/* Calculate record id of first and last block. */
-	first_rec = first_trk = req->sector >> device->s2b_shift;
+	first_rec = first_trk = req->sector >> block->s2b_shift;
 	first_offs = sector_div(first_trk, blk_per_trk);
 	last_rec = last_trk =
-		(req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+		(req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	last_offs = sector_div(last_trk, blk_per_trk);
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
@@ -1209,20 +1469,33 @@
 		if (bv->bv_len & (blksize - 1))
 			/* Eckd can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
-			cidaw += bv->bv_len >> (device->s2b_shift + 9);
+			cidaw += bv->bv_len >> (block->s2b_shift + 9);
 #endif
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
 		return ERR_PTR(-EINVAL);
-	/* 1x define extent + 1x locate record + number of blocks */
-	cplength = 2 + count;
-	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
-	datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +
-		cidaw * sizeof(unsigned long);
+
+	/* use the prefix command if available */
+	use_prefix = private->features.feature[8] & 0x01;
+	if (use_prefix) {
+		/* 1x prefix + number of blocks */
+		cplength = 2 + count;
+		/* 1x prefix + cidaws*sizeof(long) */
+		datasize = sizeof(struct PFX_eckd_data) +
+			sizeof(struct LO_eckd_data) +
+			cidaw * sizeof(unsigned long);
+	} else {
+		/* 1x define extent + 1x locate record + number of blocks */
+		cplength = 2 + count;
+		/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
+		datasize = sizeof(struct DE_eckd_data) +
+			sizeof(struct LO_eckd_data) +
+			cidaw * sizeof(unsigned long);
+	}
 	/* Find out the number of additional locate record ccws for cdl. */
 	if (private->uses_cdl && first_rec < 2*blk_per_trk) {
 		if (last_rec >= 2*blk_per_trk)
@@ -1232,26 +1505,42 @@
 	}
 	/* Allocate the ccw request. */
 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
-				   cplength, datasize, device);
+				   cplength, datasize, startdev);
 	if (IS_ERR(cqr))
 		return cqr;
 	ccw = cqr->cpaddr;
-	/* First ccw is define extent. */
-	if (define_extent(ccw++, cqr->data, first_trk,
-			  last_trk, cmd, device) == -EAGAIN) {
-		/* Clock not in sync and XRC is enabled. Try again later. */
-		dasd_sfree_request(cqr, device);
-		return ERR_PTR(-EAGAIN);
+	/* First ccw is define extent or prefix. */
+	if (use_prefix) {
+		if (prefix(ccw++, cqr->data, first_trk,
+			   last_trk, cmd, basedev, startdev) == -EAGAIN) {
+			/* Clock not in sync and XRC is enabled.
+			 * Try again later.
+			 */
+			dasd_sfree_request(cqr, startdev);
+			return ERR_PTR(-EAGAIN);
+		}
+		idaws = (unsigned long *) (cqr->data +
+					   sizeof(struct PFX_eckd_data));
+	} else {
+		if (define_extent(ccw++, cqr->data, first_trk,
+				  last_trk, cmd, startdev) == -EAGAIN) {
+			/* Clock not in sync and XRC is enabled.
+			 * Try again later.
+			 */
+			dasd_sfree_request(cqr, startdev);
+			return ERR_PTR(-EAGAIN);
+		}
+		idaws = (unsigned long *) (cqr->data +
+					   sizeof(struct DE_eckd_data));
 	}
 	/* Build locate_record+read/write/ccws. */
-	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
 	recid = first_rec;
 	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
 		/* Only standard blocks so there is just one locate record. */
 		ccw[-1].flags |= CCW_FLAG_CC;
 		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
-			      last_rec - recid + 1, cmd, device, blksize);
+			      last_rec - recid + 1, cmd, basedev, blksize);
 	}
 	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
@@ -1281,7 +1570,7 @@
 				ccw[-1].flags |= CCW_FLAG_CC;
 				locate_record(ccw++, LO_data++,
 					      trkid, recoffs + 1,
-					      1, rcmd, device, count);
+					      1, rcmd, basedev, count);
 			}
 			/* Locate record for standard blocks ? */
 			if (private->uses_cdl && recid == 2*blk_per_trk) {
@@ -1289,7 +1578,7 @@
 				locate_record(ccw++, LO_data++,
 					      trkid, recoffs + 1,
 					      last_rec - recid + 1,
-					      cmd, device, count);
+					      cmd, basedev, count);
 			}
 			/* Read/write ccw. */
 			ccw[-1].flags |= CCW_FLAG_CC;
@@ -1310,7 +1599,9 @@
 	}
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = startdev;
+	cqr->memdev = startdev;
+	cqr->block = block;
 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
 	cqr->lpm = private->path_data.ppm;
 	cqr->retries = 256;
@@ -1333,10 +1624,10 @@
 
 	if (!dasd_page_cache)
 		goto out;
-	private = (struct dasd_eckd_private *) cqr->device->private;
-	blksize = cqr->device->bp_block;
+	private = (struct dasd_eckd_private *) cqr->block->base->private;
+	blksize = cqr->block->bp_block;
 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
-	recid = req->sector >> cqr->device->s2b_shift;
+	recid = req->sector >> cqr->block->s2b_shift;
 	ccw = cqr->cpaddr;
 	/* Skip over define extent & locate record. */
 	ccw++;
@@ -1367,10 +1658,71 @@
 	}
 out:
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+/*
+ * Modify ccw chain in cqr so it can be started on a base device.
+ *
+ * Note that this is not enough to restart the cqr!
+ * Either reset cqr->startdev as well (summary unit check handling)
+ * or restart via separate cqr (as in ERP handling).
+ */
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)
+{
+	struct ccw1 *ccw;
+	struct PFX_eckd_data *pfxdata;
+
+	ccw = cqr->cpaddr;
+	pfxdata = cqr->data;
+
+	if (ccw->cmd_code == DASD_ECKD_CCW_PFX) {
+		pfxdata->validity.verify_base = 0;
+		pfxdata->validity.hyper_pav = 0;
+	}
+}
+
+#define DASD_ECKD_CHANQ_MAX_SIZE 4
+
+static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
+						     struct dasd_block *block,
+						     struct request *req)
+{
+	struct dasd_eckd_private *private;
+	struct dasd_device *startdev;
+	unsigned long flags;
+	struct dasd_ccw_req *cqr;
+
+	startdev = dasd_alias_get_start_dev(base);
+	if (!startdev)
+		startdev = base;
+	private = (struct dasd_eckd_private *) startdev->private;
+	if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
+		return ERR_PTR(-EBUSY);
+
+	spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
+	private->count++;
+	cqr = dasd_eckd_build_cp(startdev, block, req);
+	if (IS_ERR(cqr))
+		private->count--;
+	spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
+	return cqr;
+}
+
+static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
+				   struct request *req)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+
+	spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
+	private = (struct dasd_eckd_private *) cqr->memdev->private;
+	private->count--;
+	spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
+	return dasd_eckd_free_cp(cqr, req);
+}
+
 static int
 dasd_eckd_fill_info(struct dasd_device * device,
 		    struct dasd_information2_t * info)
@@ -1384,9 +1736,9 @@
 	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
 	memcpy(info->characteristics, &private->rdc_data,
 	       sizeof(struct dasd_eckd_characteristics));
-	info->confdata_size = sizeof (struct dasd_eckd_confdata);
+	info->confdata_size = sizeof(struct dasd_eckd_confdata);
 	memcpy(info->configuration_data, &private->conf_data,
-	       sizeof (struct dasd_eckd_confdata));
+	       sizeof(struct dasd_eckd_confdata));
 	return 0;
 }
 
@@ -1419,7 +1771,8 @@
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1429,7 +1782,7 @@
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1459,7 +1812,8 @@
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1469,7 +1823,7 @@
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1498,7 +1852,8 @@
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1508,7 +1863,7 @@
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1526,52 +1881,52 @@
 
 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
 				   1 /* PSF */  + 1 /* RSSD */ ,
-				   (sizeof (struct dasd_psf_prssd_data) +
-				    sizeof (struct dasd_rssd_perf_stats_t)),
+				   (sizeof(struct dasd_psf_prssd_data) +
+				    sizeof(struct dasd_rssd_perf_stats_t)),
 				   device);
 	if (IS_ERR(cqr)) {
 		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			    "Could not allocate initialization request");
 		return PTR_ERR(cqr);
 	}
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->retries = 0;
 	cqr->expires = 10 * HZ;
 
 	/* Prepare for Read Subsystem Data */
 	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-	memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
 	prssdp->order = PSF_ORDER_PRSSD;
-	prssdp->suborder = 0x01;	/* Perfomance Statistics */
+	prssdp->suborder = 0x01;	/* Performance Statistics */
 	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */
 
 	ccw = cqr->cpaddr;
 	ccw->cmd_code = DASD_ECKD_CCW_PSF;
-	ccw->count = sizeof (struct dasd_psf_prssd_data);
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
 	ccw->flags |= CCW_FLAG_CC;
 	ccw->cda = (__u32)(addr_t) prssdp;
 
 	/* Read Subsystem Data - Performance Statistics */
 	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
-	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
+	memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t));
 
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
-	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
+	ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
 	ccw->cda = (__u32)(addr_t) stats;
 
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	rc = dasd_sleep_on(cqr);
 	if (rc == 0) {
-		/* Prepare for Read Subsystem Data */
 		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
 		stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
 		if (copy_to_user(argp, stats,
 				 sizeof(struct dasd_rssd_perf_stats_t)))
 			rc = -EFAULT;
 	}
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1594,7 +1949,7 @@
 
 	rc = 0;
 	if (copy_to_user(argp, (long *) &attrib,
-			 sizeof (struct attrib_data_t)))
+			 sizeof(struct attrib_data_t)))
 		rc = -EFAULT;
 
 	return rc;
@@ -1627,8 +1982,10 @@
 }
 
 static int
-dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
+dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
 {
+	struct dasd_device *device = block->base;
+
 	switch (cmd) {
 	case BIODASDGATTR:
 		return dasd_eckd_get_attrib(device, argp);
@@ -1685,9 +2042,8 @@
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
  */
-static void
-dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
-		     struct irb *irb)
+static void dasd_eckd_dump_sense(struct dasd_device *device,
+				 struct dasd_ccw_req *req, struct irb *irb)
 {
 	char *page;
 	struct ccw1 *first, *last, *fail, *from, *to;
@@ -1743,37 +2099,40 @@
 	}
 	printk("%s", page);
 
-	/* dump the Channel Program (max 140 Bytes per line) */
-	/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
-	first = req->cpaddr;
-	for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-	to = min(first + 6, last);
-	len = sprintf(page,  KERN_ERR PRINTK_HEADER
-		      " Related CP in req: %p\n", req);
-	dasd_eckd_dump_ccw_range(first, to, page + len);
-	printk("%s", page);
-
-	/* print failing CCW area (maximum 4) */
-	/* scsw->cda is either valid or zero  */
-	len = 0;
-	from = ++to;
-	fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
-	if (from <  fail - 2) {
-		from = fail - 2;     /* there is a gap - print header */
-		len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
-	}
-	to = min(fail + 1, last);
-	len += dasd_eckd_dump_ccw_range(from, to, page + len);
-
-	/* print last CCWs (maximum 2) */
-	from = max(from, ++to);
-	if (from < last - 1) {
-		from = last - 1;     /* there is a gap - print header */
-		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
-	}
-	len += dasd_eckd_dump_ccw_range(from, last, page + len);
-	if (len > 0)
+	if (req) {
+		/* req == NULL for unsolicited interrupts */
+		/* dump the Channel Program (max 140 Bytes per line) */
+		/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+		first = req->cpaddr;
+		for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+		to = min(first + 6, last);
+		len = sprintf(page,  KERN_ERR PRINTK_HEADER
+			      " Related CP in req: %p\n", req);
+		dasd_eckd_dump_ccw_range(first, to, page + len);
 		printk("%s", page);
+
+		/* print failing CCW area (maximum 4) */
+		/* scsw->cda is either valid or zero  */
+		len = 0;
+		from = ++to;
+		fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+		if (from <  fail - 2) {
+			from = fail - 2;     /* there is a gap - print header */
+			len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
+		}
+		to = min(fail + 1, last);
+		len += dasd_eckd_dump_ccw_range(from, to, page + len);
+
+		/* print last CCWs (maximum 2) */
+		from = max(from, ++to);
+		if (from < last - 1) {
+			from = last - 1;     /* there is a gap - print header */
+			len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+		}
+		len += dasd_eckd_dump_ccw_range(from, last, page + len);
+		if (len > 0)
+			printk("%s", page);
+	}
 	free_page((unsigned long) page);
 }
 
@@ -1796,16 +2155,20 @@
 	.ebcname = "ECKD",
 	.max_blocks = 240,
 	.check_device = dasd_eckd_check_characteristics,
+	.uncheck_device = dasd_eckd_uncheck_device,
 	.do_analysis = dasd_eckd_do_analysis,
+	.ready_to_online = dasd_eckd_ready_to_online,
+	.online_to_ready = dasd_eckd_online_to_ready,
 	.fill_geometry = dasd_eckd_fill_geometry,
 	.start_IO = dasd_start_IO,
 	.term_IO = dasd_term_IO,
+	.handle_terminated_request = dasd_eckd_handle_terminated_request,
 	.format_device = dasd_eckd_format_device,
-	.examine_error = dasd_eckd_examine_error,
 	.erp_action = dasd_eckd_erp_action,
 	.erp_postaction = dasd_eckd_erp_postaction,
-	.build_cp = dasd_eckd_build_cp,
-	.free_cp = dasd_eckd_free_cp,
+	.handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+	.build_cp = dasd_eckd_build_alias_cp,
+	.free_cp = dasd_eckd_free_alias_cp,
 	.dump_sense = dasd_eckd_dump_sense,
 	.fill_info = dasd_eckd_fill_info,
 	.ioctl = dasd_eckd_ioctl,
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 712ff16..fc2509c 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -39,6 +39,8 @@
 #define DASD_ECKD_CCW_READ_CKD_MT	 0x9e
 #define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d
 #define DASD_ECKD_CCW_RESERVE		 0xB4
+#define DASD_ECKD_CCW_PFX		 0xE7
+#define DASD_ECKD_CCW_RSCK		 0xF9
 
 /*
  * Perform Subsystem Function / Sub-Orders
@@ -137,6 +139,25 @@
 	__u16 length;
 } __attribute__ ((packed));
 
+/* Prefix data for format 0x00 and 0x01 */
+struct PFX_eckd_data {
+	unsigned char format;
+	struct {
+		unsigned char define_extend:1;
+		unsigned char time_stamp:1;
+		unsigned char verify_base:1;
+		unsigned char hyper_pav:1;
+		unsigned char reserved:4;
+	} __attribute__ ((packed)) validity;
+	__u8 base_address;
+	__u8 aux;
+	__u8 base_lss;
+	__u8 reserved[7];
+	struct DE_eckd_data define_extend;
+	struct LO_eckd_data locate_record;
+	__u8 LO_extended_data[4];
+} __attribute__ ((packed));
+
 struct dasd_eckd_characteristics {
 	__u16 cu_type;
 	struct {
@@ -254,7 +275,9 @@
 		} __attribute__ ((packed)) ned;
 		struct {
 			unsigned char flags;            /* byte  0    */
-			unsigned char res2[7];          /* byte  1- 7 */
+			unsigned char res1;		/* byte  1    */
+			__u16 format;			/* byte  2-3  */
+			unsigned char res2[4];		/* byte  4-7  */
 			unsigned char sua_flags;	/* byte  8    */
 			__u8 base_unit_addr;            /* byte  9    */
 			unsigned char res3[22];	        /* byte 10-31 */
@@ -343,6 +366,11 @@
 	__u8 npm;
 };
 
+struct dasd_rssd_features {
+	char feature[256];
+} __attribute__((packed));
+
+
 /*
  * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
@@ -365,4 +393,99 @@
 	unsigned char reserved[59];
 } __attribute__((packed));
 
+
+/*
+ * some structures and definitions for alias handling
+ */
+struct dasd_unit_address_configuration {
+	struct {
+		char ua_type;
+		char base_ua;
+	} unit[256];
+} __attribute__((packed));
+
+
+#define MAX_DEVICES_PER_LCU 256
+
+/* flags on the LCU  */
+#define NEED_UAC_UPDATE  0x01
+#define UPDATE_PENDING	0x02
+
+enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
+
+
+struct alias_root {
+	struct list_head serverlist;
+	spinlock_t lock;
+};
+
+struct alias_server {
+	struct list_head server;
+	struct dasd_uid uid;
+	struct list_head lculist;
+};
+
+struct summary_unit_check_work_data {
+	char reason;
+	struct dasd_device *device;
+	struct work_struct worker;
+};
+
+struct read_uac_work_data {
+	struct dasd_device *device;
+	struct delayed_work dwork;
+};
+
+struct alias_lcu {
+	struct list_head lcu;
+	struct dasd_uid uid;
+	enum pavtype pav;
+	char flags;
+	spinlock_t lock;
+	struct list_head grouplist;
+	struct list_head active_devices;
+	struct list_head inactive_devices;
+	struct dasd_unit_address_configuration *uac;
+	struct summary_unit_check_work_data suc_data;
+	struct read_uac_work_data ruac_data;
+	struct dasd_ccw_req *rsu_cqr;
+};
+
+struct alias_pav_group {
+	struct list_head group;
+	struct dasd_uid uid;
+	struct alias_lcu *lcu;
+	struct list_head baselist;
+	struct list_head aliaslist;
+	struct dasd_device *next;
+};
+
+
+struct dasd_eckd_private {
+	struct dasd_eckd_characteristics rdc_data;
+	struct dasd_eckd_confdata conf_data;
+	struct dasd_eckd_path path_data;
+	struct eckd_count count_area[5];
+	int init_cqr_status;
+	int uses_cdl;
+	struct attrib_data_t attrib;	/* e.g. cache operations */
+	struct dasd_rssd_features features;
+
+	/* alias managemnet */
+	struct dasd_uid uid;
+	struct alias_pav_group *pavgroup;
+	struct alias_lcu *lcu;
+	int count;
+};
+
+
+
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
+int dasd_alias_add_device(struct dasd_device *);
+int dasd_alias_remove_device(struct dasd_device *);
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
+void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
+
 #endif				/* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 0c081a6..6e53ab6 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -336,7 +336,7 @@
 	unsigned long flags;
 	struct eerbuffer *eerb;
 
-	snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	if (snss_rc)
 		data_size = 0;
 	else
@@ -404,10 +404,11 @@
 		set_bit(DASD_FLAG_EER_SNSS, &device->flags);
 		return;
 	}
+	/* cdev is already locked, can't use dasd_add_request_head */
 	clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
 	cqr->status = DASD_CQR_QUEUED;
-	list_add(&cqr->list, &device->ccw_queue);
-	dasd_schedule_bh(device);
+	list_add(&cqr->devlist, &device->ccw_queue);
+	dasd_schedule_device_bh(device);
 }
 
 /*
@@ -415,7 +416,7 @@
  */
 static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
 {
-        struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	unsigned long flags;
 
 	dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
@@ -458,7 +459,7 @@
 	if (!cqr)
 		return -ENOMEM;
 
-	cqr->device = device;
+	cqr->startdev = device;
 	cqr->retries = 255;
 	cqr->expires = 10 * HZ;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index caa5d91..8f10000 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -46,6 +46,8 @@
 	if (cqr == NULL)
 		return ERR_PTR(-ENOMEM);
 	memset(cqr, 0, sizeof(struct dasd_ccw_req));
+	INIT_LIST_HEAD(&cqr->devlist);
+	INIT_LIST_HEAD(&cqr->blocklist);
 	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
 	cqr->cpaddr = NULL;
 	if (cplength > 0) {
@@ -66,7 +68,7 @@
 }
 
 void
-dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
 {
 	unsigned long flags;
 
@@ -81,11 +83,11 @@
  * dasd_default_erp_action just retries the current cqr
  */
 struct dasd_ccw_req *
-dasd_default_erp_action(struct dasd_ccw_req * cqr)
+dasd_default_erp_action(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
@@ -93,12 +95,12 @@
                              "default ERP called (%i retries left)",
                              cqr->retries);
 		cqr->lpm    = LPM_ANYPATH;
-		cqr->status = DASD_CQR_QUEUED;
+		cqr->status = DASD_CQR_FILLED;
         } else {
                 DEV_MESSAGE (KERN_WARNING, device, "%s",
 			     "default ERP called (NO retry left)");
 		cqr->status = DASD_CQR_FAILED;
-		cqr->stopclk = get_clock ();
+		cqr->stopclk = get_clock();
         }
         return cqr;
 }				/* end dasd_default_erp_action */
@@ -117,15 +119,12 @@
  * RETURN VALUES
  *   cqr		pointer to the original CQR
  */
-struct dasd_ccw_req *
-dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
+struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device;
 	int success;
 
 	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
 
-	device = cqr->device;
 	success = cqr->status == DASD_CQR_DONE;
 
 	/* free all ERPs - but NOT the original cqr */
@@ -133,10 +132,10 @@
 		struct dasd_ccw_req *refers;
 
 		refers = cqr->refers;
-		/* remove the request from the device queue */
-		list_del(&cqr->list);
+		/* remove the request from the block queue */
+		list_del(&cqr->blocklist);
 		/* free the finished erp request */
-		dasd_free_erp_request(cqr, device);
+		dasd_free_erp_request(cqr, cqr->memdev);
 		cqr = refers;
 	}
 
@@ -157,7 +156,7 @@
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	/* dump sense data */
 	if (device->discipline && device->discipline->dump_sense)
 		device->discipline->dump_sense(device, cqr, irb);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 1d95822..d13ea05 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -117,6 +117,7 @@
 static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
+	struct dasd_block *block;
 	struct dasd_fba_private *private;
 	struct ccw_device *cdev = device->cdev;
 	void *rdc_data;
@@ -133,6 +134,16 @@
 		}
 		device->private = (void *) private;
 	}
+	block = dasd_alloc_block();
+	if (IS_ERR(block)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "could not allocate dasd block structure");
+		kfree(device->private);
+		return PTR_ERR(block);
+	}
+	device->block = block;
+	block->base = device;
+
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
@@ -155,60 +166,37 @@
 	return 0;
 }
 
-static int
-dasd_fba_do_analysis(struct dasd_device *device)
+static int dasd_fba_do_analysis(struct dasd_block *block)
 {
 	struct dasd_fba_private *private;
 	int sb, rc;
 
-	private = (struct dasd_fba_private *) device->private;
+	private = (struct dasd_fba_private *) block->base->private;
 	rc = dasd_check_blocksize(private->rdc_data.blk_size);
 	if (rc) {
-		DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
+		DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
 			    private->rdc_data.blk_size);
 		return rc;
 	}
-	device->blocks = private->rdc_data.blk_bdsa;
-	device->bp_block = private->rdc_data.blk_size;
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	block->blocks = private->rdc_data.blk_bdsa;
+	block->bp_block = private->rdc_data.blk_size;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
-		device->s2b_shift++;
+		block->s2b_shift++;
 	return 0;
 }
 
-static int
-dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+static int dasd_fba_fill_geometry(struct dasd_block *block,
+				  struct hd_geometry *geo)
 {
-	if (dasd_check_blocksize(device->bp_block) != 0)
+	if (dasd_check_blocksize(block->bp_block) != 0)
 		return -EINVAL;
-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->s2b_shift;
+	geo->sectors = 128 >> block->s2b_shift;
 	return 0;
 }
 
-static dasd_era_t
-dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	struct dasd_device *device;
-	struct ccw_device *cdev;
-
-	device = (struct dasd_device *) cqr->device;
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	cdev = device->cdev;
-	switch (cdev->id.dev_type) {
-	case 0x3370:
-		return dasd_3370_erp_examine(cqr, irb);
-	case 0x9336:
-		return dasd_9336_erp_examine(cqr, irb);
-	default:
-		return dasd_era_recover;
-	}
-}
-
 static dasd_erp_fn_t
 dasd_fba_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -221,13 +209,34 @@
 	if (cqr->function == dasd_default_erp_action)
 		return dasd_default_erp_postaction;
 
-	DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
+	DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
 		    cqr->function);
 	return NULL;
 }
 
-static struct dasd_ccw_req *
-dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
+						   struct irb *irb)
+{
+	char mask;
+
+	/* first of all check for state change pending interrupt */
+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+	if ((irb->scsw.dstat & mask) == mask) {
+		dasd_generic_handle_state_change(device);
+		return;
+	}
+
+	/* check for unsolicited interrupts */
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "unsolicited interrupt received");
+	device->discipline->dump_sense(device, NULL, irb);
+	dasd_schedule_device_bh(device);
+	return;
+};
+
+static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
+					      struct dasd_block *block,
+					      struct request *req)
 {
 	struct dasd_fba_private *private;
 	unsigned long *idaws;
@@ -242,17 +251,17 @@
 	unsigned int blksize, off;
 	unsigned char cmd;
 
-	private = (struct dasd_fba_private *) device->private;
+	private = (struct dasd_fba_private *) block->base->private;
 	if (rq_data_dir(req) == READ) {
 		cmd = DASD_FBA_CCW_READ;
 	} else if (rq_data_dir(req) == WRITE) {
 		cmd = DASD_FBA_CCW_WRITE;
 	} else
 		return ERR_PTR(-EINVAL);
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	/* Calculate record id of first and last block. */
-	first_rec = req->sector >> device->s2b_shift;
-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	first_rec = req->sector >> block->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	cidaw = 0;
@@ -260,7 +269,7 @@
 		if (bv->bv_len & (blksize - 1))
 			/* Fba can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
 			cidaw += bv->bv_len / blksize;
@@ -284,13 +293,13 @@
 	}
 	/* Allocate the ccw request. */
 	cqr = dasd_smalloc_request(dasd_fba_discipline.name,
-				   cplength, datasize, device);
+				   cplength, datasize, memdev);
 	if (IS_ERR(cqr))
 		return cqr;
 	ccw = cqr->cpaddr;
 	/* First ccw is define extent. */
 	define_extent(ccw++, cqr->data, rq_data_dir(req),
-		      device->bp_block, req->sector, req->nr_sectors);
+		      block->bp_block, req->sector, req->nr_sectors);
 	/* Build locate_record + read/write ccws. */
 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
 	LO_data = (struct LO_fba_data *) (idaws + cidaw);
@@ -326,7 +335,7 @@
 					ccw[-1].flags |= CCW_FLAG_CC;
 			}
 			ccw->cmd_code = cmd;
-			ccw->count = device->bp_block;
+			ccw->count = block->bp_block;
 			if (idal_is_needed(dst, blksize)) {
 				ccw->cda = (__u32)(addr_t) idaws;
 				ccw->flags = CCW_FLAG_IDA;
@@ -342,7 +351,9 @@
 	}
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = memdev;
+	cqr->memdev = memdev;
+	cqr->block = block;
 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
 	cqr->retries = 32;
 	cqr->buildclk = get_clock();
@@ -363,8 +374,8 @@
 
 	if (!dasd_page_cache)
 		goto out;
-	private = (struct dasd_fba_private *) cqr->device->private;
-	blksize = cqr->device->bp_block;
+	private = (struct dasd_fba_private *) cqr->block->base->private;
+	blksize = cqr->block->bp_block;
 	ccw = cqr->cpaddr;
 	/* Skip over define extent & locate record. */
 	ccw++;
@@ -394,10 +405,15 @@
 	}
 out:
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+	cqr->status = DASD_CQR_FILLED;
+};
+
 static int
 dasd_fba_fill_info(struct dasd_device * device,
 		   struct dasd_information2_t * info)
@@ -546,9 +562,10 @@
 	.fill_geometry = dasd_fba_fill_geometry,
 	.start_IO = dasd_start_IO,
 	.term_IO = dasd_term_IO,
-	.examine_error = dasd_fba_examine_error,
+	.handle_terminated_request = dasd_fba_handle_terminated_request,
 	.erp_action = dasd_fba_erp_action,
 	.erp_postaction = dasd_fba_erp_postaction,
+	.handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
 	.build_cp = dasd_fba_build_cp,
 	.free_cp = dasd_fba_free_cp,
 	.dump_sense = dasd_fba_dump_sense,
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 47ba446..aee6565 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -25,14 +25,15 @@
 /*
  * Allocate and register gendisk structure for device.
  */
-int
-dasd_gendisk_alloc(struct dasd_device *device)
+int dasd_gendisk_alloc(struct dasd_block *block)
 {
 	struct gendisk *gdp;
+	struct dasd_device *base;
 	int len;
 
 	/* Make sure the minor for this device exists. */
-	if (device->devindex >= DASD_PER_MAJOR)
+	base = block->base;
+	if (base->devindex >= DASD_PER_MAJOR)
 		return -EBUSY;
 
 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
@@ -41,9 +42,9 @@
 
 	/* Initialize gendisk structure. */
 	gdp->major = DASD_MAJOR;
-	gdp->first_minor = device->devindex << DASD_PARTN_BITS;
+	gdp->first_minor = base->devindex << DASD_PARTN_BITS;
 	gdp->fops = &dasd_device_operations;
-	gdp->driverfs_dev = &device->cdev->dev;
+	gdp->driverfs_dev = &base->cdev->dev;
 
 	/*
 	 * Set device name.
@@ -53,53 +54,51 @@
 	 *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
 	 */
 	len = sprintf(gdp->disk_name, "dasd");
-	if (device->devindex > 25) {
-	        if (device->devindex > 701) {
-		        if (device->devindex > 18277)
+	if (base->devindex > 25) {
+		if (base->devindex > 701) {
+			if (base->devindex > 18277)
 			        len += sprintf(gdp->disk_name + len, "%c",
-					       'a'+(((device->devindex-18278)
+					       'a'+(((base->devindex-18278)
 						     /17576)%26));
 			len += sprintf(gdp->disk_name + len, "%c",
-				       'a'+(((device->devindex-702)/676)%26));
+				       'a'+(((base->devindex-702)/676)%26));
 		}
 		len += sprintf(gdp->disk_name + len, "%c",
-			       'a'+(((device->devindex-26)/26)%26));
+			       'a'+(((base->devindex-26)/26)%26));
 	}
-	len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
+	len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
 
-	if (device->features & DASD_FEATURE_READONLY)
+	if (block->base->features & DASD_FEATURE_READONLY)
 		set_disk_ro(gdp, 1);
-	gdp->private_data = device;
-	gdp->queue = device->request_queue;
-	device->gdp = gdp;
-	set_capacity(device->gdp, 0);
-	add_disk(device->gdp);
+	gdp->private_data = block;
+	gdp->queue = block->request_queue;
+	block->gdp = gdp;
+	set_capacity(block->gdp, 0);
+	add_disk(block->gdp);
 	return 0;
 }
 
 /*
  * Unregister and free gendisk structure for device.
  */
-void
-dasd_gendisk_free(struct dasd_device *device)
+void dasd_gendisk_free(struct dasd_block *block)
 {
-	if (device->gdp) {
-		del_gendisk(device->gdp);
-		device->gdp->queue = NULL;
-		put_disk(device->gdp);
-		device->gdp = NULL;
+	if (block->gdp) {
+		del_gendisk(block->gdp);
+		block->gdp->queue = NULL;
+		put_disk(block->gdp);
+		block->gdp = NULL;
 	}
 }
 
 /*
  * Trigger a partition detection.
  */
-int
-dasd_scan_partitions(struct dasd_device * device)
+int dasd_scan_partitions(struct dasd_block *block)
 {
 	struct block_device *bdev;
 
-	bdev = bdget_disk(device->gdp, 0);
+	bdev = bdget_disk(block->gdp, 0);
 	if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
 		return -ENODEV;
 	/*
@@ -117,7 +116,7 @@
 	 * is why the assignment to device->bdev is done AFTER
 	 * the BLKRRPART ioctl.
 	 */
-	device->bdev = bdev;
+	block->bdev = bdev;
 	return 0;
 }
 
@@ -125,8 +124,7 @@
  * Remove all inodes in the system for a device, delete the
  * partitions and make device unusable by setting its size to zero.
  */
-void
-dasd_destroy_partitions(struct dasd_device * device)
+void dasd_destroy_partitions(struct dasd_block *block)
 {
 	/* The two structs have 168/176 byte on 31/64 bit. */
 	struct blkpg_partition bpart;
@@ -137,8 +135,8 @@
 	 * Get the bdev pointer from the device structure and clear
 	 * device->bdev to lower the offline open_count limit again.
 	 */
-	bdev = device->bdev;
-	device->bdev = NULL;
+	bdev = block->bdev;
+	block->bdev = NULL;
 
 	/*
 	 * See fs/partition/check.c:delete_partition
@@ -149,17 +147,16 @@
 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
 	barg.data = (void __force __user *) &bpart;
 	barg.op = BLKPG_DEL_PARTITION;
-	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
+	for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
 
-	invalidate_partition(device->gdp, 0);
+	invalidate_partition(block->gdp, 0);
 	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
 	blkdev_put(bdev);
-	set_capacity(device->gdp, 0);
+	set_capacity(block->gdp, 0);
 }
 
-int
-dasd_gendisk_init(void)
+int dasd_gendisk_init(void)
 {
 	int rc;
 
@@ -174,8 +171,7 @@
 	return 0;
 }
 
-void
-dasd_gendisk_exit(void)
+void dasd_gendisk_exit(void)
 {
 	unregister_blkdev(DASD_MAJOR, "dasd");
 }
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index d427dae..44b2984 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -64,13 +64,7 @@
  * SECTION: Type definitions
  */
 struct dasd_device;
-
-typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover		     */
-	dasd_era_none = 0,	/* don't recover, everything alright */
-	dasd_era_msg = 1,	/* don't recover, just report...     */
-	dasd_era_recover = 2	/* recovery action recommended	     */
-} dasd_era_t;
+struct dasd_block;
 
 /* BIT DEFINITIONS FOR SENSE DATA */
 #define DASD_SENSE_BIT_0 0x80
@@ -151,19 +145,22 @@
 
 struct dasd_ccw_req {
 	unsigned int magic;		/* Eye catcher */
-        struct list_head list;		/* list_head for request queueing. */
+	struct list_head devlist;	/* for dasd_device request queue */
+	struct list_head blocklist;	/* for dasd_block request queue */
 
 	/* Where to execute what... */
-	struct dasd_device *device;	/* device the request is for */
+	struct dasd_block *block;	/* the originating block device */
+	struct dasd_device *memdev;	/* the device used to allocate this */
+	struct dasd_device *startdev;	/* device the request is started on */
 	struct ccw1 *cpaddr;		/* address of channel program */
-	char status;	        	/* status of this request */
+	char status;			/* status of this request */
 	short retries;			/* A retry counter */
 	unsigned long flags;        	/* flags of this request */
 
 	/* ... and how */
 	unsigned long starttime;	/* jiffies time of request start */
 	int expires;			/* expiration period in jiffies */
-	char lpm;               	/* logical path mask */
+	char lpm;			/* logical path mask */
 	void *data;			/* pointer to data area */
 
 	/* these are important for recovering erroneous requests          */
@@ -178,20 +175,27 @@
 	unsigned long long endclk;	/* TOD-clock of request termination */
 
         /* Callback that is called after reaching final status. */
-        void (*callback)(struct dasd_ccw_req *, void *data);
-        void *callback_data;
+	void (*callback)(struct dasd_ccw_req *, void *data);
+	void *callback_data;
 };
 
 /*
  * dasd_ccw_req -> status can be:
  */
-#define DASD_CQR_FILLED   0x00	/* request is ready to be processed */
-#define DASD_CQR_QUEUED   0x01	/* request is queued to be processed */
-#define DASD_CQR_IN_IO    0x02	/* request is currently in IO */
-#define DASD_CQR_DONE     0x03	/* request is completed successfully */
-#define DASD_CQR_ERROR    0x04	/* request is completed with error */
-#define DASD_CQR_FAILED   0x05	/* request is finally failed */
-#define DASD_CQR_CLEAR    0x06	/* request is clear pending */
+#define DASD_CQR_FILLED 	0x00	/* request is ready to be processed */
+#define DASD_CQR_DONE		0x01	/* request is completed successfully */
+#define DASD_CQR_NEED_ERP	0x02	/* request needs recovery action */
+#define DASD_CQR_IN_ERP 	0x03	/* request is in recovery */
+#define DASD_CQR_FAILED 	0x04	/* request is finally failed */
+#define DASD_CQR_TERMINATED	0x05	/* request was stopped by driver */
+
+#define DASD_CQR_QUEUED 	0x80	/* request is queued to be processed */
+#define DASD_CQR_IN_IO		0x81	/* request is currently in IO */
+#define DASD_CQR_ERROR		0x82	/* request is completed with error */
+#define DASD_CQR_CLEAR_PENDING	0x83	/* request is clear pending */
+#define DASD_CQR_CLEARED	0x84	/* request was cleared */
+#define DASD_CQR_SUCCESS	0x85	/* request was successfull */
+
 
 /* per dasd_ccw_req flags */
 #define DASD_CQR_FLAGS_USE_ERP   0	/* use ERP for this request */
@@ -214,52 +218,71 @@
 
 	struct list_head list;	/* used for list of disciplines */
 
-        /*
-         * Device recognition functions. check_device is used to verify
-         * the sense data and the information returned by read device
-         * characteristics. It returns 0 if the discipline can be used
-         * for the device in question.
-         * do_analysis is used in the step from device state "basic" to
-         * state "accept". It returns 0 if the device can be made ready,
-         * it returns -EMEDIUMTYPE if the device can't be made ready or
-         * -EAGAIN if do_analysis started a ccw that needs to complete
-         * before the analysis may be repeated.
-         */
-        int (*check_device)(struct dasd_device *);
-	int (*do_analysis) (struct dasd_device *);
+	/*
+	 * Device recognition functions. check_device is used to verify
+	 * the sense data and the information returned by read device
+	 * characteristics. It returns 0 if the discipline can be used
+	 * for the device in question. uncheck_device is called during
+	 * device shutdown to deregister a device from its discipline.
+	 */
+	int (*check_device) (struct dasd_device *);
+	void (*uncheck_device) (struct dasd_device *);
 
-        /*
-         * Device operation functions. build_cp creates a ccw chain for
-         * a block device request, start_io starts the request and
-         * term_IO cancels it (e.g. in case of a timeout). format_device
-         * returns a ccw chain to be used to format the device.
-         */
+	/*
+	 * do_analysis is used in the step from device state "basic" to
+	 * state "accept". It returns 0 if the device can be made ready,
+	 * it returns -EMEDIUMTYPE if the device can't be made ready or
+	 * -EAGAIN if do_analysis started a ccw that needs to complete
+	 * before the analysis may be repeated.
+	 */
+	int (*do_analysis) (struct dasd_block *);
+
+	/*
+	 * Last things to do when a device is set online, and first things
+	 * when it is set offline.
+	 */
+	int (*ready_to_online) (struct dasd_device *);
+	int (*online_to_ready) (struct dasd_device *);
+
+	/*
+	 * Device operation functions. build_cp creates a ccw chain for
+	 * a block device request, start_io starts the request and
+	 * term_IO cancels it (e.g. in case of a timeout). format_device
+	 * returns a ccw chain to be used to format the device.
+	 * handle_terminated_request allows to examine a cqr and prepare
+	 * it for retry.
+	 */
 	struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
+					  struct dasd_block *,
 					  struct request *);
 	int (*start_IO) (struct dasd_ccw_req *);
 	int (*term_IO) (struct dasd_ccw_req *);
+	void (*handle_terminated_request) (struct dasd_ccw_req *);
 	struct dasd_ccw_req *(*format_device) (struct dasd_device *,
 					       struct format_data_t *);
 	int (*free_cp) (struct dasd_ccw_req *, struct request *);
-        /*
-         * Error recovery functions. examine_error() returns a value that
-         * indicates what to do for an error condition. If examine_error()
+
+	/*
+	 * Error recovery functions. examine_error() returns a value that
+	 * indicates what to do for an error condition. If examine_error()
 	 * returns 'dasd_era_recover' erp_action() is called to create a
-         * special error recovery ccw. erp_postaction() is called after
-         * an error recovery ccw has finished its execution. dump_sense
-         * is called for every error condition to print the sense data
-         * to the console.
-         */
-	dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
+	 * special error recovery ccw. erp_postaction() is called after
+	 * an error recovery ccw has finished its execution. dump_sense
+	 * is called for every error condition to print the sense data
+	 * to the console.
+	 */
 	dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
 	dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
 	void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
 			    struct irb *);
 
+	void (*handle_unsolicited_interrupt) (struct dasd_device *,
+					      struct irb *);
+
         /* i/o control functions. */
-	int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
+	int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
 	int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
-	int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
+	int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -267,12 +290,18 @@
 /*
  * Unique identifier for dasd device.
  */
+#define UA_NOT_CONFIGURED  0x00
+#define UA_BASE_DEVICE	   0x01
+#define UA_BASE_PAV_ALIAS  0x02
+#define UA_HYPER_PAV_ALIAS 0x03
+
 struct dasd_uid {
-	__u8 alias;
+	__u8 type;
 	char vendor[4];
 	char serial[15];
 	__u16 ssid;
-	__u8 unit_addr;
+	__u8 real_unit_addr;
+	__u8 base_unit_addr;
 };
 
 /*
@@ -293,14 +322,9 @@
 
 struct dasd_device {
 	/* Block device stuff. */
-	struct gendisk *gdp;
-	struct request_queue *request_queue;
-	spinlock_t request_queue_lock;
-	struct block_device *bdev;
+	struct dasd_block *block;
+
         unsigned int devindex;
-	unsigned long blocks;	   /* size of volume in blocks */
-	unsigned int bp_block;	   /* bytes per block */
-	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
 	unsigned long flags;	   /* per device flags */
 	unsigned short features;   /* copy of devmap-features (read-only!) */
 
@@ -316,9 +340,8 @@
 	int state, target;
 	int stopped;		/* device (ccw_device_start) was stopped */
 
-	/* Open and reference count. */
+	/* reference count. */
         atomic_t ref_count;
-	atomic_t open_count;
 
 	/* ccw queue and memory for static ccw/erp buffers. */
 	struct list_head ccw_queue;
@@ -337,20 +360,45 @@
 
 	struct ccw_device *cdev;
 
+	/* hook for alias management */
+	struct list_head alias_list;
+};
+
+struct dasd_block {
+	/* Block device stuff. */
+	struct gendisk *gdp;
+	struct request_queue *request_queue;
+	spinlock_t request_queue_lock;
+	struct block_device *bdev;
+	atomic_t open_count;
+
+	unsigned long blocks;	   /* size of volume in blocks */
+	unsigned int bp_block;	   /* bytes per block */
+	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
+
+	struct dasd_device *base;
+	struct list_head ccw_queue;
+	spinlock_t queue_lock;
+
+	atomic_t tasklet_scheduled;
+	struct tasklet_struct tasklet;
+	struct timer_list timer;
+
 #ifdef CONFIG_DASD_PROFILE
 	struct dasd_profile_info_t profile;
 #endif
 };
 
+
+
 /* reasons why device (ccw_device_start) was stopped */
 #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
 #define DASD_STOPPED_QUIESCE 2         /* Quiesced */
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
-#define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
+#define DASD_STOPPED_SU      16        /* summary unit check handling */
 
 /* per device flags */
-#define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
 #define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
 #define DASD_FLAG_EER_SNSS	4	/* A SNSS is required */
 #define DASD_FLAG_EER_IN_USE	5	/* A SNSS request is running */
@@ -489,6 +537,9 @@
 struct dasd_device *dasd_alloc_device(void);
 void dasd_free_device(struct dasd_device *);
 
+struct dasd_block *dasd_alloc_block(void);
+void dasd_free_block(struct dasd_block *);
+
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
@@ -497,18 +548,23 @@
 void dasd_add_request_tail(struct dasd_ccw_req *);
 int  dasd_start_IO(struct dasd_ccw_req *);
 int  dasd_term_IO(struct dasd_ccw_req *);
-void dasd_schedule_bh(struct dasd_device *);
+void dasd_schedule_device_bh(struct dasd_device *);
+void dasd_schedule_block_bh(struct dasd_block *);
 int  dasd_sleep_on(struct dasd_ccw_req *);
 int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
 int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
-void dasd_set_timer(struct dasd_device *, int);
-void dasd_clear_timer(struct dasd_device *);
+void dasd_device_set_timer(struct dasd_device *, int);
+void dasd_device_clear_timer(struct dasd_device *);
+void dasd_block_set_timer(struct dasd_block *, int);
+void dasd_block_clear_timer(struct dasd_block *);
 int  dasd_cancel_req(struct dasd_ccw_req *);
+int dasd_flush_device_queue(struct dasd_device *);
 int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
 void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
+void dasd_generic_handle_state_change(struct dasd_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
 
@@ -542,10 +598,10 @@
 /* externals in dasd_gendisk.c */
 int  dasd_gendisk_init(void);
 void dasd_gendisk_exit(void);
-int dasd_gendisk_alloc(struct dasd_device *);
-void dasd_gendisk_free(struct dasd_device *);
-int dasd_scan_partitions(struct dasd_device *);
-void dasd_destroy_partitions(struct dasd_device *);
+int dasd_gendisk_alloc(struct dasd_block *);
+void dasd_gendisk_free(struct dasd_block *);
+int dasd_scan_partitions(struct dasd_block *);
+void dasd_destroy_partitions(struct dasd_block *);
 
 /* externals in dasd_ioctl.c */
 int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
@@ -563,20 +619,9 @@
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
 
-/* externals in dasd_3370_erp.c */
-dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
-
 /* externals in dasd_3990_erp.c */
-dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
 struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
 
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
-
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
-struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
-
 /* externals in dasd_eer.c */
 #ifdef CONFIG_DASD_EER
 int dasd_eer_init(void);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 672eb0a..91a6463 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -38,15 +38,15 @@
 static int
 dasd_ioctl_enable(struct block_device *bdev)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	dasd_enable_device(device);
+	dasd_enable_device(block->base);
 	/* Formatting the dasd device can change the capacity. */
 	mutex_lock(&bdev->bd_mutex);
-	i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
+	i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
 	mutex_unlock(&bdev->bd_mutex);
 	return 0;
 }
@@ -58,7 +58,7 @@
 static int
 dasd_ioctl_disable(struct block_device *bdev)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -71,7 +71,7 @@
 	 * using the BIODASDFMT ioctl. Therefore the correct state for the
 	 * device is DASD_STATE_BASIC that allows to do basic i/o.
 	 */
-	dasd_set_target_state(device, DASD_STATE_BASIC);
+	dasd_set_target_state(block->base, DASD_STATE_BASIC);
 	/*
 	 * Set i_size to zero, since read, write, etc. check against this
 	 * value.
@@ -85,19 +85,19 @@
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_quiesce(struct dasd_device *device)
+static int dasd_ioctl_quiesce(struct dasd_block *block)
 {
 	unsigned long flags;
+	struct dasd_device *base;
 
+	base = block->base;
 	if (!capable (CAP_SYS_ADMIN))
 		return -EACCES;
 
-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
-		     "Quiesce IO on device");
-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped |= DASD_STOPPED_QUIESCE;
-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+	base->stopped |= DASD_STOPPED_QUIESCE;
+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 	return 0;
 }
 
@@ -105,22 +105,21 @@
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_resume(struct dasd_device *device)
+static int dasd_ioctl_resume(struct dasd_block *block)
 {
 	unsigned long flags;
+	struct dasd_device *base;
 
+	base = block->base;
 	if (!capable (CAP_SYS_ADMIN))
 		return -EACCES;
 
-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
-		     "resume IO on device");
+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+	base->stopped &= ~DASD_STOPPED_QUIESCE;
+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 
-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped &= ~DASD_STOPPED_QUIESCE;
-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-
-	dasd_schedule_bh (device);
+	dasd_schedule_block_bh(block);
 	return 0;
 }
 
@@ -130,22 +129,23 @@
  * commands to format a single unit of the device. In terms of the ECKD
  * devices this means CCWs are generated to format a single track.
  */
-static int
-dasd_format(struct dasd_device * device, struct format_data_t * fdata)
+static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
 {
 	struct dasd_ccw_req *cqr;
+	struct dasd_device *base;
 	int rc;
 
-	if (device->discipline->format_device == NULL)
+	base = block->base;
+	if (base->discipline->format_device == NULL)
 		return -EPERM;
 
-	if (device->state != DASD_STATE_BASIC) {
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
+	if (base->state != DASD_STATE_BASIC) {
+		DEV_MESSAGE(KERN_WARNING, base, "%s",
 			    "dasd_format: device is not disabled! ");
 		return -EBUSY;
 	}
 
-	DBF_DEV_EVENT(DBF_NOTICE, device,
+	DBF_DEV_EVENT(DBF_NOTICE, base,
 		      "formatting units %d to %d (%d B blocks) flags %d",
 		      fdata->start_unit,
 		      fdata->stop_unit, fdata->blksize, fdata->intensity);
@@ -156,20 +156,20 @@
 	 * enabling the device later.
 	 */
 	if (fdata->start_unit == 0) {
-		struct block_device *bdev = bdget_disk(device->gdp, 0);
+		struct block_device *bdev = bdget_disk(block->gdp, 0);
 		bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
 		bdput(bdev);
 	}
 
 	while (fdata->start_unit <= fdata->stop_unit) {
-		cqr = device->discipline->format_device(device, fdata);
+		cqr = base->discipline->format_device(base, fdata);
 		if (IS_ERR(cqr))
 			return PTR_ERR(cqr);
 		rc = dasd_sleep_on_interruptible(cqr);
-		dasd_sfree_request(cqr, cqr->device);
+		dasd_sfree_request(cqr, cqr->memdev);
 		if (rc) {
 			if (rc != -ERESTARTSYS)
-				DEV_MESSAGE(KERN_ERR, device,
+				DEV_MESSAGE(KERN_ERR, base,
 					    " Formatting of unit %d failed "
 					    "with rc = %d",
 					    fdata->start_unit, rc);
@@ -186,7 +186,7 @@
 static int
 dasd_ioctl_format(struct block_device *bdev, void __user *argp)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 	struct format_data_t fdata;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -194,51 +194,47 @@
 	if (!argp)
 		return -EINVAL;
 
-	if (device->features & DASD_FEATURE_READONLY)
+	if (block->base->features & DASD_FEATURE_READONLY)
 		return -EROFS;
 	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
 		return -EFAULT;
 	if (bdev != bdev->bd_contains) {
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
+		DEV_MESSAGE(KERN_WARNING, block->base, "%s",
 			    "Cannot low-level format a partition");
 		return -EINVAL;
 	}
-	return dasd_format(device, &fdata);
+	return dasd_format(block, &fdata);
 }
 
 #ifdef CONFIG_DASD_PROFILE
 /*
  * Reset device profile information
  */
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
-	memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
+	memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
 	return 0;
 }
 
 /*
  * Return device profile information
  */
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
 	if (dasd_profile_level == DASD_PROFILE_OFF)
 		return -EIO;
-	if (copy_to_user(argp, &device->profile,
-			 sizeof (struct dasd_profile_info_t)))
+	if (copy_to_user(argp, &block->profile,
+			 sizeof(struct dasd_profile_info_t)))
 		return -EFAULT;
 	return 0;
 }
 #else
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
 	return -ENOSYS;
 }
 
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
 	return -ENOSYS;
 }
@@ -247,87 +243,88 @@
 /*
  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
  */
-static int
-dasd_ioctl_information(struct dasd_device *device,
-		unsigned int cmd, void __user *argp)
+static int dasd_ioctl_information(struct dasd_block *block,
+				  unsigned int cmd, void __user *argp)
 {
 	struct dasd_information2_t *dasd_info;
 	unsigned long flags;
 	int rc;
+	struct dasd_device *base;
 	struct ccw_device *cdev;
 	struct ccw_dev_id dev_id;
 
-	if (!device->discipline->fill_info)
+	base = block->base;
+	if (!base->discipline->fill_info)
 		return -EINVAL;
 
 	dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
 	if (dasd_info == NULL)
 		return -ENOMEM;
 
-	rc = device->discipline->fill_info(device, dasd_info);
+	rc = base->discipline->fill_info(base, dasd_info);
 	if (rc) {
 		kfree(dasd_info);
 		return rc;
 	}
 
-	cdev = device->cdev;
+	cdev = base->cdev;
 	ccw_device_get_id(cdev, &dev_id);
 
 	dasd_info->devno = dev_id.devno;
-	dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
+	dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
 	dasd_info->cu_type = cdev->id.cu_type;
 	dasd_info->cu_model = cdev->id.cu_model;
 	dasd_info->dev_type = cdev->id.dev_type;
 	dasd_info->dev_model = cdev->id.dev_model;
-	dasd_info->status = device->state;
+	dasd_info->status = base->state;
 	/*
 	 * The open_count is increased for every opener, that includes
 	 * the blkdev_get in dasd_scan_partitions.
 	 * This must be hidden from user-space.
 	 */
-	dasd_info->open_count = atomic_read(&device->open_count);
-	if (!device->bdev)
+	dasd_info->open_count = atomic_read(&block->open_count);
+	if (!block->bdev)
 		dasd_info->open_count++;
 
 	/*
 	 * check if device is really formatted
 	 * LDL / CDL was returned by 'fill_info'
 	 */
-	if ((device->state < DASD_STATE_READY) ||
-	    (dasd_check_blocksize(device->bp_block)))
+	if ((base->state < DASD_STATE_READY) ||
+	    (dasd_check_blocksize(block->bp_block)))
 		dasd_info->format = DASD_FORMAT_NONE;
 
 	dasd_info->features |=
-		((device->features & DASD_FEATURE_READONLY) != 0);
+		((base->features & DASD_FEATURE_READONLY) != 0);
 
-	if (device->discipline)
-		memcpy(dasd_info->type, device->discipline->name, 4);
+	if (base->discipline)
+		memcpy(dasd_info->type, base->discipline->name, 4);
 	else
 		memcpy(dasd_info->type, "none", 4);
 
-	if (device->request_queue->request_fn) {
+	if (block->request_queue->request_fn) {
 		struct list_head *l;
 #ifdef DASD_EXTENDED_PROFILING
 		{
 			struct list_head *l;
-			spin_lock_irqsave(&device->lock, flags);
-			list_for_each(l, &device->request_queue->queue_head)
+			spin_lock_irqsave(&block->lock, flags);
+			list_for_each(l, &block->request_queue->queue_head)
 				dasd_info->req_queue_len++;
-			spin_unlock_irqrestore(&device->lock, flags);
+			spin_unlock_irqrestore(&block->lock, flags);
 		}
 #endif				/* DASD_EXTENDED_PROFILING */
-		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-		list_for_each(l, &device->ccw_queue)
+		spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+		list_for_each(l, &base->ccw_queue)
 			dasd_info->chanq_len++;
-		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+		spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
 				       flags);
 	}
 
 	rc = 0;
 	if (copy_to_user(argp, dasd_info,
 			 ((cmd == (unsigned int) BIODASDINFO2) ?
-			  sizeof (struct dasd_information2_t) :
-			  sizeof (struct dasd_information_t))))
+			  sizeof(struct dasd_information2_t) :
+			  sizeof(struct dasd_information_t))))
 		rc = -EFAULT;
 	kfree(dasd_info);
 	return rc;
@@ -339,7 +336,7 @@
 static int
 dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
 {
-	struct dasd_device *device =  bdev->bd_disk->private_data;
+	struct dasd_block *block =  bdev->bd_disk->private_data;
 	int intval;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -351,11 +348,10 @@
 		return -EFAULT;
 
 	set_disk_ro(bdev->bd_disk, intval);
-	return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
+	return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
 }
 
-static int
-dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
+static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
 		unsigned long arg)
 {
 	struct cmbdata __user *argp = (void __user *) arg;
@@ -363,7 +359,7 @@
 	struct cmbdata data;
 	int ret;
 
-	ret = cmf_readall(device->cdev, &data);
+	ret = cmf_readall(block->base->cdev, &data);
 	if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
 		return -EFAULT;
 	return ret;
@@ -374,10 +370,10 @@
 	   unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 	void __user *argp = (void __user *)arg;
 
-	if (!device)
+	if (!block)
                 return -ENODEV;
 
 	if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
@@ -391,33 +387,33 @@
 	case BIODASDENABLE:
 		return dasd_ioctl_enable(bdev);
 	case BIODASDQUIESCE:
-		return dasd_ioctl_quiesce(device);
+		return dasd_ioctl_quiesce(block);
 	case BIODASDRESUME:
-		return dasd_ioctl_resume(device);
+		return dasd_ioctl_resume(block);
 	case BIODASDFMT:
 		return dasd_ioctl_format(bdev, argp);
 	case BIODASDINFO:
-		return dasd_ioctl_information(device, cmd, argp);
+		return dasd_ioctl_information(block, cmd, argp);
 	case BIODASDINFO2:
-		return dasd_ioctl_information(device, cmd, argp);
+		return dasd_ioctl_information(block, cmd, argp);
 	case BIODASDPRRD:
-		return dasd_ioctl_read_profile(device, argp);
+		return dasd_ioctl_read_profile(block, argp);
 	case BIODASDPRRST:
-		return dasd_ioctl_reset_profile(device);
+		return dasd_ioctl_reset_profile(block);
 	case BLKROSET:
 		return dasd_ioctl_set_ro(bdev, argp);
 	case DASDAPIVER:
 		return dasd_ioctl_api_version(argp);
 	case BIODASDCMFENABLE:
-		return enable_cmf(device->cdev);
+		return enable_cmf(block->base->cdev);
 	case BIODASDCMFDISABLE:
-		return disable_cmf(device->cdev);
+		return disable_cmf(block->base->cdev);
 	case BIODASDREADALLCMB:
-		return dasd_ioctl_readall_cmb(device, cmd, arg);
+		return dasd_ioctl_readall_cmb(block, cmd, arg);
 	default:
 		/* if the discipline has an ioctl method try it. */
-		if (device->discipline->ioctl) {
-			int rval = device->discipline->ioctl(device, cmd, argp);
+		if (block->base->discipline->ioctl) {
+			int rval = block->base->discipline->ioctl(block, cmd, argp);
 			if (rval != -ENOIOCTLCMD)
 				return rval;
 		}
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index ac7e8ef..28a86f07 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -54,11 +54,16 @@
 dasd_devices_show(struct seq_file *m, void *v)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 	char *substr;
 
 	device = dasd_device_from_devindex((unsigned long) v - 1);
 	if (IS_ERR(device))
 		return 0;
+	if (device->block)
+		block = device->block;
+	else
+		return 0;
 	/* Print device number. */
 	seq_printf(m, "%s", device->cdev->dev.bus_id);
 	/* Print discipline string. */
@@ -67,14 +72,14 @@
 	else
 		seq_printf(m, "(none)");
 	/* Print kdev. */
-	if (device->gdp)
+	if (block->gdp)
 		seq_printf(m, " at (%3d:%6d)",
-			   device->gdp->major, device->gdp->first_minor);
+			   block->gdp->major, block->gdp->first_minor);
 	else
 		seq_printf(m, "  at (???:??????)");
 	/* Print device name. */
-	if (device->gdp)
-		seq_printf(m, " is %-8s", device->gdp->disk_name);
+	if (block->gdp)
+		seq_printf(m, " is %-8s", block->gdp->disk_name);
 	else
 		seq_printf(m, " is ????????");
 	/* Print devices features. */
@@ -100,14 +105,14 @@
 	case DASD_STATE_READY:
 	case DASD_STATE_ONLINE:
 		seq_printf(m, "active ");
-		if (dasd_check_blocksize(device->bp_block))
+		if (dasd_check_blocksize(block->bp_block))
 			seq_printf(m, "n/f	 ");
 		else
 			seq_printf(m,
 				   "at blocksize: %d, %ld blocks, %ld MB",
-				   device->bp_block, device->blocks,
-				   ((device->bp_block >> 9) *
-				    device->blocks) >> 11);
+				   block->bp_block, block->blocks,
+				   ((block->bp_block >> 9) *
+				    block->blocks) >> 11);
 		break;
 	default:
 		seq_printf(m, "no stat");
@@ -137,7 +142,7 @@
 {
 }
 
-static struct seq_operations dasd_devices_seq_ops = {
+static const struct seq_operations dasd_devices_seq_ops = {
 	.start		= dasd_devices_start,
 	.next		= dasd_devices_next,
 	.stop		= dasd_devices_stop,
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 15a5789..7779bfc 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -82,7 +82,7 @@
 	struct request_queue *dcssblk_queue;
 };
 
-static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices);
+static LIST_HEAD(dcssblk_devices);
 static struct rw_semaphore dcssblk_devices_sem;
 
 /*
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 130de19..7e73e39 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-	 sclp_info.o sclp_config.o sclp_chp.o
+	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 20442fb..a86c053 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -295,7 +295,7 @@
 module_exit(mon_exit);
 
 module_param_named(max_bufs, mon_max_bufs, int, 0644);
-MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
+MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
 		 "that can be active at one time");
 
 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 8d1c64a..0d98f1f 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -66,7 +66,7 @@
 static DEFINE_MUTEX(raw3270_mutex);
 
 /* List of 3270 devices. */
-static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
+static LIST_HEAD(raw3270_devices);
 
 /*
  * Flag to indicate if the driver has been registered. Some operations
@@ -1210,7 +1210,7 @@
 	void (*notifier)(int, int);
 };
 
-static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
+static LIST_HEAD(raw3270_notifier);
 
 int raw3270_register_notifier(void (*notifier)(int, int))
 {
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index c7318a1..aa8186d 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -56,8 +56,6 @@
 #define SCLP_CMDW_READ_EVENT_DATA	0x00770005
 #define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
 #define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
-#define SCLP_CMDW_READ_SCP_INFO		0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
 
 #define GDS_ID_MDSMU		0x1310
 #define GDS_ID_MDSROUTEINFO	0x1311
@@ -83,6 +81,8 @@
 
 #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
+#define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)
+#define SCLP_HAS_CPU_RECONFIG	(sclp_facilities & 0x0400000000000000ULL)
 
 struct gds_subvector {
 	u8	length;
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
deleted file mode 100644
index c68f5e7..0000000
--- a/drivers/s390/char/sclp_chp.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *  drivers/s390/char/sclp_chp.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/errno.h>
-#include <linux/completion.h>
-#include <asm/sclp.h>
-#include <asm/chpid.h>
-
-#include "sclp.h"
-
-#define TAG	"sclp_chp: "
-
-#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH	0x000f0001
-#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH	0x000e0001
-#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION	0x00030001
-
-static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
-{
-	return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
-{
-	return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static void chp_callback(struct sclp_req *req, void *data)
-{
-	struct completion *completion = data;
-
-	complete(completion);
-}
-
-struct chp_cfg_sccb {
-	struct sccb_header header;
-	u8 ccm;
-	u8 reserved[6];
-	u8 cssid;
-} __attribute__((packed));
-
-struct chp_cfg_data {
-	struct chp_cfg_sccb sccb;
-	struct sclp_req req;
-	struct completion completion;
-} __attribute__((packed));
-
-static int do_configure(sclp_cmdw_t cmd)
-{
-	struct chp_cfg_data *data;
-	int rc;
-
-	if (!SCLP_HAS_CHP_RECONFIG)
-		return -EOPNOTSUPP;
-	/* Prepare sccb. */
-	data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!data)
-		return -ENOMEM;
-	data->sccb.header.length = sizeof(struct chp_cfg_sccb);
-	data->req.command = cmd;
-	data->req.sccb = &(data->sccb);
-	data->req.status = SCLP_REQ_FILLED;
-	data->req.callback = chp_callback;
-	data->req.callback_data = &(data->completion);
-	init_completion(&data->completion);
-
-	/* Perform sclp request. */
-	rc = sclp_add_request(&(data->req));
-	if (rc)
-		goto out;
-	wait_for_completion(&data->completion);
-
-	/* Check response .*/
-	if (data->req.status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING TAG "configure channel-path request failed "
-		       "(status=0x%02x)\n", data->req.status);
-		rc = -EIO;
-		goto out;
-	}
-	switch (data->sccb.header.response_code) {
-	case 0x0020:
-	case 0x0120:
-	case 0x0440:
-	case 0x0450:
-		break;
-	default:
-		printk(KERN_WARNING TAG "configure channel-path failed "
-		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
-		       data->sccb.header.response_code);
-		rc = -EIO;
-		break;
-	}
-out:
-	free_page((unsigned long) data);
-
-	return rc;
-}
-
-/**
- * sclp_chp_configure - perform configure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform configure channel-path command sclp command for specified chpid.
- * Return 0 after command successfully finished, non-zero otherwise.
- */
-int sclp_chp_configure(struct chp_id chpid)
-{
-	return do_configure(get_configure_cmdw(chpid));
-}
-
-/**
- * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform deconfigure channel-path command sclp command for specified chpid
- * and wait for completion. On success return 0. Return non-zero otherwise.
- */
-int sclp_chp_deconfigure(struct chp_id chpid)
-{
-	return do_configure(get_deconfigure_cmdw(chpid));
-}
-
-struct chp_info_sccb {
-	struct sccb_header header;
-	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
-	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
-	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
-	u8 ccm;
-	u8 reserved[6];
-	u8 cssid;
-} __attribute__((packed));
-
-struct chp_info_data {
-	struct chp_info_sccb sccb;
-	struct sclp_req req;
-	struct completion completion;
-} __attribute__((packed));
-
-/**
- * sclp_chp_read_info - perform read channel-path information sclp command
- * @info: resulting channel-path information data
- *
- * Perform read channel-path information sclp command and wait for completion.
- * On success, store channel-path information in @info and return 0. Return
- * non-zero otherwise.
- */
-int sclp_chp_read_info(struct sclp_chp_info *info)
-{
-	struct chp_info_data *data;
-	int rc;
-
-	if (!SCLP_HAS_CHP_INFO)
-		return -EOPNOTSUPP;
-	/* Prepare sccb. */
-	data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!data)
-		return -ENOMEM;
-	data->sccb.header.length = sizeof(struct chp_info_sccb);
-	data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
-	data->req.sccb = &(data->sccb);
-	data->req.status = SCLP_REQ_FILLED;
-	data->req.callback = chp_callback;
-	data->req.callback_data = &(data->completion);
-	init_completion(&data->completion);
-
-	/* Perform sclp request. */
-	rc = sclp_add_request(&(data->req));
-	if (rc)
-		goto out;
-	wait_for_completion(&data->completion);
-
-	/* Check response .*/
-	if (data->req.status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING TAG "read channel-path info request failed "
-		       "(status=0x%02x)\n", data->req.status);
-		rc = -EIO;
-		goto out;
-	}
-	if (data->sccb.header.response_code != 0x0010) {
-		printk(KERN_WARNING TAG "read channel-path info failed "
-		       "(response=0x%04x)\n", data->sccb.header.response_code);
-		rc = -EIO;
-		goto out;
-	}
-	memcpy(info->recognized, data->sccb.recognized,
-	       SCLP_CHP_INFO_MASK_SIZE);
-	memcpy(info->standby, data->sccb.standby,
-	       SCLP_CHP_INFO_MASK_SIZE);
-	memcpy(info->configured, data->sccb.configured,
-	       SCLP_CHP_INFO_MASK_SIZE);
-out:
-	free_page((unsigned long) data);
-
-	return rc;
-}
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
new file mode 100644
index 0000000..b5c2339
--- /dev/null
+++ b/drivers/s390/char/sclp_cmd.c
@@ -0,0 +1,398 @@
+/*
+ *  drivers/s390/char/sclp_cmd.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/chpid.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+#define TAG	"sclp_cmd: "
+
+#define SCLP_CMDW_READ_SCP_INFO		0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
+
+struct read_info_sccb {
+	struct	sccb_header header;	/* 0-7 */
+	u16	rnmax;			/* 8-9 */
+	u8	rnsize;			/* 10 */
+	u8	_reserved0[24 - 11];	/* 11-15 */
+	u8	loadparm[8];		/* 24-31 */
+	u8	_reserved1[48 - 32];	/* 32-47 */
+	u64	facilities;		/* 48-55 */
+	u8	_reserved2[84 - 56];	/* 56-83 */
+	u8	fac84;			/* 84 */
+	u8	_reserved3[91 - 85];	/* 85-90 */
+	u8	flags;			/* 91 */
+	u8	_reserved4[100 - 92];	/* 92-99 */
+	u32	rnsize2;		/* 100-103 */
+	u64	rnmax2;			/* 104-111 */
+	u8	_reserved5[4096 - 112];	/* 112-4095 */
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static struct read_info_sccb __initdata early_read_info_sccb;
+static int __initdata early_read_info_sccb_valid;
+
+u64 sclp_facilities;
+static u8 sclp_fac84;
+
+static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
+{
+	int rc;
+
+	__ctl_set_bit(0, 9);
+	rc = sclp_service_call(cmd, sccb);
+	if (rc)
+		goto out;
+	__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+			PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+	local_irq_disable();
+out:
+	/* Contents of the sccb might have changed. */
+	barrier();
+	__ctl_clear_bit(0, 9);
+	return rc;
+}
+
+void __init sclp_read_info_early(void)
+{
+	int rc;
+	int i;
+	struct read_info_sccb *sccb;
+	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+				  SCLP_CMDW_READ_SCP_INFO};
+
+	sccb = &early_read_info_sccb;
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		do {
+			memset(sccb, 0, sizeof(*sccb));
+			sccb->header.length = sizeof(*sccb);
+			sccb->header.control_mask[2] = 0x80;
+			rc = sclp_cmd_sync_early(commands[i], sccb);
+		} while (rc == -EBUSY);
+
+		if (rc)
+			break;
+		if (sccb->header.response_code == 0x10) {
+			early_read_info_sccb_valid = 1;
+			break;
+		}
+		if (sccb->header.response_code != 0x1f0)
+			break;
+	}
+}
+
+void __init sclp_facilities_detect(void)
+{
+	if (!early_read_info_sccb_valid)
+		return;
+	sclp_facilities = early_read_info_sccb.facilities;
+	sclp_fac84 = early_read_info_sccb.fac84;
+}
+
+unsigned long long __init sclp_memory_detect(void)
+{
+	unsigned long long memsize;
+	struct read_info_sccb *sccb;
+
+	if (!early_read_info_sccb_valid)
+		return 0;
+	sccb = &early_read_info_sccb;
+	if (sccb->rnsize)
+		memsize = sccb->rnsize << 20;
+	else
+		memsize = sccb->rnsize2 << 20;
+	if (sccb->rnmax)
+		memsize *= sccb->rnmax;
+	else
+		memsize *= sccb->rnmax2;
+	return memsize;
+}
+
+/*
+ * This function will be called after sclp_memory_detect(), which gets called
+ * early from early.c code. Therefore the sccb should have valid contents.
+ */
+void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
+{
+	struct read_info_sccb *sccb;
+
+	if (!early_read_info_sccb_valid)
+		return;
+	sccb = &early_read_info_sccb;
+	info->is_valid = 1;
+	if (sccb->flags & 0x2)
+		info->has_dump = 1;
+	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
+}
+
+static void sclp_sync_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
+{
+	struct completion completion;
+	struct sclp_req *request;
+	int rc;
+
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+	request->command = cmd;
+	request->sccb = sccb;
+	request->status = SCLP_REQ_FILLED;
+	request->callback = sclp_sync_callback;
+	request->callback_data = &completion;
+	init_completion(&completion);
+
+	/* Perform sclp request. */
+	rc = sclp_add_request(request);
+	if (rc)
+		goto out;
+	wait_for_completion(&completion);
+
+	/* Check response. */
+	if (request->status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING TAG "sync request failed "
+		       "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
+		rc = -EIO;
+	}
+out:
+	kfree(request);
+	return rc;
+}
+
+/*
+ * CPU configuration related functions.
+ */
+
+#define SCLP_CMDW_READ_CPU_INFO		0x00010001
+#define SCLP_CMDW_CONFIGURE_CPU		0x00110001
+#define SCLP_CMDW_DECONFIGURE_CPU	0x00100001
+
+struct read_cpu_info_sccb {
+	struct	sccb_header header;
+	u16	nr_configured;
+	u16	offset_configured;
+	u16	nr_standby;
+	u16	offset_standby;
+	u8	reserved[4096 - 16];
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
+			       struct read_cpu_info_sccb *sccb)
+{
+	char *page = (char *) sccb;
+
+	memset(info, 0, sizeof(*info));
+	info->configured = sccb->nr_configured;
+	info->standby = sccb->nr_standby;
+	info->combined = sccb->nr_configured + sccb->nr_standby;
+	info->has_cpu_type = sclp_fac84 & 0x1;
+	memcpy(&info->cpu, page + sccb->offset_configured,
+	       info->combined * sizeof(struct sclp_cpu_entry));
+}
+
+int sclp_get_cpu_info(struct sclp_cpu_info *info)
+{
+	int rc;
+	struct read_cpu_info_sccb *sccb;
+
+	if (!SCLP_HAS_CPU_INFO)
+		return -EOPNOTSUPP;
+	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
+	if (rc)
+		goto out;
+	if (sccb->header.response_code != 0x0010) {
+		printk(KERN_WARNING TAG "readcpuinfo failed "
+		       "(response=0x%04x)\n", sccb->header.response_code);
+		rc = -EIO;
+		goto out;
+	}
+	sclp_fill_cpu_info(info, sccb);
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+struct cpu_configure_sccb {
+	struct sccb_header header;
+} __attribute__((packed, aligned(8)));
+
+static int do_cpu_configure(sclp_cmdw_t cmd)
+{
+	struct cpu_configure_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CPU_RECONFIG)
+		return -EOPNOTSUPP;
+	/*
+	 * This is not going to cross a page boundary since we force
+	 * kmalloc to have a minimum alignment of 8 bytes on s390.
+	 */
+	sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(cmd, sccb);
+	if (rc)
+		goto out;
+	switch (sccb->header.response_code) {
+	case 0x0020:
+	case 0x0120:
+		break;
+	default:
+		printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
+		       "response=0x%04x)\n", cmd, sccb->header.response_code);
+		rc = -EIO;
+		break;
+	}
+out:
+	kfree(sccb);
+	return rc;
+}
+
+int sclp_cpu_configure(u8 cpu)
+{
+	return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
+}
+
+int sclp_cpu_deconfigure(u8 cpu)
+{
+	return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
+}
+
+/*
+ * Channel path configuration related functions.
+ */
+
+#define SCLP_CMDW_CONFIGURE_CHPATH		0x000f0001
+#define SCLP_CMDW_DECONFIGURE_CHPATH		0x000e0001
+#define SCLP_CMDW_READ_CHPATH_INFORMATION	0x00030001
+
+struct chp_cfg_sccb {
+	struct sccb_header header;
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+static int do_chp_configure(sclp_cmdw_t cmd)
+{
+	struct chp_cfg_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CHP_RECONFIG)
+		return -EOPNOTSUPP;
+	/* Prepare sccb. */
+	sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(cmd, sccb);
+	if (rc)
+		goto out;
+	switch (sccb->header.response_code) {
+	case 0x0020:
+	case 0x0120:
+	case 0x0440:
+	case 0x0450:
+		break;
+	default:
+		printk(KERN_WARNING TAG "configure channel-path failed "
+		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
+		       sccb->header.response_code);
+		rc = -EIO;
+		break;
+	}
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+/**
+ * sclp_chp_configure - perform configure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform configure channel-path command sclp command for specified chpid.
+ * Return 0 after command successfully finished, non-zero otherwise.
+ */
+int sclp_chp_configure(struct chp_id chpid)
+{
+	return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
+}
+
+/**
+ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform deconfigure channel-path command sclp command for specified chpid
+ * and wait for completion. On success return 0. Return non-zero otherwise.
+ */
+int sclp_chp_deconfigure(struct chp_id chpid)
+{
+	return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
+}
+
+struct chp_info_sccb {
+	struct sccb_header header;
+	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+/**
+ * sclp_chp_read_info - perform read channel-path information sclp command
+ * @info: resulting channel-path information data
+ *
+ * Perform read channel-path information sclp command and wait for completion.
+ * On success, store channel-path information in @info and return 0. Return
+ * non-zero otherwise.
+ */
+int sclp_chp_read_info(struct sclp_chp_info *info)
+{
+	struct chp_info_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CHP_INFO)
+		return -EOPNOTSUPP;
+	/* Prepare sccb. */
+	sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
+	if (rc)
+		goto out;
+	if (sccb->header.response_code != 0x0010) {
+		printk(KERN_WARNING TAG "read channel-path info failed "
+		       "(response=0x%04x)\n", sccb->header.response_code);
+		rc = -EIO;
+		goto out;
+	}
+	memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 82a13d9..5716487 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -1,255 +1,41 @@
 /*
- * Author: Martin Peschke <mpeschke@de.ibm.com>
- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ *  drivers/s390/char/sclp_cpi.c
+ *    SCLP control programm identification
  *
- * SCLP Control-Program Identification.
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
  */
 
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <asm/ebcdic.h>
-#include <asm/semaphore.h>
-
-#include "sclp.h"
-#include "sclp_rw.h"
-
-#define CPI_LENGTH_SYSTEM_TYPE	8
-#define CPI_LENGTH_SYSTEM_NAME	8
-#define CPI_LENGTH_SYSPLEX_NAME	8
-
-struct cpi_evbuf {
-	struct evbuf_header header;
-	u8	id_format;
-	u8	reserved0;
-	u8	system_type[CPI_LENGTH_SYSTEM_TYPE];
-	u64	reserved1;
-	u8	system_name[CPI_LENGTH_SYSTEM_NAME];
-	u64	reserved2;
-	u64	system_level;
-	u64	reserved3;
-	u8	sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
-	u8	reserved4[16];
-} __attribute__((packed));
-
-struct cpi_sccb {
-	struct sccb_header header;
-	struct cpi_evbuf cpi_evbuf;
-} __attribute__((packed));
-
-/* Event type structure for write message and write priority message */
-static struct sclp_register sclp_cpi_event =
-{
-	.send_mask = EVTYP_CTLPROGIDENT_MASK
-};
+#include <linux/version.h>
+#include "sclp_cpi_sys.h"
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Identify this operating system instance "
+		   "to the System z hardware");
+MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
+	      "Michael Ernst <mernst@de.ibm.com>");
 
-MODULE_AUTHOR(
-	"Martin Peschke, IBM Deutschland Entwicklung GmbH "
-	"<mpeschke@de.ibm.com>");
+static char *system_name = "";
+static char *sysplex_name = "";
 
-MODULE_DESCRIPTION(
-	"identify this operating system instance to the S/390 "
-	"or zSeries hardware");
-
-static char *system_name = NULL;
 module_param(system_name, charp, 0);
 MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-
-static char *sysplex_name = NULL;
-#ifdef ALLOW_SYSPLEX_NAME
 module_param(sysplex_name, charp, 0);
 MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-#endif
 
-/* use default value for this field (as well as for system level) */
-static char *system_type = "LINUX";
-
-static int
-cpi_check_parms(void)
+static int __init cpi_module_init(void)
 {
-	/* reject if no system type specified */
-	if (!system_type) {
-		printk("cpi: bug: no system type specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system type larger than 8 characters */
-	if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: bug: system type has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
-		return -EINVAL;
-	}
-
-	/* reject if no system name specified */
-	if (!system_name) {
-		printk("cpi: no system name specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system name larger than 8 characters */
-	if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: system name has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
-		return -EINVAL;
-	}
-
-	/* reject if specified sysplex name larger than 8 characters */
-	if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
-		printk("cpi: sysplex name has length of %li characters"
-		       " - only %i characters supported\n",
-		       strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
-		return -EINVAL;
-	}
-	return 0;
+	return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
+				 LINUX_VERSION_CODE);
 }
 
-static void
-cpi_callback(struct sclp_req *req, void *data)
-{
-	struct semaphore *sem;
-
-	sem = (struct semaphore *) data;
-	up(sem);
-}
-
-static struct sclp_req *
-cpi_prepare_req(void)
-{
-	struct sclp_req *req;
-	struct cpi_sccb *sccb;
-	struct cpi_evbuf *evb;
-
-	req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
-	if (req == NULL)
-		return ERR_PTR(-ENOMEM);
-	sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
-	if (sccb == NULL) {
-		kfree(req);
-		return ERR_PTR(-ENOMEM);
-	}
-	memset(sccb, 0, sizeof(struct cpi_sccb));
-
-	/* setup SCCB for Control-Program Identification */
-	sccb->header.length = sizeof(struct cpi_sccb);
-	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
-	sccb->cpi_evbuf.header.type = 0x0B;
-	evb = &sccb->cpi_evbuf;
-
-	/* set system type */
-	memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
-	memcpy(evb->system_type, system_type, strlen(system_type));
-	sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-	EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-
-	/* set system name */
-	memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
-	memcpy(evb->system_name, system_name, strlen(system_name));
-	sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-	EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-
-	/* set system level */
-	evb->system_level = LINUX_VERSION_CODE;
-
-	/* set sysplex name */
-	if (sysplex_name) {
-		memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
-		memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
-		sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-		EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-	}
-
-	/* prepare request data structure presented to SCLP driver */
-	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
-	req->sccb = sccb;
-	req->status = SCLP_REQ_FILLED;
-	req->callback = cpi_callback;
-	return req;
-}
-
-static void
-cpi_free_req(struct sclp_req *req)
-{
-	free_page((unsigned long) req->sccb);
-	kfree(req);
-}
-
-static int __init
-cpi_module_init(void)
-{
-	struct semaphore sem;
-	struct sclp_req *req;
-	int rc;
-
-	rc = cpi_check_parms();
-	if (rc)
-		return rc;
-
-	rc = sclp_register(&sclp_cpi_event);
-	if (rc) {
-		/* could not register sclp event. Die. */
-		printk(KERN_WARNING "cpi: could not register to hardware "
-		       "console.\n");
-		return -EINVAL;
-	}
-	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
-		printk(KERN_WARNING "cpi: no control program identification "
-		       "support\n");
-		sclp_unregister(&sclp_cpi_event);
-		return -EOPNOTSUPP;
-	}
-
-	req = cpi_prepare_req();
-	if (IS_ERR(req)) {
-		printk(KERN_WARNING "cpi: couldn't allocate request\n");
-		sclp_unregister(&sclp_cpi_event);
-		return PTR_ERR(req);
-	}
-
-	/* Prepare semaphore */
-	sema_init(&sem, 0);
-	req->callback_data = &sem;
-	/* Add request to sclp queue */
-	rc = sclp_add_request(req);
-	if (rc) {
-		printk(KERN_WARNING "cpi: could not start request\n");
-		cpi_free_req(req);
-		sclp_unregister(&sclp_cpi_event);
-		return rc;
-	}
-	/* make "insmod" sleep until callback arrives */
-	down(&sem);
-
-	rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
-	if (rc != 0x0020) {
-		printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
-		       rc);
-		rc = -ECOMM;
-	} else
-		rc = 0;
-
-	cpi_free_req(req);
-	sclp_unregister(&sclp_cpi_event);
-
-	return rc;
-}
-
-
 static void __exit cpi_module_exit(void)
 {
 }
 
-
-/* declare driver module init/cleanup functions */
 module_init(cpi_module_init);
 module_exit(cpi_module_exit);
-
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
new file mode 100644
index 0000000..4161703
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -0,0 +1,400 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.c
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+#include "sclp_rw.h"
+#include "sclp_cpi_sys.h"
+
+#define CPI_LENGTH_NAME 8
+#define CPI_LENGTH_LEVEL 16
+
+struct cpi_evbuf {
+	struct evbuf_header header;
+	u8	id_format;
+	u8	reserved0;
+	u8	system_type[CPI_LENGTH_NAME];
+	u64	reserved1;
+	u8	system_name[CPI_LENGTH_NAME];
+	u64	reserved2;
+	u64	system_level;
+	u64	reserved3;
+	u8	sysplex_name[CPI_LENGTH_NAME];
+	u8	reserved4[16];
+} __attribute__((packed));
+
+struct cpi_sccb {
+	struct sccb_header header;
+	struct cpi_evbuf cpi_evbuf;
+} __attribute__((packed));
+
+static struct sclp_register sclp_cpi_event = {
+	.send_mask = EVTYP_CTLPROGIDENT_MASK,
+};
+
+static char system_name[CPI_LENGTH_NAME + 1];
+static char sysplex_name[CPI_LENGTH_NAME + 1];
+static char system_type[CPI_LENGTH_NAME + 1];
+static u64 system_level;
+
+static void set_data(char *field, char *data)
+{
+	memset(field, ' ', CPI_LENGTH_NAME);
+	memcpy(field, data, strlen(data));
+	sclp_ascebc_str(field, CPI_LENGTH_NAME);
+}
+
+static void cpi_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+static struct sclp_req *cpi_prepare_req(void)
+{
+	struct sclp_req *req;
+	struct cpi_sccb *sccb;
+	struct cpi_evbuf *evb;
+
+	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb) {
+		kfree(req);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* setup SCCB for Control-Program Identification */
+	sccb->header.length = sizeof(struct cpi_sccb);
+	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
+	sccb->cpi_evbuf.header.type = 0x0b;
+	evb = &sccb->cpi_evbuf;
+
+	/* set system type */
+	set_data(evb->system_type, system_type);
+
+	/* set system name */
+	set_data(evb->system_name, system_name);
+
+	/* set sytem level */
+	evb->system_level = system_level;
+
+	/* set sysplex name */
+	set_data(evb->sysplex_name, sysplex_name);
+
+	/* prepare request data structure presented to SCLP driver */
+	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
+	req->sccb = sccb;
+	req->status = SCLP_REQ_FILLED;
+	req->callback = cpi_callback;
+	return req;
+}
+
+static void cpi_free_req(struct sclp_req *req)
+{
+	free_page((unsigned long) req->sccb);
+	kfree(req);
+}
+
+static int cpi_req(void)
+{
+	struct completion completion;
+	struct sclp_req *req;
+	int rc;
+	int response;
+
+	rc = sclp_register(&sclp_cpi_event);
+	if (rc) {
+		printk(KERN_WARNING "cpi: could not register "
+			"to hardware console.\n");
+		goto out;
+	}
+	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
+		printk(KERN_WARNING "cpi: no control program "
+			"identification support\n");
+		rc = -EOPNOTSUPP;
+		goto out_unregister;
+	}
+
+	req = cpi_prepare_req();
+	if (IS_ERR(req)) {
+		printk(KERN_WARNING "cpi: could not allocate request\n");
+		rc = PTR_ERR(req);
+		goto out_unregister;
+	}
+
+	init_completion(&completion);
+	req->callback_data = &completion;
+
+	/* Add request to sclp queue */
+	rc = sclp_add_request(req);
+	if (rc) {
+		printk(KERN_WARNING "cpi: could not start request\n");
+		goto out_free_req;
+	}
+
+	wait_for_completion(&completion);
+
+	if (req->status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
+			req->status);
+		rc = -EIO;
+		goto out_free_req;
+	}
+
+	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
+	if (response != 0x0020) {
+		printk(KERN_WARNING "cpi: failed with "
+			"response code 0x%x\n", response);
+		rc = -EIO;
+	}
+
+out_free_req:
+	cpi_free_req(req);
+
+out_unregister:
+	sclp_unregister(&sclp_cpi_event);
+
+out:
+	return rc;
+}
+
+static int check_string(const char *attr, const char *str)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(str);
+
+	if ((len > 0) && (str[len - 1] == '\n'))
+		len--;
+
+	if (len > CPI_LENGTH_NAME)
+		return -EINVAL;
+
+	for (i = 0; i < len ; i++) {
+		if (isalpha(str[i]) || isdigit(str[i]) ||
+		    strchr("$@# ", str[i]))
+			continue;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void set_string(char *attr, const char *value)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(value);
+
+	if ((len > 0) && (value[len - 1] == '\n'))
+		len--;
+
+	for (i = 0; i < CPI_LENGTH_NAME; i++) {
+		if (i < len)
+			attr[i] = toupper(value[i]);
+		else
+			attr[i] = ' ';
+	}
+}
+
+static ssize_t system_name_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", system_name);
+}
+
+static ssize_t system_name_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("system_name", buf);
+	if (rc)
+		return rc;
+
+	set_string(system_name, buf);
+
+	return len;
+}
+
+static struct kobj_attribute system_name_attr =
+	__ATTR(system_name, 0644, system_name_show, system_name_store);
+
+static ssize_t sysplex_name_show(struct kobject *kobj,
+				 struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+}
+
+static ssize_t sysplex_name_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("sysplex_name", buf);
+	if (rc)
+		return rc;
+
+	set_string(sysplex_name, buf);
+
+	return len;
+}
+
+static struct kobj_attribute sysplex_name_attr =
+	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
+
+static ssize_t system_type_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", system_type);
+}
+
+static ssize_t system_type_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("system_type", buf);
+	if (rc)
+		return rc;
+
+	set_string(system_type, buf);
+
+	return len;
+}
+
+static struct kobj_attribute system_type_attr =
+	__ATTR(system_type, 0644, system_type_show, system_type_store);
+
+static ssize_t system_level_show(struct kobject *kobj,
+				 struct kobj_attribute *attr, char *page)
+{
+	unsigned long long level = system_level;
+
+	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
+}
+
+static ssize_t system_level_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf,
+	size_t len)
+{
+	unsigned long long level;
+	char *endp;
+
+	level = simple_strtoull(buf, &endp, 16);
+
+	if (endp == buf)
+		return -EINVAL;
+	if (*endp == '\n')
+		endp++;
+	if (*endp)
+		return -EINVAL;
+
+	system_level = level;
+
+	return len;
+}
+
+static struct kobj_attribute system_level_attr =
+	__ATTR(system_level, 0644, system_level_show, system_level_store);
+
+static ssize_t set_store(struct kobject *kobj,
+			 struct kobj_attribute *attr,
+			 const char *buf, size_t len)
+{
+	int rc;
+
+	rc = cpi_req();
+	if (rc)
+		return rc;
+
+	return len;
+}
+
+static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
+
+static struct attribute *cpi_attrs[] = {
+	&system_name_attr.attr,
+	&sysplex_name_attr.attr,
+	&system_type_attr.attr,
+	&system_level_attr.attr,
+	&set_attr.attr,
+	NULL,
+};
+
+static struct attribute_group cpi_attr_group = {
+	.attrs = cpi_attrs,
+};
+
+static struct kset *cpi_kset;
+
+int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
+		      const u64 level)
+{
+	int rc;
+
+	rc = check_string("system_name", system);
+	if (rc)
+		return rc;
+	rc = check_string("sysplex_name", sysplex);
+	if (rc)
+		return rc;
+	rc = check_string("system_type", type);
+	if (rc)
+		return rc;
+
+	set_string(system_name, system);
+	set_string(sysplex_name, sysplex);
+	set_string(system_type, type);
+	system_level = level;
+
+	return cpi_req();
+}
+EXPORT_SYMBOL(sclp_cpi_set_data);
+
+static int __init cpi_init(void)
+{
+	int rc;
+
+	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
+	if (!cpi_kset)
+		return -ENOMEM;
+
+	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
+	if (rc)
+		kset_unregister(cpi_kset);
+
+	return rc;
+}
+
+__initcall(cpi_init);
diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
new file mode 100644
index 0000000..deef3e6
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.h
@@ -0,0 +1,15 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.h
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Michael Ernst <mernst@de.ibm.com>
+ */
+
+#ifndef __SCLP_CPI_SYS_H__
+#define __SCLP_CPI_SYS_H__
+
+int sclp_cpi_set_data(const char *system, const char *sysplex,
+		      const char *type, u64 level);
+
+#endif	 /* __SCLP_CPI_SYS_H__ */
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
deleted file mode 100644
index a1136e0..0000000
--- a/drivers/s390/char/sclp_info.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *  drivers/s390/char/sclp_info.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <asm/sclp.h>
-#include "sclp.h"
-
-struct sclp_readinfo_sccb {
-	struct	sccb_header header;	/* 0-7 */
-	u16	rnmax;			/* 8-9 */
-	u8	rnsize;			/* 10 */
-	u8	_reserved0[24 - 11];	/* 11-23 */
-	u8	loadparm[8];		/* 24-31 */
-	u8	_reserved1[48 - 32];	/* 32-47 */
-	u64	facilities;		/* 48-55 */
-	u8	_reserved2[91 - 56];	/* 56-90 */
-	u8	flags;			/* 91 */
-	u8	_reserved3[100 - 92];	/* 92-99 */
-	u32	rnsize2;		/* 100-103 */
-	u64	rnmax2;			/* 104-111 */
-	u8	_reserved4[4096 - 112];	/* 112-4095 */
-} __attribute__((packed, aligned(4096)));
-
-static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
-static int __initdata early_readinfo_sccb_valid;
-
-u64 sclp_facilities;
-
-void __init sclp_readinfo_early(void)
-{
-	int ret;
-	int i;
-	struct sclp_readinfo_sccb *sccb;
-	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
-				  SCLP_CMDW_READ_SCP_INFO};
-
-	/* Enable service signal subclass mask. */
-	__ctl_set_bit(0, 9);
-	sccb = &early_readinfo_sccb;
-	for (i = 0; i < ARRAY_SIZE(commands); i++) {
-		do {
-			memset(sccb, 0, sizeof(*sccb));
-			sccb->header.length = sizeof(*sccb);
-			sccb->header.control_mask[2] = 0x80;
-			ret = sclp_service_call(commands[i], sccb);
-		} while (ret == -EBUSY);
-
-		if (ret)
-			break;
-		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
-				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
-		local_irq_disable();
-		/*
-		 * Contents of the sccb might have changed
-		 * therefore a barrier is needed.
-		 */
-		barrier();
-		if (sccb->header.response_code == 0x10) {
-			early_readinfo_sccb_valid = 1;
-			break;
-		}
-		if (sccb->header.response_code != 0x1f0)
-			break;
-	}
-	/* Disable service signal subclass mask again. */
-	__ctl_clear_bit(0, 9);
-}
-
-void __init sclp_facilities_detect(void)
-{
-	if (!early_readinfo_sccb_valid)
-		return;
-	sclp_facilities = early_readinfo_sccb.facilities;
-}
-
-unsigned long long __init sclp_memory_detect(void)
-{
-	unsigned long long memsize;
-	struct sclp_readinfo_sccb *sccb;
-
-	if (!early_readinfo_sccb_valid)
-		return 0;
-	sccb = &early_readinfo_sccb;
-	if (sccb->rnsize)
-		memsize = sccb->rnsize << 20;
-	else
-		memsize = sccb->rnsize2 << 20;
-	if (sccb->rnmax)
-		memsize *= sccb->rnmax;
-	else
-		memsize *= sccb->rnmax2;
-	return memsize;
-}
-
-/*
- * This function will be called after sclp_memory_detect(), which gets called
- * early from early.c code. Therefore the sccb should have valid contents.
- */
-void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
-{
-	struct sclp_readinfo_sccb *sccb;
-
-	if (!early_readinfo_sccb_valid)
-		return;
-	sccb = &early_readinfo_sccb;
-	info->is_valid = 1;
-	if (sccb->flags & 0x2)
-		info->has_dump = 1;
-	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
-}
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index d6b06ab..ad7195d 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -76,7 +76,7 @@
 }
 
 /*
- * Return a pointer to the orignal page that has been used to create
+ * Return a pointer to the original page that has been used to create
  * the buffer.
  */
 void *
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index da25f8e..8246ef3 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -1495,7 +1495,7 @@
 			   device->cdev->dev.bus_id);
 		return tape_3590_erp_basic(device, request, irb, -EPERM);
 	case 0x8013:
-		PRINT_WARN("(%s): Another host has priviliged access to the "
+		PRINT_WARN("(%s): Another host has privileged access to the "
 			   "tape device\n", device->cdev->dev.bus_id);
 		PRINT_WARN("(%s): To solve the problem unload the current "
 			   "cartridge!\n", device->cdev->dev.bus_id);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 2fae633..7ad8cf1 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -37,7 +37,7 @@
  * we can assign the devices to minor numbers of the same major
  * The list is protected by the rwlock
  */
-static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list);
+static LIST_HEAD(tape_device_list);
 static DEFINE_RWLOCK(tape_device_lock);
 
 /*
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index cea49f0..c9b96d5 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -97,7 +97,7 @@
 {
 }
 
-static struct seq_operations tape_proc_seq = {
+static const struct seq_operations tape_proc_seq = {
 	.start		= tape_proc_start,
 	.next		= tape_proc_next,
 	.stop		= tape_proc_stop,
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index e0c4c50..d364e0b 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -683,7 +683,7 @@
 	/* Register with iucv driver */
 	ret = iucv_register(&vmlogrdr_iucv_handler, 1);
 	if (ret) {
-		printk (KERN_ERR "vmlogrdr: failed to register with"
+		printk (KERN_ERR "vmlogrdr: failed to register with "
 			"iucv driver\n");
 		goto out;
 	}
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index d70a6e6..7689b50 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -759,7 +759,7 @@
 	return newpos;
 }
 
-static struct file_operations ur_fops = {
+static const struct file_operations ur_fops = {
 	.owner	 = THIS_MODULE,
 	.open	 = ur_open,
 	.release = ur_release,
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 7073daf..f523501 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -470,7 +470,7 @@
 	return rc;
 }
 
-static struct file_operations zcore_fops = {
+static const struct file_operations zcore_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= zcore_lseek,
 	.read		= zcore_read,
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 5287631..b7a07a8 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/airq.c
- *   S/390 common I/O routines -- support for adapter interruptions
+ *    Support for adapter interruptions
  *
- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- *			      IBM Corporation
- *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cornelia.huck@de.ibm.com)
- *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2007
+ *    Author(s): Ingo Adlung <adlung@de.ibm.com>
+ *		 Cornelia Huck <cornelia.huck@de.ibm.com>
+ *		 Arnd Bergmann <arndb@de.ibm.com>
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
 #include <linux/init.h>
@@ -14,72 +14,131 @@
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 
+#include <asm/airq.h>
+
+#include "cio.h"
 #include "cio_debug.h"
-#include "airq.h"
 
-static adapter_int_handler_t adapter_handler;
+#define NR_AIRQS		32
+#define NR_AIRQS_PER_WORD	sizeof(unsigned long)
+#define NR_AIRQ_WORDS		(NR_AIRQS / NR_AIRQS_PER_WORD)
 
-/*
- * register for adapter interrupts
+union indicator_t {
+	unsigned long word[NR_AIRQ_WORDS];
+	unsigned char byte[NR_AIRQS];
+} __attribute__((packed));
+
+struct airq_t {
+	adapter_int_handler_t handler;
+	void *drv_data;
+};
+
+static union indicator_t indicators;
+static struct airq_t *airqs[NR_AIRQS];
+
+static int register_airq(struct airq_t *airq)
+{
+	int i;
+
+	for (i = 0; i < NR_AIRQS; i++)
+		if (!cmpxchg(&airqs[i], NULL, airq))
+			return i;
+	return -ENOMEM;
+}
+
+/**
+ * s390_register_adapter_interrupt() - register adapter interrupt handler
+ * @handler: adapter handler to be registered
+ * @drv_data: driver data passed with each call to the handler
  *
- * With HiperSockets the zSeries architecture provides for
- *  means of adapter interrups, pseudo I/O interrupts that are
- *  not tied to an I/O subchannel, but to an adapter. However,
- *  it doesn't disclose the info how to enable/disable them, but
- *  to recognize them only. Perhaps we should consider them
- *  being shared interrupts, and thus build a linked list
- *  of adapter handlers ... to be evaluated ...
+ * Returns:
+ *  Pointer to the indicator to be used on success
+ *  ERR_PTR() if registration failed
  */
-int
-s390_register_adapter_interrupt (adapter_int_handler_t handler)
+void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
+				      void *drv_data)
 {
+	struct airq_t *airq;
+	char dbf_txt[16];
 	int ret;
-	char dbf_txt[15];
 
-	CIO_TRACE_EVENT (4, "rgaint");
-
-	if (handler == NULL)
-		ret = -EINVAL;
-	else
-		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
-	if (!ret)
-		synchronize_sched();  /* Allow interrupts to complete. */
-
-	sprintf (dbf_txt, "ret:%d", ret);
-	CIO_TRACE_EVENT (4, dbf_txt);
-
-	return ret;
-}
-
-int
-s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
-{
-	int ret;
-	char dbf_txt[15];
-
-	CIO_TRACE_EVENT (4, "urgaint");
-
-	if (handler == NULL)
-		ret = -EINVAL;
-	else {
-		adapter_handler = NULL;
-		synchronize_sched();  /* Allow interrupts to complete. */
-		ret = 0;
+	airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
+	if (!airq) {
+		ret = -ENOMEM;
+		goto out;
 	}
-	sprintf (dbf_txt, "ret:%d", ret);
-	CIO_TRACE_EVENT (4, dbf_txt);
-
-	return ret;
+	airq->handler = handler;
+	airq->drv_data = drv_data;
+	ret = register_airq(airq);
+	if (ret < 0)
+		kfree(airq);
+out:
+	snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
+	CIO_TRACE_EVENT(4, dbf_txt);
+	if (ret < 0)
+		return ERR_PTR(ret);
+	else
+		return &indicators.byte[ret];
 }
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
 
-void
-do_adapter_IO (void)
+/**
+ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
+ * @ind: indicator for which the handler is to be unregistered
+ */
+void s390_unregister_adapter_interrupt(void *ind)
 {
-	CIO_TRACE_EVENT (6, "doaio");
+	struct airq_t *airq;
+	char dbf_txt[16];
+	int i;
 
-	if (adapter_handler)
-		(*adapter_handler) ();
+	i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
+	snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
+	CIO_TRACE_EVENT(4, dbf_txt);
+	indicators.byte[i] = 0;
+	airq = xchg(&airqs[i], NULL);
+	/*
+	 * Allow interrupts to complete. This will ensure that the airq handle
+	 * is no longer referenced by any interrupt handler.
+	 */
+	synchronize_sched();
+	kfree(airq);
 }
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
 
-EXPORT_SYMBOL (s390_register_adapter_interrupt);
-EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
+#define INDICATOR_MASK	(0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
+
+void do_adapter_IO(void)
+{
+	int w;
+	int i;
+	unsigned long word;
+	struct airq_t *airq;
+
+	/*
+	 * Access indicator array in word-sized chunks to minimize storage
+	 * fetch operations.
+	 */
+	for (w = 0; w < NR_AIRQ_WORDS; w++) {
+		word = indicators.word[w];
+		i = w * NR_AIRQS_PER_WORD;
+		/*
+		 * Check bytes within word for active indicators.
+		 */
+		while (word) {
+			if (word & INDICATOR_MASK) {
+				airq = airqs[i];
+				if (likely(airq))
+					airq->handler(&indicators.byte[i],
+						      airq->drv_data);
+				else
+					/*
+					 * Reset ill-behaved indicator.
+					 */
+					indicators.byte[i] = 0;
+			}
+			word <<= 8;
+			i++;
+		}
+	}
+}
diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
deleted file mode 100644
index 7d6be3f..0000000
--- a/drivers/s390/cio/airq.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef S390_AINTERRUPT_H
-#define S390_AINTERRUPT_H
-
-typedef	int (*adapter_int_handler_t)(void);
-
-extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
-extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
-extern void do_adapter_IO (void);
-
-#endif
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index bd5f16f..e8597ec 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -348,7 +348,7 @@
 	return user_len;
 }
 
-static struct seq_operations cio_ignore_proc_seq_ops = {
+static const struct seq_operations cio_ignore_proc_seq_ops = {
 	.start = cio_ignore_proc_seq_start,
 	.stop  = cio_ignore_proc_seq_stop,
 	.next  = cio_ignore_proc_seq_next,
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 5baa517..3964056 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -35,8 +35,8 @@
 	struct ccwgroup_device *gdev;
 	struct ccwgroup_driver *gdrv;
 
-	gdev = container_of(dev, struct ccwgroup_device, dev);
-	gdrv = container_of(drv, struct ccwgroup_driver, driver);
+	gdev = to_ccwgroupdev(dev);
+	gdrv = to_ccwgroupdrv(drv);
 
 	if (gdev->creator_id == gdrv->driver_id)
 		return 1;
@@ -75,8 +75,10 @@
 	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
 
 	mutex_lock(&gdev->reg_mutex);
-	__ccwgroup_remove_symlinks(gdev);
-	device_unregister(dev);
+	if (device_is_registered(&gdev->dev)) {
+		__ccwgroup_remove_symlinks(gdev);
+		device_unregister(dev);
+	}
 	mutex_unlock(&gdev->reg_mutex);
 }
 
@@ -111,7 +113,7 @@
 	gdev = to_ccwgroupdev(dev);
 
 	for (i = 0; i < gdev->count; i++) {
-		gdev->cdev[i]->dev.driver_data = NULL;
+		dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 		put_device(&gdev->cdev[i]->dev);
 	}
 	kfree(gdev);
@@ -196,11 +198,11 @@
 			goto error;
 		}
 		/* Don't allow a device to belong to more than one group. */
-		if (gdev->cdev[i]->dev.driver_data) {
+		if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
 			rc = -EINVAL;
 			goto error;
 		}
-		gdev->cdev[i]->dev.driver_data = gdev;
+		dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
 	}
 
 	gdev->creator_id = creator_id;
@@ -234,8 +236,8 @@
 error:
 	for (i = 0; i < argc; i++)
 		if (gdev->cdev[i]) {
-			if (gdev->cdev[i]->dev.driver_data == gdev)
-				gdev->cdev[i]->dev.driver_data = NULL;
+			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
+				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 			put_device(&gdev->cdev[i]->dev);
 		}
 	mutex_unlock(&gdev->reg_mutex);
@@ -408,6 +410,7 @@
 	/* register our new driver with the core */
 	cdriver->driver.bus = &ccwgroup_bus_type;
 	cdriver->driver.name = cdriver->name;
+	cdriver->driver.owner = cdriver->owner;
 
 	return driver_register(&cdriver->driver);
 }
@@ -463,8 +466,8 @@
 {
 	struct ccwgroup_device *gdev;
 
-	if (cdev->dev.driver_data) {
-		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
+	gdev = dev_get_drvdata(&cdev->dev);
+	if (gdev) {
 		if (get_device(&gdev->dev)) {
 			mutex_lock(&gdev->reg_mutex);
 			if (device_is_registered(&gdev->dev))
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 597c0c7..e7ba16a 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -89,7 +89,8 @@
 	/* Copy data */
 	ret = 0;
 	memset(ssd, 0, sizeof(struct chsc_ssd_info));
-	if ((ssd_area->st != 0) && (ssd_area->st != 2))
+	if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
+	    (ssd_area->st != SUBCHANNEL_TYPE_MSG))
 		goto out_free;
 	ssd->path_mask = ssd_area->path_mask;
 	ssd->fla_valid_mask = ssd_area->fla_valid_mask;
@@ -132,20 +133,16 @@
 	device_set_intretry(sch);
 	/* Call handler. */
 	if (sch->driver && sch->driver->termination)
-		sch->driver->termination(&sch->dev);
+		sch->driver->termination(sch);
 }
 
-static int
-s390_subchannel_remove_chpid(struct device *dev, void *data)
+static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 {
 	int j;
 	int mask;
-	struct subchannel *sch;
-	struct chp_id *chpid;
+	struct chp_id *chpid = data;
 	struct schib schib;
 
-	sch = to_subchannel(dev);
-	chpid = data;
 	for (j = 0; j < 8; j++) {
 		mask = 0x80 >> j;
 		if ((sch->schib.pmcw.pim & mask) &&
@@ -158,7 +155,7 @@
 	spin_lock_irq(sch->lock);
 
 	stsch(sch->schid, &schib);
-	if (!schib.pmcw.dnv)
+	if (!css_sch_is_valid(&schib))
 		goto out_unreg;
 	memcpy(&sch->schib, &schib, sizeof(struct schib));
 	/* Check for single path devices. */
@@ -172,12 +169,12 @@
 			terminate_internal_io(sch);
 			/* Re-start path verification. */
 			if (sch->driver && sch->driver->verify)
-				sch->driver->verify(&sch->dev);
+				sch->driver->verify(sch);
 		}
 	} else {
 		/* trigger path verification. */
 		if (sch->driver && sch->driver->verify)
-			sch->driver->verify(&sch->dev);
+			sch->driver->verify(sch);
 		else if (sch->lpm == mask)
 			goto out_unreg;
 	}
@@ -201,12 +198,10 @@
 
 	if (chp_get_status(chpid) <= 0)
 		return;
-	bus_for_each_dev(&css_bus_type, NULL, &chpid,
-			 s390_subchannel_remove_chpid);
+	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
 }
 
-static int
-s390_process_res_acc_new_sch(struct subchannel_id schid)
+static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
 	/*
@@ -252,18 +247,10 @@
 	return 0;
 }
 
-static int
-__s390_process_res_acc(struct subchannel_id schid, void *data)
+static int __s390_process_res_acc(struct subchannel *sch, void *data)
 {
 	int chp_mask, old_lpm;
-	struct res_acc_data *res_data;
-	struct subchannel *sch;
-
-	res_data = data;
-	sch = get_subchannel_by_schid(schid);
-	if (!sch)
-		/* Check if a subchannel is newly available. */
-		return s390_process_res_acc_new_sch(schid);
+	struct res_acc_data *res_data = data;
 
 	spin_lock_irq(sch->lock);
 	chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
@@ -279,10 +266,10 @@
 	if (!old_lpm && sch->lpm)
 		device_trigger_reprobe(sch);
 	else if (sch->driver && sch->driver->verify)
-		sch->driver->verify(&sch->dev);
+		sch->driver->verify(sch);
 out:
 	spin_unlock_irq(sch->lock);
-	put_device(&sch->dev);
+
 	return 0;
 }
 
@@ -305,7 +292,8 @@
 	 * The more information we have (info), the less scanning
 	 * will we have to do.
 	 */
-	for_each_subchannel(__s390_process_res_acc, res_data);
+	for_each_subchannel_staged(__s390_process_res_acc,
+				   s390_process_res_acc_new_sch, res_data);
 }
 
 static int
@@ -499,8 +487,7 @@
 	} while (sei_area->flags & 0x80);
 }
 
-static int
-__chp_add_new_sch(struct subchannel_id schid)
+static int __chp_add_new_sch(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
 
@@ -514,45 +501,37 @@
 }
 
 
-static int
-__chp_add(struct subchannel_id schid, void *data)
+static int __chp_add(struct subchannel *sch, void *data)
 {
 	int i, mask;
-	struct chp_id *chpid;
-	struct subchannel *sch;
+	struct chp_id *chpid = data;
 
-	chpid = data;
-	sch = get_subchannel_by_schid(schid);
-	if (!sch)
-		/* Check if the subchannel is now available. */
-		return __chp_add_new_sch(schid);
 	spin_lock_irq(sch->lock);
 	for (i=0; i<8; i++) {
 		mask = 0x80 >> i;
 		if ((sch->schib.pmcw.pim & mask) &&
-		    (sch->schib.pmcw.chpid[i] == chpid->id)) {
-			if (stsch(sch->schid, &sch->schib) != 0) {
-				/* Endgame. */
-				spin_unlock_irq(sch->lock);
-				return -ENXIO;
-			}
+		    (sch->schib.pmcw.chpid[i] == chpid->id))
 			break;
-		}
 	}
 	if (i==8) {
 		spin_unlock_irq(sch->lock);
 		return 0;
 	}
+	if (stsch(sch->schid, &sch->schib)) {
+		spin_unlock_irq(sch->lock);
+		css_schedule_eval(sch->schid);
+		return 0;
+	}
 	sch->lpm = ((sch->schib.pmcw.pim &
 		     sch->schib.pmcw.pam &
 		     sch->schib.pmcw.pom)
 		    | mask) & sch->opm;
 
 	if (sch->driver && sch->driver->verify)
-		sch->driver->verify(&sch->dev);
+		sch->driver->verify(sch);
 
 	spin_unlock_irq(sch->lock);
-	put_device(&sch->dev);
+
 	return 0;
 }
 
@@ -564,7 +543,8 @@
 	CIO_TRACE_EVENT(2, dbf_txt);
 
 	if (chp_get_status(chpid) != 0)
-		for_each_subchannel(__chp_add, &chpid);
+		for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
+					   &chpid);
 }
 
 static void __s390_subchannel_vary_chpid(struct subchannel *sch,
@@ -589,7 +569,7 @@
 			if (!old_lpm)
 				device_trigger_reprobe(sch);
 			else if (sch->driver && sch->driver->verify)
-				sch->driver->verify(&sch->dev);
+				sch->driver->verify(sch);
 			break;
 		}
 		sch->opm &= ~mask;
@@ -603,37 +583,29 @@
 				terminate_internal_io(sch);
 				/* Re-start path verification. */
 				if (sch->driver && sch->driver->verify)
-					sch->driver->verify(&sch->dev);
+					sch->driver->verify(sch);
 			}
 		} else if (!sch->lpm) {
 			if (device_trigger_verify(sch) != 0)
 				css_schedule_eval(sch->schid);
 		} else if (sch->driver && sch->driver->verify)
-			sch->driver->verify(&sch->dev);
+			sch->driver->verify(sch);
 		break;
 	}
 	spin_unlock_irqrestore(sch->lock, flags);
 }
 
-static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
 {
-	struct subchannel *sch;
-	struct chp_id *chpid;
-
-	sch = to_subchannel(dev);
-	chpid = data;
+	struct chp_id *chpid = data;
 
 	__s390_subchannel_vary_chpid(sch, *chpid, 0);
 	return 0;
 }
 
-static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
 {
-	struct subchannel *sch;
-	struct chp_id *chpid;
-
-	sch = to_subchannel(dev);
-	chpid = data;
+	struct chp_id *chpid = data;
 
 	__s390_subchannel_vary_chpid(sch, *chpid, 1);
 	return 0;
@@ -643,13 +615,7 @@
 __s390_vary_chpid_on(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
-	struct subchannel *sch;
 
-	sch = get_subchannel_by_schid(schid);
-	if (sch) {
-		put_device(&sch->dev);
-		return 0;
-	}
 	if (stsch_err(schid, &schib))
 		/* We're through */
 		return -ENXIO;
@@ -669,12 +635,13 @@
 	 * Redo PathVerification on the devices the chpid connects to
 	 */
 
-	bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?
-			 s390_subchannel_vary_chpid_on :
-			 s390_subchannel_vary_chpid_off);
 	if (on)
-		/* Scan for new devices on varied on path. */
-		for_each_subchannel(__s390_vary_chpid_on, NULL);
+		for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
+					   __s390_vary_chpid_on, &chpid);
+	else
+		for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
+					   NULL, &chpid);
+
 	return 0;
 }
 
@@ -1075,7 +1042,7 @@
 
 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scsc_area) {
-		CIO_MSG_EVENT(0, "Was not able to determine available"
+		CIO_MSG_EVENT(0, "Was not able to determine available "
 			      "CHSCs due to no memory.\n");
 		return -ENOMEM;
 	}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 4690534..60590a1 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -23,11 +23,12 @@
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/chpid.h>
-#include "airq.h"
+#include <asm/airq.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "io_sch.h"
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
@@ -56,39 +57,37 @@
 
 /*
  * Function: cio_debug_init
- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * Initializes three debug logs for common I/O:
+ * - cio_msg logs generic cio messages
  * - cio_trace logs the calling of different functions
- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ * - cio_crw logs machine check related cio messages
  */
-static int __init
-cio_debug_init (void)
+static int __init cio_debug_init(void)
 {
-	cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
+	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
 	if (!cio_debug_msg_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
-	debug_set_level (cio_debug_msg_id, 2);
-	cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
+	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+	debug_set_level(cio_debug_msg_id, 2);
+	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
 	if (!cio_debug_trace_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
-	debug_set_level (cio_debug_trace_id, 2);
-	cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
+	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+	debug_set_level(cio_debug_trace_id, 2);
+	cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
 	if (!cio_debug_crw_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
-	debug_set_level (cio_debug_crw_id, 2);
+	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+	debug_set_level(cio_debug_crw_id, 4);
 	return 0;
 
 out_unregister:
 	if (cio_debug_msg_id)
-		debug_unregister (cio_debug_msg_id);
+		debug_unregister(cio_debug_msg_id);
 	if (cio_debug_trace_id)
-		debug_unregister (cio_debug_trace_id);
+		debug_unregister(cio_debug_trace_id);
 	if (cio_debug_crw_id)
-		debug_unregister (cio_debug_crw_id);
+		debug_unregister(cio_debug_crw_id);
 	printk(KERN_WARNING"cio: could not initialize debugging\n");
 	return -1;
 }
@@ -147,7 +146,7 @@
 	spin_lock(sch->lock);
 	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
 	if (sch->driver && sch->driver->irq)
-		sch->driver->irq(&sch->dev);
+		sch->driver->irq(sch);
 	spin_unlock(sch->lock);
 	irq_exit ();
 	_local_bh_enable();
@@ -184,33 +183,35 @@
 {
 	char dbf_txt[15];
 	int ccode;
+	struct orb *orb;
 
-	CIO_TRACE_EVENT (4, "stIO");
-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
+	CIO_TRACE_EVENT(4, "stIO");
+	CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
+	orb = &to_io_private(sch)->orb;
 	/* sch is always under 2G. */
-	sch->orb.intparm = (__u32)(unsigned long)sch;
-	sch->orb.fmt = 1;
+	orb->intparm = (u32)(addr_t)sch;
+	orb->fmt = 1;
 
-	sch->orb.pfch = sch->options.prefetch == 0;
-	sch->orb.spnd = sch->options.suspend;
-	sch->orb.ssic = sch->options.suspend && sch->options.inter;
-	sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+	orb->pfch = sch->options.prefetch == 0;
+	orb->spnd = sch->options.suspend;
+	orb->ssic = sch->options.suspend && sch->options.inter;
+	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
 	/*
 	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
 	 */
-	sch->orb.c64 = 1;
-	sch->orb.i2k = 0;
+	orb->c64 = 1;
+	orb->i2k = 0;
 #endif
-	sch->orb.key = key >> 4;
+	orb->key = key >> 4;
 	/* issue "Start Subchannel" */
-	sch->orb.cpa = (__u32) __pa (cpa);
-	ccode = ssch (sch->schid, &sch->orb);
+	orb->cpa = (__u32) __pa(cpa);
+	ccode = ssch(sch->schid, orb);
 
 	/* process condition code */
-	sprintf (dbf_txt, "ccode:%d", ccode);
-	CIO_TRACE_EVENT (4, dbf_txt);
+	sprintf(dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT(4, dbf_txt);
 
 	switch (ccode) {
 	case 0:
@@ -405,8 +406,8 @@
 /*
  * Enable subchannel.
  */
-int
-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
+			  u32 intparm)
 {
 	char dbf_txt[15];
 	int ccode;
@@ -425,7 +426,7 @@
 	for (retry = 5, ret = 0; retry > 0; retry--) {
 		sch->schib.pmcw.ena = 1;
 		sch->schib.pmcw.isc = isc;
-		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+		sch->schib.pmcw.intparm = intparm;
 		ret = cio_modify(sch);
 		if (ret == -ENODEV)
 			break;
@@ -567,7 +568,7 @@
 	 */
 	if (sch->st != 0) {
 		CIO_DEBUG(KERN_INFO, 0,
-			  "cio: Subchannel 0.%x.%04x reports "
+			  "Subchannel 0.%x.%04x reports "
 			  "non-I/O subchannel type %04X\n",
 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
 		/* We stop here for non-io subchannels. */
@@ -576,11 +577,11 @@
 	}
 
 	/* Initialization for io subchannels. */
-	if (!sch->schib.pmcw.dnv) {
-		/* io subchannel but device number is invalid. */
+	if (!css_sch_is_valid(&sch->schib)) {
 		err = -ENODEV;
 		goto out;
 	}
+
 	/* Devno is valid. */
 	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
 		/*
@@ -600,7 +601,7 @@
 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
 	CIO_DEBUG(KERN_INFO, 0,
-		  "cio: Detected device %04x on subchannel 0.%x.%04X"
+		  "Detected device %04x on subchannel 0.%x.%04X"
 		  " - PIM = %02X, PAM = %02X, POM = %02X\n",
 		  sch->schib.pmcw.dev, sch->schid.ssid,
 		  sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -680,7 +681,7 @@
 				sizeof (irb->scsw));
 			/* Call interrupt handler if there is one. */
 			if (sch->driver && sch->driver->irq)
-				sch->driver->irq(&sch->dev);
+				sch->driver->irq(sch);
 		}
 		if (sch)
 			spin_unlock(sch->lock);
@@ -698,8 +699,14 @@
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+void *cio_get_console_priv(void)
+{
+	return &console_priv;
+}
+
 /*
  * busy wait for the next interrupt on the console
  */
@@ -738,9 +745,9 @@
 {
 	if (stsch_err(schid, &console_subchannel.schib) != 0)
 		return -ENXIO;
-	if (console_subchannel.schib.pmcw.dnv &&
-	    console_subchannel.schib.pmcw.dev ==
-	    console_devno) {
+	if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
+	    console_subchannel.schib.pmcw.dnv &&
+	    (console_subchannel.schib.pmcw.dev == console_devno)) {
 		console_irq = schid.sch_no;
 		return 1; /* found */
 	}
@@ -758,6 +765,7 @@
 		/* VM provided us with the irq number of the console. */
 		schid.sch_no = console_irq;
 		if (stsch(schid, &console_subchannel.schib) != 0 ||
+		    (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
 		    !console_subchannel.schib.pmcw.dnv)
 			return -1;
 		console_devno = console_subchannel.schib.pmcw.dev;
@@ -804,7 +812,7 @@
 	ctl_set_bit(6, 24);
 	console_subchannel.schib.pmcw.isc = 7;
 	console_subchannel.schib.pmcw.intparm =
-		(__u32)(unsigned long)&console_subchannel;
+		(u32)(addr_t)&console_subchannel;
 	ret = cio_modify(&console_subchannel);
 	if (ret) {
 		console_subchannel_in_use = 0;
@@ -1022,7 +1030,7 @@
 
 	if (stsch_reset(schid, &schib))
 		return -ENXIO;
-	if (schib.pmcw.dnv &&
+	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
 	    (schib.pmcw.dev == match_id->devid.devno) &&
 	    (schid.ssid == match_id->devid.ssid)) {
 		match_id->schid = schid;
@@ -1068,6 +1076,8 @@
 		return -ENODEV;
 	if (stsch(schid, &schib))
 		return -ENODEV;
+	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
+		return -ENODEV;
 	if (!schib.pmcw.dnv)
 		return -ENODEV;
 	iplinfo->devno = schib.pmcw.dev;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 7446c399..52afa4c 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -11,32 +11,32 @@
  * path management control word
  */
 struct pmcw {
-	__u32 intparm;		/* interruption parameter */
-	__u32 qf   : 1;		/* qdio facility */
-	__u32 res0 : 1;		/* reserved zeros */
-	__u32 isc  : 3;		/* interruption sublass */
-	__u32 res5 : 3;		/* reserved zeros */
-	__u32 ena  : 1;		/* enabled */
-	__u32 lm   : 2;		/* limit mode */
-	__u32 mme  : 2;		/* measurement-mode enable */
-	__u32 mp   : 1;		/* multipath mode */
-	__u32 tf   : 1;		/* timing facility */
-	__u32 dnv  : 1;		/* device number valid */
-	__u32 dev  : 16;	/* device number */
-	__u8  lpm;		/* logical path mask */
-	__u8  pnom;		/* path not operational mask */
-	__u8  lpum;		/* last path used mask */
-	__u8  pim;		/* path installed mask */
-	__u16 mbi;		/* measurement-block index */
-	__u8  pom;		/* path operational mask */
-	__u8  pam;		/* path available mask */
-	__u8  chpid[8];		/* CHPID 0-7 (if available) */
-	__u32 unused1 : 8;	/* reserved zeros */
-	__u32 st      : 3;	/* subchannel type */
-	__u32 unused2 : 18;	/* reserved zeros */
-	__u32 mbfc    : 1;      /* measurement block format control */
-	__u32 xmwme   : 1;      /* extended measurement word mode enable */
-	__u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
+	u32 intparm;		/* interruption parameter */
+	u32 qf	 : 1;		/* qdio facility */
+	u32 res0 : 1;		/* reserved zeros */
+	u32 isc  : 3;		/* interruption sublass */
+	u32 res5 : 3;		/* reserved zeros */
+	u32 ena  : 1;		/* enabled */
+	u32 lm	 : 2;		/* limit mode */
+	u32 mme  : 2;		/* measurement-mode enable */
+	u32 mp	 : 1;		/* multipath mode */
+	u32 tf	 : 1;		/* timing facility */
+	u32 dnv  : 1;		/* device number valid */
+	u32 dev  : 16;		/* device number */
+	u8  lpm;		/* logical path mask */
+	u8  pnom;		/* path not operational mask */
+	u8  lpum;		/* last path used mask */
+	u8  pim;		/* path installed mask */
+	u16 mbi;		/* measurement-block index */
+	u8  pom;		/* path operational mask */
+	u8  pam;		/* path available mask */
+	u8  chpid[8];		/* CHPID 0-7 (if available) */
+	u32 unused1 : 8;	/* reserved zeros */
+	u32 st	    : 3;	/* subchannel type */
+	u32 unused2 : 18;	/* reserved zeros */
+	u32 mbfc    : 1;	/* measurement block format control */
+	u32 xmwme   : 1;	/* extended measurement word mode enable */
+	u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
 				/*  ... per MSCH, however, if facility */
 				/*  ... is not installed, this results */
 				/*  ... in an operand exception.       */
@@ -52,31 +52,6 @@
 	__u8 mda[4];		 /* model dependent area */
 } __attribute__ ((packed,aligned(4)));
 
-/*
- * operation request block
- */
-struct orb {
-	__u32 intparm;		/* interruption parameter */
-	__u32 key  : 4; 	/* flags, like key, suspend control, etc. */
-	__u32 spnd : 1; 	/* suspend control */
-	__u32 res1 : 1; 	/* reserved */
-	__u32 mod  : 1; 	/* modification control */
-	__u32 sync : 1; 	/* synchronize control */
-	__u32 fmt  : 1; 	/* format control */
-	__u32 pfch : 1; 	/* prefetch control */
-	__u32 isic : 1; 	/* initial-status-interruption control */
-	__u32 alcc : 1; 	/* address-limit-checking control */
-	__u32 ssic : 1; 	/* suppress-suspended-interr. control */
-	__u32 res2 : 1; 	/* reserved */
-	__u32 c64  : 1; 	/* IDAW/QDIO 64 bit control  */
-	__u32 i2k  : 1; 	/* IDAW 2/4kB block size control */
-	__u32 lpm  : 8; 	/* logical path mask */
-	__u32 ils  : 1; 	/* incorrect length */
-	__u32 zero : 6; 	/* reserved zeros */
-	__u32 orbx : 1; 	/* ORB extension control */
-	__u32 cpa;		/* channel program address */
-}  __attribute__ ((packed,aligned(4)));
-
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
 	struct subchannel_id schid;
@@ -85,7 +60,7 @@
 	enum {
 		SUBCHANNEL_TYPE_IO = 0,
 		SUBCHANNEL_TYPE_CHSC = 1,
-		SUBCHANNEL_TYPE_MESSAGE = 2,
+		SUBCHANNEL_TYPE_MSG = 2,
 		SUBCHANNEL_TYPE_ADM = 3,
 	} st;			/* subchannel type */
 
@@ -99,11 +74,10 @@
 	__u8 lpm;		/* logical path mask */
 	__u8 opm;               /* operational path mask */
 	struct schib schib;	/* subchannel information block */
-	struct orb orb;		/* operation request block */
-	struct ccw1 sense_ccw;	/* static ccw for sense command */
 	struct chsc_ssd_info ssd_info;	/* subchannel description */
 	struct device dev;	/* entry in device tree */
 	struct css_driver *driver;
+	void *private; /* private per subchannel type data */
 } __attribute__ ((aligned(8)));
 
 #define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
@@ -111,7 +85,7 @@
 #define to_subchannel(n) container_of(n, struct subchannel, dev)
 
 extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel (struct subchannel *, unsigned int);
+extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
 extern int cio_disable_subchannel (struct subchannel *);
 extern int cio_cancel (struct subchannel *);
 extern int cio_clear (struct subchannel *);
@@ -125,6 +99,7 @@
 extern int cio_modify (struct subchannel *);
 
 int cio_create_sch_lock(struct subchannel *);
+void do_adapter_IO(void);
 
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
@@ -133,10 +108,12 @@
 extern int cio_is_console(struct subchannel_id);
 extern struct subchannel *cio_get_console_subchannel(void);
 extern spinlock_t * cio_get_console_lock(void);
+extern void *cio_get_console_priv(void);
 #else
 #define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
-#define cio_get_console_lock() NULL;
+#define cio_get_console_lock() NULL
+#define cio_get_console_priv() NULL
 #endif
 
 extern int cio_show_msg;
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index c9bf898..d7429ef 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -8,20 +8,19 @@
 extern debug_info_t *cio_debug_trace_id;
 extern debug_info_t *cio_debug_crw_id;
 
-#define CIO_TRACE_EVENT(imp, txt) do { \
+#define CIO_TRACE_EVENT(imp, txt) do {				\
 		debug_text_event(cio_debug_trace_id, imp, txt); \
 	} while (0)
 
-#define CIO_MSG_EVENT(imp, args...) do { \
-		debug_sprintf_event(cio_debug_msg_id, imp , ##args); \
+#define CIO_MSG_EVENT(imp, args...) do {				\
+		debug_sprintf_event(cio_debug_msg_id, imp , ##args);	\
 	} while (0)
 
-#define CIO_CRW_EVENT(imp, args...) do { \
-		debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
+#define CIO_CRW_EVENT(imp, args...) do {				\
+		debug_sprintf_event(cio_debug_crw_id, imp , ##args);	\
 	} while (0)
 
-static inline void
-CIO_HEX_EVENT(int level, void *data, int length)
+static inline void CIO_HEX_EVENT(int level, void *data, int length)
 {
 	if (unlikely(!cio_debug_trace_id))
 		return;
@@ -32,9 +31,10 @@
 	}
 }
 
-#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
-	if (cio_show_msg) printk(printk_level msg); \
-	CIO_MSG_EVENT (event_level, msg); \
-})
+#define CIO_DEBUG(printk_level, event_level, msg...) do {	\
+		if (cio_show_msg)				\
+			printk(printk_level "cio: " msg);	\
+		CIO_MSG_EVENT(event_level, msg);		\
+	} while (0)
 
 #endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c3df2cd..3b45bbe 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -51,6 +51,62 @@
 	return ret;
 }
 
+struct cb_data {
+	void *data;
+	struct idset *set;
+	int (*fn_known_sch)(struct subchannel *, void *);
+	int (*fn_unknown_sch)(struct subchannel_id, void *);
+};
+
+static int call_fn_known_sch(struct device *dev, void *data)
+{
+	struct subchannel *sch = to_subchannel(dev);
+	struct cb_data *cb = data;
+	int rc = 0;
+
+	idset_sch_del(cb->set, sch->schid);
+	if (cb->fn_known_sch)
+		rc = cb->fn_known_sch(sch, cb->data);
+	return rc;
+}
+
+static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
+{
+	struct cb_data *cb = data;
+	int rc = 0;
+
+	if (idset_sch_contains(cb->set, schid))
+		rc = cb->fn_unknown_sch(schid, cb->data);
+	return rc;
+}
+
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+			       int (*fn_unknown)(struct subchannel_id,
+			       void *), void *data)
+{
+	struct cb_data cb;
+	int rc;
+
+	cb.set = idset_sch_new();
+	if (!cb.set)
+		return -ENOMEM;
+	idset_fill(cb.set);
+	cb.data = data;
+	cb.fn_known_sch = fn_known;
+	cb.fn_unknown_sch = fn_unknown;
+	/* Process registered subchannels. */
+	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
+	if (rc)
+		goto out;
+	/* Process unregistered subchannels. */
+	if (fn_unknown)
+		rc = for_each_subchannel(call_fn_unknown_sch, &cb);
+out:
+	idset_free(cb.set);
+
+	return rc;
+}
+
 static struct subchannel *
 css_alloc_subchannel(struct subchannel_id schid)
 {
@@ -77,7 +133,7 @@
 	 * This is fine even on 64bit since the subchannel is always located
 	 * under 2G.
 	 */
-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
 	ret = cio_modify(sch);
 	if (ret) {
 		kfree(sch->lock);
@@ -237,11 +293,25 @@
 	return dev ? to_subchannel(dev) : NULL;
 }
 
+/**
+ * css_sch_is_valid() - check if a subchannel is valid
+ * @schib: subchannel information block for the subchannel
+ */
+int css_sch_is_valid(struct schib *schib)
+{
+	if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(css_sch_is_valid);
+
 static int css_get_subchannel_status(struct subchannel *sch)
 {
 	struct schib schib;
 
-	if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
+	if (stsch(sch->schid, &schib))
+		return CIO_GONE;
+	if (!css_sch_is_valid(&schib))
 		return CIO_GONE;
 	if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
 		return CIO_REVALIDATE;
@@ -293,7 +363,7 @@
 		action = UNREGISTER;
 		if (sch->driver && sch->driver->notify) {
 			spin_unlock_irqrestore(sch->lock, flags);
-			ret = sch->driver->notify(&sch->dev, event);
+			ret = sch->driver->notify(sch, event);
 			spin_lock_irqsave(sch->lock, flags);
 			if (ret)
 				action = NONE;
@@ -349,7 +419,7 @@
 		/* Will be done on the slow path. */
 		return -EAGAIN;
 	}
-	if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
+	if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) {
 		/* Unusable - ignore. */
 		return 0;
 	}
@@ -388,20 +458,56 @@
 	return 0;
 }
 
+static int slow_eval_known_fn(struct subchannel *sch, void *data)
+{
+	int eval;
+	int rc;
+
+	spin_lock_irq(&slow_subchannel_lock);
+	eval = idset_sch_contains(slow_subchannel_set, sch->schid);
+	idset_sch_del(slow_subchannel_set, sch->schid);
+	spin_unlock_irq(&slow_subchannel_lock);
+	if (eval) {
+		rc = css_evaluate_known_subchannel(sch, 1);
+		if (rc == -EAGAIN)
+			css_schedule_eval(sch->schid);
+	}
+	return 0;
+}
+
+static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
+{
+	int eval;
+	int rc = 0;
+
+	spin_lock_irq(&slow_subchannel_lock);
+	eval = idset_sch_contains(slow_subchannel_set, schid);
+	idset_sch_del(slow_subchannel_set, schid);
+	spin_unlock_irq(&slow_subchannel_lock);
+	if (eval) {
+		rc = css_evaluate_new_subchannel(schid, 1);
+		switch (rc) {
+		case -EAGAIN:
+			css_schedule_eval(schid);
+			rc = 0;
+			break;
+		case -ENXIO:
+		case -ENOMEM:
+		case -EIO:
+			/* These should abort looping */
+			break;
+		default:
+			rc = 0;
+		}
+	}
+	return rc;
+}
+
 static void css_slow_path_func(struct work_struct *unused)
 {
-	struct subchannel_id schid;
-
 	CIO_TRACE_EVENT(4, "slowpath");
-	spin_lock_irq(&slow_subchannel_lock);
-	init_subchannel_id(&schid);
-	while (idset_sch_get_first(slow_subchannel_set, &schid)) {
-		idset_sch_del(slow_subchannel_set, schid);
-		spin_unlock_irq(&slow_subchannel_lock);
-		css_evaluate_subchannel(schid, 1);
-		spin_lock_irq(&slow_subchannel_lock);
-	}
-	spin_unlock_irq(&slow_subchannel_lock);
+	for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
+				   NULL);
 }
 
 static DECLARE_WORK(slow_path_work, css_slow_path_func);
@@ -430,7 +536,6 @@
 /* Reprobe subchannel if unregistered. */
 static int reprobe_subchannel(struct subchannel_id schid, void *data)
 {
-	struct subchannel *sch;
 	int ret;
 
 	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
@@ -438,13 +543,6 @@
 	if (need_reprobe)
 		return -EAGAIN;
 
-	sch = get_subchannel_by_schid(schid);
-	if (sch) {
-		/* Already known. */
-		put_device(&sch->dev);
-		return 0;
-	}
-
 	ret = css_probe_device(schid);
 	switch (ret) {
 	case 0:
@@ -472,7 +570,7 @@
 	/* Make sure initial subchannel scan is done. */
 	wait_event(ccw_device_init_wq,
 		   atomic_read(&ccw_device_init_count) == 0);
-	ret = for_each_subchannel(reprobe_subchannel, NULL);
+	ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
 
 	CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
 		      need_reprobe);
@@ -787,8 +885,8 @@
 static int
 css_bus_match (struct device *dev, struct device_driver *drv)
 {
-	struct subchannel *sch = container_of (dev, struct subchannel, dev);
-	struct css_driver *driver = container_of (drv, struct css_driver, drv);
+	struct subchannel *sch = to_subchannel(dev);
+	struct css_driver *driver = to_cssdriver(drv);
 
 	if (sch->st == driver->subchannel_type)
 		return 1;
@@ -796,32 +894,36 @@
 	return 0;
 }
 
-static int
-css_probe (struct device *dev)
+static int css_probe(struct device *dev)
 {
 	struct subchannel *sch;
+	int ret;
 
 	sch = to_subchannel(dev);
-	sch->driver = container_of (dev->driver, struct css_driver, drv);
-	return (sch->driver->probe ? sch->driver->probe(sch) : 0);
+	sch->driver = to_cssdriver(dev->driver);
+	ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
+	if (ret)
+		sch->driver = NULL;
+	return ret;
 }
 
-static int
-css_remove (struct device *dev)
+static int css_remove(struct device *dev)
 {
 	struct subchannel *sch;
+	int ret;
 
 	sch = to_subchannel(dev);
-	return (sch->driver->remove ? sch->driver->remove(sch) : 0);
+	ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
+	sch->driver = NULL;
+	return ret;
 }
 
-static void
-css_shutdown (struct device *dev)
+static void css_shutdown(struct device *dev)
 {
 	struct subchannel *sch;
 
 	sch = to_subchannel(dev);
-	if (sch->driver->shutdown)
+	if (sch->driver && sch->driver->shutdown)
 		sch->driver->shutdown(sch);
 }
 
@@ -833,6 +935,34 @@
 	.shutdown = css_shutdown,
 };
 
+/**
+ * css_driver_register - register a css driver
+ * @cdrv: css driver to register
+ *
+ * This is mainly a wrapper around driver_register that sets name
+ * and bus_type in the embedded struct device_driver correctly.
+ */
+int css_driver_register(struct css_driver *cdrv)
+{
+	cdrv->drv.name = cdrv->name;
+	cdrv->drv.bus = &css_bus_type;
+	cdrv->drv.owner = cdrv->owner;
+	return driver_register(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_register);
+
+/**
+ * css_driver_unregister - unregister a css driver
+ * @cdrv: css driver to unregister
+ *
+ * This is a wrapper around driver_unregister.
+ */
+void css_driver_unregister(struct css_driver *cdrv)
+{
+	driver_unregister(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_unregister);
+
 subsys_initcall(init_channel_subsystem);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 81215ef..b705545 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -58,64 +58,6 @@
 	__u32 tod_high;		/* high word TOD clock */
 } __attribute__ ((packed));
 
-#define MAX_CIWS 8
-
-/*
- * sense-id response buffer layout
- */
-struct senseid {
-	/* common part */
-	__u8  reserved;     	/* always 0x'FF' */
-	__u16 cu_type;	     	/* control unit type */
-	__u8  cu_model;     	/* control unit model */
-	__u16 dev_type;     	/* device type */
-	__u8  dev_model;    	/* device model */
-	__u8  unused;	     	/* padding byte */
-	/* extended part */
-	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
-}  __attribute__ ((packed,aligned(4)));
-
-struct ccw_device_private {
-	struct ccw_device *cdev;
-	struct subchannel *sch;
-	int state;		/* device state */
-	atomic_t onoff;
-	unsigned long registered;
-	struct ccw_dev_id dev_id;	/* device id */
-	struct subchannel_id schid;	/* subchannel number */
-	__u8 imask;		/* lpm mask for SNID/SID/SPGID */
-	int iretry;		/* retry counter SNID/SID/SPGID */
-	struct {
-		unsigned int fast:1;	/* post with "channel end" */
-		unsigned int repall:1;	/* report every interrupt status */
-		unsigned int pgroup:1;  /* do path grouping */
-		unsigned int force:1;   /* allow forced online */
-	} __attribute__ ((packed)) options;
-	struct {
-		unsigned int pgid_single:1; /* use single path for Set PGID */
-		unsigned int esid:1;        /* Ext. SenseID supported by HW */
-		unsigned int dosense:1;	    /* delayed SENSE required */
-		unsigned int doverify:1;    /* delayed path verification */
-		unsigned int donotify:1;    /* call notify function */
-		unsigned int recog_done:1;  /* dev. recog. complete */
-		unsigned int fake_irb:1;    /* deliver faked irb */
-		unsigned int intretry:1;    /* retry internal operation */
-	} __attribute__((packed)) flags;
-	unsigned long intparm;	/* user interruption parameter */
-	struct qdio_irq *qdio_data;
-	struct irb irb;		/* device status */
-	struct senseid senseid;	/* SenseID info */
-	struct pgid pgid[8];	/* path group IDs per chpid*/
-	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
-	struct work_struct kick_work;
-	wait_queue_head_t wait_q;
-	struct timer_list timer;
-	void *cmb;			/* measurement information */
-	struct list_head cmb_list;	/* list of measured devices */
-	u64 cmb_start_time;		/* clock value of cmb reset */
-	void *cmb_wait;			/* deferred cmb enable/disable */
-};
-
 /*
  * A css driver handles all subchannels of one type.
  * Currently, we only care about I/O subchannels (type 0), these
@@ -123,25 +65,35 @@
  */
 struct subchannel;
 struct css_driver {
+	struct module *owner;
 	unsigned int subchannel_type;
 	struct device_driver drv;
-	void (*irq)(struct device *);
-	int (*notify)(struct device *, int);
-	void (*verify)(struct device *);
-	void (*termination)(struct device *);
+	void (*irq)(struct subchannel *);
+	int (*notify)(struct subchannel *, int);
+	void (*verify)(struct subchannel *);
+	void (*termination)(struct subchannel *);
 	int (*probe)(struct subchannel *);
 	int (*remove)(struct subchannel *);
 	void (*shutdown)(struct subchannel *);
+	const char *name;
 };
 
+#define to_cssdriver(n) container_of(n, struct css_driver, drv)
+
 /*
  * all css_drivers have the css_bus_type
  */
 extern struct bus_type css_bus_type;
 
+extern int css_driver_register(struct css_driver *);
+extern void css_driver_unregister(struct css_driver *);
+
 extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+			       int (*fn_unknown)(struct subchannel_id,
+			       void *), void *data);
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
 extern void css_process_crw(int, int);
 extern void css_reiterate_subchannels(void);
@@ -188,6 +140,8 @@
 void css_schedule_eval_all(void);
 
 int sch_is_pseudo_sch(struct subchannel *);
+struct schib;
+int css_sch_is_valid(struct schib *);
 
 extern struct workqueue_struct *slow_path_wq;
 
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 74f6b53..d35dc3f 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <linux/timer.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -28,6 +29,12 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
+
+static struct timer_list recovery_timer;
+static spinlock_t recovery_lock;
+static int recovery_phase;
+static const unsigned long recovery_delay[] = { 3, 30, 300 };
 
 /******************* bus type handling ***********************/
 
@@ -115,19 +122,18 @@
 
 struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct subchannel *);
-static int io_subchannel_remove (struct subchannel *);
-static int io_subchannel_notify(struct device *, int);
-static void io_subchannel_verify(struct device *);
-static void io_subchannel_ioterm(struct device *);
+static void io_subchannel_irq(struct subchannel *);
+static int io_subchannel_probe(struct subchannel *);
+static int io_subchannel_remove(struct subchannel *);
+static int io_subchannel_notify(struct subchannel *, int);
+static void io_subchannel_verify(struct subchannel *);
+static void io_subchannel_ioterm(struct subchannel *);
 static void io_subchannel_shutdown(struct subchannel *);
 
 static struct css_driver io_subchannel_driver = {
+	.owner = THIS_MODULE,
 	.subchannel_type = SUBCHANNEL_TYPE_IO,
-	.drv = {
-		.name = "io_subchannel",
-		.bus  = &css_bus_type,
-	},
+	.name = "io_subchannel",
 	.irq = io_subchannel_irq,
 	.notify = io_subchannel_notify,
 	.verify = io_subchannel_verify,
@@ -142,6 +148,8 @@
 wait_queue_head_t ccw_device_init_wq;
 atomic_t ccw_device_init_count;
 
+static void recovery_func(unsigned long data);
+
 static int __init
 init_ccw_bus_type (void)
 {
@@ -149,6 +157,7 @@
 
 	init_waitqueue_head(&ccw_device_init_wq);
 	atomic_set(&ccw_device_init_count, 0);
+	setup_timer(&recovery_timer, recovery_func, 0);
 
 	ccw_device_work = create_singlethread_workqueue("cio");
 	if (!ccw_device_work)
@@ -166,7 +175,8 @@
 	if ((ret = bus_register (&ccw_bus_type)))
 		goto out_err;
 
-	if ((ret = driver_register(&io_subchannel_driver.drv)))
+	ret = css_driver_register(&io_subchannel_driver);
+	if (ret)
 		goto out_err;
 
 	wait_event(ccw_device_init_wq,
@@ -186,7 +196,7 @@
 static void __exit
 cleanup_ccw_bus_type (void)
 {
-	driver_unregister(&io_subchannel_driver.drv);
+	css_driver_unregister(&io_subchannel_driver);
 	bus_unregister(&ccw_bus_type);
 	destroy_workqueue(ccw_device_notify_work);
 	destroy_workqueue(ccw_device_work);
@@ -773,7 +783,7 @@
 {
 	css_update_ssd_info(sch);
 	spin_lock_irq(sch->lock);
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	cdev->private->schid = sch->schid;
 	cdev->ccwlock = sch->lock;
 	device_trigger_reprobe(sch);
@@ -795,7 +805,7 @@
 		put_device(&other_sch->dev);
 		return;
 	}
-	other_sch->dev.driver_data = NULL;
+	sch_set_cdev(other_sch, NULL);
 	/* No need to keep a subchannel without ccw device around. */
 	css_sch_device_unregister(other_sch);
 	put_device(&other_sch->dev);
@@ -831,12 +841,12 @@
 		return;
 	}
 	spin_lock_irq(sch->lock);
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	spin_unlock_irq(sch->lock);
 	/* Start recognition for the new ccw device. */
 	if (io_subchannel_recog(cdev, sch)) {
 		spin_lock_irq(sch->lock);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irq(sch->lock);
 		if (cdev->dev.release)
 			cdev->dev.release(&cdev->dev);
@@ -940,7 +950,7 @@
 			      cdev->private->dev_id.devno, ret);
 		put_device(&cdev->dev);
 		spin_lock_irqsave(sch->lock, flags);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irqrestore(sch->lock, flags);
 		kfree (cdev->private);
 		kfree (cdev);
@@ -1022,7 +1032,7 @@
 	int rc;
 	struct ccw_device_private *priv;
 
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	sch->driver = &io_subchannel_driver;
 	cdev->ccwlock = sch->lock;
 
@@ -1082,7 +1092,7 @@
 	}
 	if (former_parent) {
 		spin_lock_irq(former_parent->lock);
-		former_parent->dev.driver_data = NULL;
+		sch_set_cdev(former_parent, NULL);
 		spin_unlock_irq(former_parent->lock);
 		css_sch_device_unregister(former_parent);
 		/* Reset intparm to zeroes. */
@@ -1096,6 +1106,18 @@
 	put_device(&cdev->dev);
 }
 
+static void io_subchannel_irq(struct subchannel *sch)
+{
+	struct ccw_device *cdev;
+
+	cdev = sch_get_cdev(sch);
+
+	CIO_TRACE_EVENT(3, "IRQ");
+	CIO_TRACE_EVENT(3, sch->dev.bus_id);
+	if (cdev)
+		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+}
+
 static int
 io_subchannel_probe (struct subchannel *sch)
 {
@@ -1104,13 +1126,13 @@
 	unsigned long flags;
 	struct ccw_dev_id dev_id;
 
-	if (sch->dev.driver_data) {
+	cdev = sch_get_cdev(sch);
+	if (cdev) {
 		/*
 		 * This subchannel already has an associated ccw_device.
 		 * Register it and exit. This happens for all early
 		 * device, e.g. the console.
 		 */
-		cdev = sch->dev.driver_data;
 		cdev->dev.groups = ccwdev_attr_groups;
 		device_initialize(&cdev->dev);
 		ccw_device_register(cdev);
@@ -1132,6 +1154,11 @@
 	 */
 	dev_id.devno = sch->schib.pmcw.dev;
 	dev_id.ssid = sch->schid.ssid;
+	/* Allocate I/O subchannel private data. */
+	sch->private = kzalloc(sizeof(struct io_subchannel_private),
+			       GFP_KERNEL | GFP_DMA);
+	if (!sch->private)
+		return -ENOMEM;
 	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
 	if (!cdev)
 		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1149,16 +1176,18 @@
 		return 0;
 	}
 	cdev = io_subchannel_create_ccwdev(sch);
-	if (IS_ERR(cdev))
+	if (IS_ERR(cdev)) {
+		kfree(sch->private);
 		return PTR_ERR(cdev);
-
+	}
 	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
 		spin_lock_irqsave(sch->lock, flags);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irqrestore(sch->lock, flags);
 		if (cdev->dev.release)
 			cdev->dev.release(&cdev->dev);
+		kfree(sch->private);
 	}
 
 	return rc;
@@ -1170,25 +1199,25 @@
 	struct ccw_device *cdev;
 	unsigned long flags;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	/* Set ccw device to not operational and drop reference. */
 	spin_lock_irqsave(cdev->ccwlock, flags);
-	sch->dev.driver_data = NULL;
+	sch_set_cdev(sch, NULL);
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	spin_unlock_irqrestore(cdev->ccwlock, flags);
 	ccw_device_unregister(cdev);
 	put_device(&cdev->dev);
+	kfree(sch->private);
 	return 0;
 }
 
-static int
-io_subchannel_notify(struct device *dev, int event)
+static int io_subchannel_notify(struct subchannel *sch, int event)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return 0;
 	if (!cdev->drv)
@@ -1198,22 +1227,20 @@
 	return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
 }
 
-static void
-io_subchannel_verify(struct device *dev)
+static void io_subchannel_verify(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (cdev)
 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 }
 
-static void
-io_subchannel_ioterm(struct device *dev)
+static void io_subchannel_ioterm(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return;
 	/* Internal I/O will be retried by the interrupt handler. */
@@ -1231,7 +1258,7 @@
 	struct ccw_device *cdev;
 	int ret;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 
 	if (cio_is_console(sch->schid))
 		return;
@@ -1271,6 +1298,9 @@
 {
 	int rc;
 
+	/* Attach subchannel private data. */
+	sch->private = cio_get_console_priv();
+	memset(sch->private, 0, sizeof(struct io_subchannel_private));
 	/* Initialize the ccw_device structure. */
 	cdev->dev.parent= &sch->dev;
 	rc = io_subchannel_recog(cdev, sch);
@@ -1456,6 +1486,7 @@
 
 	drv->bus = &ccw_bus_type;
 	drv->name = cdriver->name;
+	drv->owner = cdriver->owner;
 
 	return driver_register(drv);
 }
@@ -1481,6 +1512,60 @@
 	return sch->schid;
 }
 
+static int recovery_check(struct device *dev, void *data)
+{
+	struct ccw_device *cdev = to_ccwdev(dev);
+	int *redo = data;
+
+	spin_lock_irq(cdev->ccwlock);
+	switch (cdev->private->state) {
+	case DEV_STATE_DISCONNECTED:
+		CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+			      cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
+		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+		*redo = 1;
+		break;
+	case DEV_STATE_DISCONNECTED_SENSE_ID:
+		*redo = 1;
+		break;
+	}
+	spin_unlock_irq(cdev->ccwlock);
+
+	return 0;
+}
+
+static void recovery_func(unsigned long data)
+{
+	int redo = 0;
+
+	bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
+	if (redo) {
+		spin_lock_irq(&recovery_lock);
+		if (!timer_pending(&recovery_timer)) {
+			if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
+				recovery_phase++;
+			mod_timer(&recovery_timer, jiffies +
+				  recovery_delay[recovery_phase] * HZ);
+		}
+		spin_unlock_irq(&recovery_lock);
+	} else
+		CIO_MSG_EVENT(2, "recovery: end\n");
+}
+
+void ccw_device_schedule_recovery(void)
+{
+	unsigned long flags;
+
+	CIO_MSG_EVENT(2, "recovery: schedule\n");
+	spin_lock_irqsave(&recovery_lock, flags);
+	if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
+		recovery_phase = 0;
+		mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
+	}
+	spin_unlock_irqrestore(&recovery_lock, flags);
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 0d40896..d40a2ff 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -5,6 +5,8 @@
 #include <asm/atomic.h>
 #include <linux/wait.h>
 
+#include "io_sch.h"
+
 /*
  * states of the device statemachine
  */
@@ -74,7 +76,6 @@
 extern wait_queue_head_t ccw_device_init_wq;
 extern atomic_t ccw_device_init_count;
 
-void io_subchannel_irq (struct device *pdev);
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -87,6 +88,8 @@
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 
+void ccw_device_schedule_recovery(void);
+
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
 void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index bfad421..4b92c84 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -25,14 +25,16 @@
 #include "ioasm.h"
 #include "chp.h"
 
+static int timeout_log_enabled;
+
 int
 device_is_online(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	return (cdev->private->state == DEV_STATE_ONLINE);
 }
 
@@ -41,9 +43,9 @@
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	return (cdev->private->state == DEV_STATE_DISCONNECTED ||
 		cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
 }
@@ -53,19 +55,21 @@
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	ccw_device_set_timeout(cdev, 0);
 	cdev->private->flags.fake_irb = 0;
 	cdev->private->state = DEV_STATE_DISCONNECTED;
+	if (cdev->online)
+		ccw_device_schedule_recovery();
 }
 
 void device_set_intretry(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return;
 	cdev->private->flags.intretry = 1;
@@ -75,13 +79,62 @@
 {
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev || !cdev->online)
 		return -EINVAL;
 	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 	return 0;
 }
 
+static int __init ccw_timeout_log_setup(char *unused)
+{
+	timeout_log_enabled = 1;
+	return 1;
+}
+
+__setup("ccw_timeout_log", ccw_timeout_log_setup);
+
+static void ccw_timeout_log(struct ccw_device *cdev)
+{
+	struct schib schib;
+	struct subchannel *sch;
+	struct io_subchannel_private *private;
+	int cc;
+
+	sch = to_subchannel(cdev->dev.parent);
+	private = to_io_private(sch);
+	cc = stsch(sch->schid, &schib);
+
+	printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
+	       "device information:\n", get_clock());
+	printk(KERN_WARNING "cio: orb:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &private->orb, sizeof(private->orb), 0);
+	printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
+	printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
+	printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
+	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
+
+	if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
+	    (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
+		printk(KERN_WARNING "cio: last channel program (intern):\n");
+	else
+		printk(KERN_WARNING "cio: last channel program:\n");
+
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       (void *)(addr_t)private->orb.cpa,
+		       sizeof(struct ccw1), 0);
+	printk(KERN_WARNING "cio: ccw device state: %d\n",
+	       cdev->private->state);
+	printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
+	printk(KERN_WARNING "cio: schib:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &schib, sizeof(schib), 0);
+	printk(KERN_WARNING "cio: ccw device flags:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &cdev->private->flags, sizeof(cdev->private->flags), 0);
+}
+
 /*
  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
  */
@@ -92,6 +145,8 @@
 
 	cdev = (struct ccw_device *) data;
 	spin_lock_irq(cdev->ccwlock);
+	if (timeout_log_enabled)
+		ccw_timeout_log(cdev);
 	dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
 	spin_unlock_irq(cdev->ccwlock);
 }
@@ -122,9 +177,9 @@
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	ccw_device_set_timeout(cdev, 0);
 }
 
@@ -268,7 +323,7 @@
 	switch (state) {
 	case DEV_STATE_NOT_OPER:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: SenseID : unknown device %04x on subchannel "
+			  "SenseID : unknown device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -294,7 +349,7 @@
 		}
 		/* Issue device info message. */
 		CIO_DEBUG(KERN_INFO, 2,
-			  "cio: SenseID : device 0.%x.%04x reports: "
+			  "SenseID : device 0.%x.%04x reports: "
 			  "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
 			  "%04X/%02X\n",
 			  cdev->private->dev_id.ssid,
@@ -304,7 +359,7 @@
 		break;
 	case DEV_STATE_BOXED:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: SenseID : boxed device %04x on subchannel "
+			  "SenseID : boxed device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -349,7 +404,7 @@
 	sch = to_subchannel(cdev->dev.parent);
 	if (sch->driver && sch->driver->notify) {
 		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		ret = sch->driver->notify(&sch->dev, CIO_OPER);
+		ret = sch->driver->notify(sch, CIO_OPER);
 		spin_lock_irqsave(cdev->ccwlock, flags);
 	} else
 		ret = 0;
@@ -389,7 +444,7 @@
 
 	if (state == DEV_STATE_BOXED)
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: Boxed device %04x on subchannel %04x\n",
+			  "Boxed device %04x on subchannel %04x\n",
 			  cdev->private->dev_id.devno, sch->schid.sch_no);
 
 	if (cdev->private->flags.donotify) {
@@ -500,7 +555,8 @@
 	    (cdev->private->state != DEV_STATE_BOXED))
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				    (u32)(addr_t)sch);
 	if (ret != 0)
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		return ret;
@@ -587,9 +643,10 @@
 	default:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
-		if (cdev->online)
+		if (cdev->online) {
+			ccw_device_set_timeout(cdev, 0);
 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-		else
+		} else
 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -610,7 +667,8 @@
 	sch = to_subchannel(cdev->dev.parent);
 	if (css_init_done && !get_device(&cdev->dev))
 		return -ENODEV;
-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				    (u32)(addr_t)sch);
 	if (ret != 0) {
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		if (ret == -ENODEV)
@@ -937,7 +995,7 @@
 	int ret;
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	ret = ccw_device_cancel_halt_clear(cdev);
 	if (ret == -EBUSY) {
 		ccw_device_set_timeout(cdev, 3*HZ);
@@ -990,7 +1048,8 @@
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
-	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0)
+	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				  (u32)(addr_t)sch) != 0)
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		return;
 
@@ -1006,9 +1065,9 @@
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	if (cdev->private->state != DEV_STATE_DISCONNECTED)
 		return;
 
@@ -1028,7 +1087,7 @@
 	sch->schib.pmcw.ena = 0;
 	if ((sch->lpm & (sch->lpm - 1)) != 0)
 		sch->schib.pmcw.mp = 1;
-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
 	/* We should also udate ssd info, but this has to wait. */
 	/* Check if this is another device which appeared on the same sch. */
 	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
@@ -1223,21 +1282,4 @@
 	},
 };
 
-/*
- * io_subchannel_irq is called for "real" interrupts or for status
- * pending conditions on msch.
- */
-void
-io_subchannel_irq (struct device *pdev)
-{
-	struct ccw_device *cdev;
-
-	cdev = to_subchannel(pdev)->dev.driver_data;
-
-	CIO_TRACE_EVENT (3, "IRQ");
-	CIO_TRACE_EVENT (3, pdev->bus_id);
-	if (cdev)
-		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
-}
-
 EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 156f3f9..918b8b8 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -24,6 +24,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Input :
@@ -219,11 +220,13 @@
 		return -EAGAIN;
 	}
 	if (irb->scsw.cc == 3) {
-		if ((sch->orb.lpm &
-		     sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
+		u8 lpm;
+
+		lpm = to_io_private(sch)->orb.lpm;
+		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
 			CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
 				      "on subchannel 0.%x.%04x is "
-				      "'not operational'\n", sch->orb.lpm,
+				      "'not operational'\n", lpm,
 				      cdev->private->dev_id.devno,
 				      sch->schid.ssid, sch->schid.sch_no);
 		return -EACCES;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 7fd2dad..49b58eb 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -501,7 +501,7 @@
 		return -ENOMEM;
 	}
 	spin_lock_irqsave(sch->lock, flags);
-	ret = cio_enable_subchannel(sch, 3);
+	ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
 	if (ret)
 		goto out_unlock;
 	/*
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index cb1879a..c52449a 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -22,6 +22,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Helper function called from interrupt context to decide whether an
@@ -155,10 +156,13 @@
 		return -EAGAIN;
 	}
 	if (irb->scsw.cc == 3) {
+		u8 lpm;
+
+		lpm = to_io_private(sch)->orb.lpm;
 		CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
 			      " lpm %02X, became 'not operational'\n",
 			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, sch->orb.lpm);
+			      sch->schid.sch_no, lpm);
 		return -EACCES;
 	}
 	i = 8 - ffs(cdev->private->imask);
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index aa96e67..ebe0848 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -20,6 +20,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Check for any kind of channel or interface control check but don't
@@ -310,6 +311,7 @@
 ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
 {
 	struct subchannel *sch;
+	struct ccw1 *sense_ccw;
 
 	sch = to_subchannel(cdev->dev.parent);
 
@@ -326,15 +328,16 @@
 	/*
 	 * We have ending status but no sense information. Do a basic sense.
 	 */
-	sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
-	sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
-	sch->sense_ccw.count = SENSE_MAX_COUNT;
-	sch->sense_ccw.flags = CCW_FLAG_SLI;
+	sense_ccw = &to_io_private(sch)->sense_ccw;
+	sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+	sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
+	sense_ccw->count = SENSE_MAX_COUNT;
+	sense_ccw->flags = CCW_FLAG_SLI;
 
 	/* Reset internal retry indication. */
 	cdev->private->flags.intretry = 0;
 
-	return cio_start (sch, &sch->sense_ccw, 0xff);
+	return cio_start(sch, sense_ccw, 0xff);
 }
 
 /*
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
new file mode 100644
index 0000000..8c61316
--- /dev/null
+++ b/drivers/s390/cio/io_sch.h
@@ -0,0 +1,163 @@
+#ifndef S390_IO_SCH_H
+#define S390_IO_SCH_H
+
+#include "schid.h"
+
+/*
+ * operation request block
+ */
+struct orb {
+	u32 intparm;	/* interruption parameter */
+	u32 key  : 4;	/* flags, like key, suspend control, etc. */
+	u32 spnd : 1;	/* suspend control */
+	u32 res1 : 1;	/* reserved */
+	u32 mod  : 1;	/* modification control */
+	u32 sync : 1;	/* synchronize control */
+	u32 fmt  : 1;	/* format control */
+	u32 pfch : 1;	/* prefetch control */
+	u32 isic : 1;	/* initial-status-interruption control */
+	u32 alcc : 1;	/* address-limit-checking control */
+	u32 ssic : 1;	/* suppress-suspended-interr. control */
+	u32 res2 : 1;	/* reserved */
+	u32 c64  : 1;	/* IDAW/QDIO 64 bit control  */
+	u32 i2k  : 1;	/* IDAW 2/4kB block size control */
+	u32 lpm  : 8;	/* logical path mask */
+	u32 ils  : 1;	/* incorrect length */
+	u32 zero : 6;	/* reserved zeros */
+	u32 orbx : 1;	/* ORB extension control */
+	u32 cpa;	/* channel program address */
+}  __attribute__ ((packed, aligned(4)));
+
+struct io_subchannel_private {
+	struct orb orb;		/* operation request block */
+	struct ccw1 sense_ccw;	/* static ccw for sense command */
+} __attribute__ ((aligned(8)));
+
+#define to_io_private(n) ((struct io_subchannel_private *)n->private)
+#define sch_get_cdev(n) (dev_get_drvdata(&n->dev))
+#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c))
+
+#define MAX_CIWS 8
+
+/*
+ * sense-id response buffer layout
+ */
+struct senseid {
+	/* common part */
+	u8  reserved;	/* always 0x'FF' */
+	u16 cu_type;	/* control unit type */
+	u8  cu_model;	/* control unit model */
+	u16 dev_type;	/* device type */
+	u8  dev_model;	/* device model */
+	u8  unused;	/* padding byte */
+	/* extended part */
+	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
+}  __attribute__ ((packed, aligned(4)));
+
+struct ccw_device_private {
+	struct ccw_device *cdev;
+	struct subchannel *sch;
+	int state;		/* device state */
+	atomic_t onoff;
+	unsigned long registered;
+	struct ccw_dev_id dev_id;	/* device id */
+	struct subchannel_id schid;	/* subchannel number */
+	u8 imask;		/* lpm mask for SNID/SID/SPGID */
+	int iretry;		/* retry counter SNID/SID/SPGID */
+	struct {
+		unsigned int fast:1;	/* post with "channel end" */
+		unsigned int repall:1;	/* report every interrupt status */
+		unsigned int pgroup:1;	/* do path grouping */
+		unsigned int force:1;	/* allow forced online */
+	} __attribute__ ((packed)) options;
+	struct {
+		unsigned int pgid_single:1; /* use single path for Set PGID */
+		unsigned int esid:1;	    /* Ext. SenseID supported by HW */
+		unsigned int dosense:1;	    /* delayed SENSE required */
+		unsigned int doverify:1;    /* delayed path verification */
+		unsigned int donotify:1;    /* call notify function */
+		unsigned int recog_done:1;  /* dev. recog. complete */
+		unsigned int fake_irb:1;    /* deliver faked irb */
+		unsigned int intretry:1;    /* retry internal operation */
+	} __attribute__((packed)) flags;
+	unsigned long intparm;	/* user interruption parameter */
+	struct qdio_irq *qdio_data;
+	struct irb irb;		/* device status */
+	struct senseid senseid;	/* SenseID info */
+	struct pgid pgid[8];	/* path group IDs per chpid*/
+	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
+	struct work_struct kick_work;
+	wait_queue_head_t wait_q;
+	struct timer_list timer;
+	void *cmb;			/* measurement information */
+	struct list_head cmb_list;	/* list of measured devices */
+	u64 cmb_start_time;		/* clock value of cmb reset */
+	void *cmb_wait;			/* deferred cmb enable/disable */
+};
+
+static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	ssch	0(%2)\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+	return ccode;
+}
+
+static inline int rsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	rsch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int csch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	csch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int hsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	hsch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int xsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	.insn	rre,0xb2760000,%1,0\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+#endif
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 7153dd9..652ea36 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -109,72 +109,6 @@
 	return ccode;
 }
 
-static inline int ssch(struct subchannel_id schid,
-			   volatile struct orb *addr)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	ssch	0(%2)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
-	return ccode;
-}
-
-static inline int rsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	rsch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	csch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	hsch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	.insn	rre,0xb2760000,%1,0\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
 static inline int chsc(void *chsc_area)
 {
 	typedef struct { char _[4096]; } addr_type;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 40a3208..e2a781b 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -48,11 +48,11 @@
 #include <asm/debug.h>
 #include <asm/s390_rdev.h>
 #include <asm/qdio.h>
+#include <asm/airq.h>
 
 #include "cio.h"
 #include "css.h"
 #include "device.h"
-#include "airq.h"
 #include "qdio.h"
 #include "ioasm.h"
 #include "chsc.h"
@@ -96,7 +96,7 @@
 static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
 						 during a while loop */
 static DEFINE_SPINLOCK(ttiq_list_lock);
-static int register_thinint_result;
+static void *tiqdio_ind;
 static void tiqdio_tl(unsigned long);
 static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
 
@@ -399,7 +399,7 @@
 {
 	int i;
 
-	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
+	for (i = 0; i < INDICATORS_PER_CACHELINE; i++)
 		if (!indicator_used[i]) {
 			indicator_used[i]=1;
 			return indicators+i;
@@ -1408,8 +1408,7 @@
 	if (q->hydra_gives_outbound_pcis) {
 		if (!q->siga_sync_done_on_thinints) {
 			SYNC_MEMORY_ALL;
-		} else if ((!q->siga_sync_done_on_outb_tis)&&
-			 (q->hydra_gives_outbound_pcis)) {
+		} else if (!q->siga_sync_done_on_outb_tis) {
 			SYNC_MEMORY_ALL_OUTB;
 		}
 	} else {
@@ -1911,8 +1910,7 @@
 	}
 }
 
-static int
-tiqdio_thinint_handler(void)
+static void tiqdio_thinint_handler(void *ind, void *drv_data)
 {
 	QDIO_DBF_TEXT4(0,trace,"thin_int");
 
@@ -1925,7 +1923,6 @@
 		tiqdio_clear_global_summary();
 
 	tiqdio_inbound_checks();
-	return 0;
 }
 
 static void
@@ -2445,7 +2442,7 @@
 		real_addr_dev_st_chg_ind=0;
 	} else {
 		real_addr_local_summary_bit=
-			virt_to_phys((volatile void *)indicators);
+			virt_to_phys((volatile void *)tiqdio_ind);
 		real_addr_dev_st_chg_ind=
 			virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
 	}
@@ -3740,23 +3737,25 @@
 tiqdio_register_thinints(void)
 {
 	char dbf_text[20];
-	register_thinint_result=
-		s390_register_adapter_interrupt(&tiqdio_thinint_handler);
-	if (register_thinint_result) {
-		sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
+
+	tiqdio_ind =
+		s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
+	if (IS_ERR(tiqdio_ind)) {
+		sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
 		QDIO_DBF_TEXT0(0,setup,dbf_text);
 		QDIO_PRINT_ERR("failed to register adapter handler " \
-			       "(rc=%i).\nAdapter interrupts might " \
+			       "(rc=%li).\nAdapter interrupts might " \
 			       "not work. Continuing.\n",
-			       register_thinint_result);
+			       PTR_ERR(tiqdio_ind));
+		tiqdio_ind = NULL;
 	}
 }
 
 static void
 tiqdio_unregister_thinints(void)
 {
-	if (!register_thinint_result)
-		s390_unregister_adapter_interrupt(&tiqdio_thinint_handler);
+	if (tiqdio_ind)
+		s390_unregister_adapter_interrupt(tiqdio_ind);
 }
 
 static int
@@ -3768,8 +3767,8 @@
 	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
 		indicator_used[i]=0;
 	indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
-				   GFP_KERNEL);
-       	if (!indicators)
+			     GFP_KERNEL);
+	if (!indicators)
 		return -ENOMEM;
 	return 0;
 }
@@ -3780,7 +3779,6 @@
 	kfree(indicators);
 }
 
-
 static void
 qdio_unregister_dbf_views(void)
 {
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 6d7aad1..37870e4 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -57,7 +57,7 @@
 					    of the queue to 0 */
 
 #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
-#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
+#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
 #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
 #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
 #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 3561982..c307621 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -2416,7 +2416,7 @@
 		    privptr->p_buff_pages_perwrite);
 #endif
                    if (p_buff==NULL) {
-                        printk(KERN_INFO "%s:%s __get_free_pages"
+			printk(KERN_INFO "%s:%s __get_free_pages "
 			 	"for writes buf failed : get is for %d pages\n",
 				dev->name,
 				__FUNCTION__,
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 0fd663b..7bfe8d7 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1115,7 +1115,7 @@
 			rc = lcs_send_setipm(card, ipm);
 			spin_lock_irqsave(&card->ipm_lock, flags);
 			if (rc) {
-				PRINT_INFO("Adding multicast address failed."
+				PRINT_INFO("Adding multicast address failed. "
 					   "Table possibly full!\n");
 				/* store ipm in failed list -> will be added
 				 * to ipm_list again, so a retry will be done
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index d6e93f1..f3d893c 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -198,8 +198,7 @@
 /**
  * Linked list of all connection structs.
  */
-static struct list_head iucv_connection_list =
-	LIST_HEAD_INIT(iucv_connection_list);
+static LIST_HEAD(iucv_connection_list);
 static DEFINE_RWLOCK(iucv_connection_rwlock);
 
 /**
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index f1ff165..46ecd03 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -146,7 +146,7 @@
 	return 0;
 }
 
-static struct seq_operations qeth_procfile_seq_ops = {
+static const struct seq_operations qeth_procfile_seq_ops = {
 	.start = qeth_procfile_seq_start,
 	.stop  = qeth_procfile_seq_stop,
 	.next  = qeth_procfile_seq_next,
@@ -264,7 +264,7 @@
 	return 0;
 }
 
-static struct seq_operations qeth_perf_procfile_seq_ops = {
+static const struct seq_operations qeth_perf_procfile_seq_ops = {
 	.start = qeth_procfile_seq_start,
 	.stop  = qeth_procfile_seq_stop,
 	.next  = qeth_procfile_seq_next,
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 47bb47b..8735a41 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -42,7 +42,7 @@
 static struct iucv_path *smsg_path;
 
 static DEFINE_SPINLOCK(smsg_list_lock);
-static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
+static LIST_HEAD(smsg_list);
 
 static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
 static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4f86c0e..2dc8110 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1286,7 +1286,7 @@
 	 * note: no lock in subsequent strategy routines
 	 * (this allows these routine to call schedule, e.g.
 	 * kmalloc with such flags or qdio_initialize & friends)
-	 * Note: in case of timeout, the seperate strategies will fail
+	 * Note: in case of timeout, the separate strategies will fail
 	 * anyhow. No need for a special action. Even worse, a nameserver
 	 * failure would not wake up waiting ports without the call.
 	 */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index fe57941a..e45f85f 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -502,7 +502,7 @@
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 	case FSF_SQ_NO_RECOM:
-		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
+		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a "
 				"problem on the adapter %s "
 				"Stopping all operations on this adapter. ",
 				zfcp_get_busid_by_adapter(fsf_req->adapter));
@@ -813,7 +813,7 @@
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 
 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
-		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
+		ZFCP_LOG_NORMAL("bug: Reopen port indication received for "
 				"nonexisting port with d_id 0x%06x on "
 				"adapter %s. Ignored.\n",
 				status_buffer->d_id & ZFCP_DID_MASK,
@@ -2281,7 +2281,7 @@
 				     &lock_flags, &fsf_req);
 	if (retval) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-			      "exchange port data request for"
+			      "exchange port data request for "
 			      "the adapter %s.\n",
 			      zfcp_get_busid_by_adapter(adapter));
 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -2340,7 +2340,7 @@
 				0, NULL, &lock_flags, &fsf_req);
 	if (retval) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-			      "exchange port data request for"
+			      "exchange port data request for "
 			      "the adapter %s.\n",
 			      zfcp_get_busid_by_adapter(adapter));
 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -4725,7 +4725,7 @@
 	/* allocate new FSF request */
 	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
 	if (unlikely(NULL == fsf_req)) {
-		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
+		ZFCP_LOG_DEBUG("error: Could not put an FSF request into "
 			       "the outbound (send) queue.\n");
 		ret = -ENOMEM;
 		goto failed_fsf_req;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 51d92b1..22fdc17 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -529,7 +529,7 @@
 
 
 /**
- * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
+ * zfcp_qdio_sbale_fill - set address and length in current SBALE
  *	on request_queue
  */
 static void
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index facb678..6a48dfa 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -277,6 +277,8 @@
 	if (termios->c_iflag & INPCK)
 		port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
 
+	tty_encode_baud_rate(tty,  baud, baud);
+
 	/*
 	 * Which character status flags should we ignore?
 	 */
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 6f475b6..ac2a3ef 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -442,7 +442,8 @@
 		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
 			INTR_ON_BUF,
 			DIMENSION_LINEAR,
-			DATA_SIZE_8));
+			DATA_SIZE_8,
+			DMA_SYNC_RESTART));
 	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
 	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
 	set_dma_x_modify(uart->tx_dma_channel, 1);
@@ -689,7 +690,8 @@
 	set_dma_config(uart->rx_dma_channel,
 		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
 				INTR_ON_ROW, DIMENSION_2D,
-				DATA_SIZE_8));
+				DATA_SIZE_8,
+				DMA_SYNC_RESTART));
 	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
 	set_dma_x_modify(uart->rx_dma_channel, 1);
 	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f81d08d..77a3759 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -308,7 +308,7 @@
 
 config USB_GADGET_AT91
 	boolean "AT91 USB Device Port"
-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
+	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
 	select USB_GADGET_SELECTED
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 5cfa3d1..74e1f4b 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -47,7 +47,7 @@
 #endif
 
 #ifdef CONFIG_TPS65010
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 #else
 
 #define LOW	0
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index ca2a6ab..6c52c66 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -112,9 +112,9 @@
 static int isp1301_command(struct i2c_client *client, unsigned int cmd,
 			   void *arg);
 
-static unsigned short normal_i2c[] =
+static const unsigned short normal_i2c[] =
     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
 
 static struct i2c_client_address_data addr_data = {
 	.normal_i2c = normal_i2c,
@@ -123,7 +123,6 @@
 };
 
 struct i2c_driver isp1301_driver = {
-	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
 	.class = I2C_CLASS_HWMON,
 	.attach_adapter = isp1301_probe,
 	.detach_client = isp1301_detach,
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5b3dbcf..758435f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -889,7 +889,7 @@
 
 config FB_ATMEL
 	tristate "AT91/AT32 LCD Controller support"
-	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 7c30cc8..f8e7111 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -30,7 +30,7 @@
 #define ATMEL_LCDC_CVAL_DEFAULT		0xc8
 #define ATMEL_LCDC_DMA_BURST_LEN	8
 
-#if defined(CONFIG_ARCH_AT91SAM9263)
+#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
 #define ATMEL_LCDC_FIFO_SIZE		2048
 #else
 #define ATMEL_LCDC_FIFO_SIZE		512
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 74d11c3..c8e7427 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -224,7 +224,8 @@
 	set_dma_config(CH_EPPI0,
 		       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
 					   INTR_DISABLE, DIMENSION_2D,
-					   DATA_SIZE_32));
+					   DATA_SIZE_32,
+					   DMA_NOSYNC_KEEP_DMA_BUF));
 	set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
 	set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
 	set_dma_y_count(CH_EPPI0, LCD_Y_RES);
@@ -263,8 +264,7 @@
 		}
 	}
 
-	gpio_direction_output(disp);
-	gpio_set_value(disp, 1);
+	gpio_direction_output(disp, 1);
 
 	return 0;
 }
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 49cd53e..0cd58f8 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -1232,7 +1232,7 @@
 	return 0;
 }
 
-static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
 static struct i2c_driver maven_driver;
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index c604d93..31e9783 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -21,9 +21,9 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/arch/gpio.h>
-#include <asm/arch/tps65010.h>
 #include <asm/arch/omapfb.h>
 
 #define MODULE_NAME	"omapfb-lcd_h3"
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index d93eb62..0fd5820 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -29,7 +29,7 @@
  * However, the chip cannot be detected without doing an i2c write,
  * so use the force module parameter.
  */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /**
  * Insmod parameters
diff --git a/fs/Kconfig b/fs/Kconfig
index b6df18f..9656139 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1899,13 +1899,15 @@
 	  file servers such as Windows 2000 (including Windows 2003, NT 4  
 	  and Windows XP) as well by Samba (which provides excellent CIFS
 	  server support for Linux and many other operating systems). Limited
-	  support for OS/2 and Windows ME and similar servers is provided as well.
+	  support for OS/2 and Windows ME and similar servers is provided as
+	  well.
 
-	  The intent of the cifs module is to provide an advanced
-	  network file system client for mounting to CIFS compliant servers,
-	  including support for dfs (hierarchical name space), secure per-user
-	  session establishment, safe distributed caching (oplock), optional
-	  packet signing, Unicode and other internationalization improvements. 
+	  The cifs module provides an advanced network file system
+	  client for mounting to CIFS compliant servers.  It includes
+	  support for DFS (hierarchical name space), secure per-user
+	  session establishment via Kerberos or NTLM or NTLMv2,
+	  safe distributed caching (oplock), optional packet
+	  signing, Unicode and other internationalization improvements.
 	  If you need to mount to Samba or Windows from this machine, say Y.
 
 config CIFS_STATS
@@ -1937,7 +1939,8 @@
 	  (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
 	  security mechanisms. These hash the password more securely
 	  than the mechanisms used in the older LANMAN version of the
-          SMB protocol needed to establish sessions with old SMB servers.
+	  SMB protocol but LANMAN based authentication is needed to
+	  establish sessions with some old SMB servers.
 
 	  Enabling this option allows the cifs module to mount to older
 	  LANMAN based servers such as OS/2 and Windows 95, but such
@@ -1945,8 +1948,8 @@
 	  security mechanisms if you are on a public network.  Unless you
 	  have a need to access old SMB servers (and are on a private 
 	  network) you probably want to say N.  Even if this support
-	  is enabled in the kernel build, they will not be used
-	  automatically. At runtime LANMAN mounts are disabled but
+	  is enabled in the kernel build, LANMAN authentication will not be
+	  used automatically. At runtime LANMAN mounts are disabled but
 	  can be set to required (or optional) either in
 	  /proc/fs/cifs (see fs/cifs/README for more detail) or via an
 	  option on the mount command. This support is disabled by 
@@ -2012,12 +2015,22 @@
 	  depends on CIFS_EXPERIMENTAL
 	  depends on KEYS
 	  help
-	    Enables an upcall mechanism for CIFS which will be used to contact
-	    userspace helper utilities to provide SPNEGO packaged Kerberos
-	    tickets which are needed to mount to certain secure servers
+	    Enables an upcall mechanism for CIFS which accesses
+	    userspace helper utilities to provide SPNEGO packaged (RFC 4178)
+	    Kerberos tickets which are needed to mount to certain secure servers
 	    (for which more secure Kerberos authentication is required). If
 	    unsure, say N.
 
+config CIFS_DFS_UPCALL
+	  bool "DFS feature support (EXPERIMENTAL)"
+	  depends on CIFS_EXPERIMENTAL
+	  depends on KEYS
+	  help
+	    Enables an upcall mechanism for CIFS which contacts userspace
+	    helper utilities to provide server name resolution (host names to
+	    IP addresses) which is needed for implicit mounts of DFS junction
+	    points. If unsure, say N.
+
 config NCP_FS
 	tristate "NCP file system support (to mount NetWare volumes)"
 	depends on IPX!=n || INET
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index a609599..edd2483 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,10 @@
 Fix oops on second mount to server when null auth is used.
 Enable experimental Kerberos support.  Return writebehind errors on flush
 and sync so that events like out of disk space get reported properly on
-cached files.
+cached files. Fix setxattr failure to certain Samba versions. Fix mount
+of second share to disconnected server session (autoreconnect on this).
+Add ability to modify cifs acls for handling chmod (when mounted with
+cifsacl flag).
 
 Version 1.51
 ------------
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 45e42fb..6ba43fb 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -9,3 +9,5 @@
 	  readdir.o ioctl.o sess.o export.o cifsacl.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
+
+cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
diff --git a/fs/cifs/README b/fs/cifs/README
index bf11329..c623e2f 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -56,7 +56,8 @@
 similar files reside (usually /sbin).  Although the helper software is not  
 required, mount.cifs is recommended.  Eventually the Samba 3.0 utility program 
 "net" may also be helpful since it may someday provide easier mount syntax for
-users who are used to Windows e.g.  net use <mount point> <UNC name or cifs URL>
+users who are used to Windows e.g.
+	net use <mount point> <UNC name or cifs URL>
 Note that running the Winbind pam/nss module (logon service) on all of your
 Linux clients is useful in mapping Uids and Gids consistently across the
 domain to the proper network user.  The mount.cifs mount helper can be
@@ -248,7 +249,7 @@
 		the CIFS session.
   password	The user password.  If the mount helper is
 		installed, the user will be prompted for password
-		if it is not supplied.
+		if not supplied.
   ip		The ip address of the target server
   unc		The target server Universal Network Name (export) to 
 		mount.	
@@ -283,7 +284,7 @@
 		can be enabled by specifying file_mode and dir_mode on 
 		the client.  Note that the mount.cifs helper must be
 		at version 1.10 or higher to support specifying the uid
-		(or gid) in non-numberic form.
+		(or gid) in non-numeric form.
   gid		Set the default gid for inodes (similar to above).
   file_mode     If CIFS Unix extensions are not supported by the server
 		this overrides the default mode for file inodes.
@@ -417,9 +418,10 @@
   acl   	Allow setfacl and getfacl to manage posix ACLs if server
 		supports them.  (default)
   noacl 	Do not allow setfacl and getfacl calls on this mount
-  user_xattr    Allow getting and setting user xattrs as OS/2 EAs (extended
-		attributes) to the server (default) e.g. via setfattr 
-		and getfattr utilities. 
+  user_xattr    Allow getting and setting user xattrs (those attributes whose
+		name begins with "user." or "os2.") as OS/2 EAs (extended
+		attributes) to the server.  This allows support of the
+		setfattr and getfattr utilities. (default)
   nouser_xattr  Do not allow getfattr/setfattr to get/set/list xattrs 
   mapchars      Translate six of the seven reserved characters (not backslash)
 			*?<>|:
@@ -434,6 +436,7 @@
  nomapchars     Do not translate any of these seven characters (default).
  nocase         Request case insensitive path name matching (case
 		sensitive is the default if the server suports it).
+		(mount option "ignorecase" is identical to "nocase")
  posixpaths     If CIFS Unix extensions are supported, attempt to
 		negotiate posix path name support which allows certain
 		characters forbidden in typical CIFS filenames, without
@@ -485,6 +488,9 @@
 			ntlmv2i Use NTLMv2 password hashing with packet signing
 			lanman  (if configured in kernel config) use older
 				lanman hash
+hard		Retry file operations if server is not responding
+soft		Limit retries to unresponsive servers (usually only
+		one retry) before returning an error.  (default)
 
 The mount.cifs mount helper also accepts a few mount options before -o
 including:
@@ -535,8 +541,8 @@
 			must use NTLM					0x02002
 			may use NTLMv2					0x00004
 			must use NTLMv2					0x04004
-			may use Kerberos security (not implemented yet) 0x00008
-			must use Kerberos (not implemented yet)         0x08008
+			may use Kerberos security			0x00008
+			must use Kerberos				0x08008
 			may use lanman (weak) password hash  		0x00010
 			must use lanman password hash			0x10010
 			may use plaintext passwords    			0x00020
@@ -626,6 +632,6 @@
 	
 Also note that "cat /proc/fs/cifs/DebugData" will display information about 
 the active sessions and the shares that are mounted.
-Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
-but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
-LANMAN support do not require this helpr.
+Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
+on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
+LANMAN support do not require this helper.
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index a8852c2..92c9fea 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-Version 1.49 April 26, 2007
+Version 1.52 January 3, 2008
 
 A Partial List of Missing Features
 ==================================
@@ -16,16 +16,14 @@
 c) Better pam/winbind integration (e.g. to handle uid mapping
 better)
 
-d) Verify that Kerberos signing works
-
-e) Cleanup now unneeded SessSetup code in
+d) Cleanup now unneeded SessSetup code in
 fs/cifs/connect.c and add back in NTLMSSP code if any servers
 need it
 
-f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup 
-used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
-and raw NTLMSSP already. This is important when enabling
-extended security and mounting to Windows 2003 Servers
+e) ms-dfs and ms-dfs host name resolution cleanup
+
+f) fix NTLMv2 signing when two mounts with different users to same
+server.
 
 g) Directory entry caching relies on a 1 second timer, rather than 
 using FindNotify or equivalent.  - (started)
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
new file mode 100644
index 0000000..413ee23
--- /dev/null
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -0,0 +1,377 @@
+/*
+ *   Contains the CIFS DFS referral mounting routines used for handling
+ *   traversal via DFS junction point
+ *
+ *   Copyright (c) 2007 Igor Mammedov
+ *   Copyright (C) International Business Machines  Corp., 2008
+ *   Author(s): Igor Mammedov (niallain@gmail.com)
+ *		Steve French (sfrench@us.ibm.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/dcache.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/vfs.h>
+#include <linux/fs.h>
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifsfs.h"
+#include "dns_resolve.h"
+#include "cifs_debug.h"
+
+LIST_HEAD(cifs_dfs_automount_list);
+
+/*
+ * DFS functions
+*/
+
+void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
+{
+	mark_mounts_for_expiry(&cifs_dfs_automount_list);
+	mark_mounts_for_expiry(&cifs_dfs_automount_list);
+	shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
+}
+
+/**
+ * cifs_get_share_name	-	extracts share name from UNC
+ * @node_name:	pointer to UNC string
+ *
+ * Extracts sharename form full UNC.
+ * i.e. strips from UNC trailing path that is not part of share
+ * name and fixup missing '\' in the begining of DFS node refferal
+ * if neccessary.
+ * Returns pointer to share name on success or NULL on error.
+ * Caller is responsible for freeing returned string.
+ */
+static char *cifs_get_share_name(const char *node_name)
+{
+	int len;
+	char *UNC;
+	char *pSep;
+
+	len = strlen(node_name);
+	UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
+			 GFP_KERNEL);
+	if (!UNC)
+		return NULL;
+
+	/* get share name and server name */
+	if (node_name[1] != '\\') {
+		UNC[0] = '\\';
+		strncpy(UNC+1, node_name, len);
+		len++;
+		UNC[len] = 0;
+	} else {
+		strncpy(UNC, node_name, len);
+		UNC[len] = 0;
+	}
+
+	/* find server name end */
+	pSep = memchr(UNC+2, '\\', len-2);
+	if (!pSep) {
+		cERROR(1, ("%s: no server name end in node name: %s",
+			__FUNCTION__, node_name));
+		kfree(UNC);
+		return NULL;
+	}
+
+	/* find sharename end */
+	pSep++;
+	pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
+	if (!pSep) {
+		cERROR(1, ("%s:2 cant find share name in node name: %s",
+			__FUNCTION__, node_name));
+		kfree(UNC);
+		return NULL;
+	}
+	/* trim path up to sharename end
+	 *          * now we have share name in UNC */
+	*pSep = 0;
+
+	return UNC;
+}
+
+
+/**
+ * compose_mount_options	-	creates mount options for refferral
+ * @sb_mountdata:	parent/root DFS mount options (template)
+ * @ref_unc:		refferral server UNC
+ * @devname:		pointer for saving device name
+ *
+ * creates mount options for submount based on template options sb_mountdata
+ * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
+ *
+ * Returns: pointer to new mount options or ERR_PTR.
+ * Caller is responcible for freeing retunrned value if it is not error.
+ */
+static char *compose_mount_options(const char *sb_mountdata,
+				   const char *ref_unc,
+				   char **devname)
+{
+	int rc;
+	char *mountdata;
+	int md_len;
+	char *tkn_e;
+	char *srvIP = NULL;
+	char sep = ',';
+	int off, noff;
+
+	if (sb_mountdata == NULL)
+		return ERR_PTR(-EINVAL);
+
+	*devname = cifs_get_share_name(ref_unc);
+	rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
+	if (rc != 0) {
+		cERROR(1, ("%s: Failed to resolve server part of %s to IP",
+			  __FUNCTION__, *devname));
+		mountdata = ERR_PTR(rc);
+		goto compose_mount_options_out;
+	}
+	md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3;
+	mountdata = kzalloc(md_len+1, GFP_KERNEL);
+	if (mountdata == NULL) {
+		mountdata = ERR_PTR(-ENOMEM);
+		goto compose_mount_options_out;
+	}
+
+	/* copy all options except of unc,ip,prefixpath */
+	off = 0;
+	if (strncmp(sb_mountdata, "sep=", 4) == 0) {
+			sep = sb_mountdata[4];
+			strncpy(mountdata, sb_mountdata, 5);
+			off += 5;
+	}
+	while ((tkn_e = strchr(sb_mountdata+off, sep))) {
+		noff = (tkn_e - (sb_mountdata+off)) + 1;
+		if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) {
+			off += noff;
+			continue;
+		}
+		if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) {
+			off += noff;
+			continue;
+		}
+		if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) {
+			off += noff;
+			continue;
+		}
+		strncat(mountdata, sb_mountdata+off, noff);
+		off += noff;
+	}
+	strcat(mountdata, sb_mountdata+off);
+	mountdata[md_len] = '\0';
+
+	/* copy new IP and ref share name */
+	strcat(mountdata, ",ip=");
+	strcat(mountdata, srvIP);
+	strcat(mountdata, ",unc=");
+	strcat(mountdata, *devname);
+
+	/* find & copy prefixpath */
+	tkn_e = strchr(ref_unc+2, '\\');
+	if (tkn_e) {
+		tkn_e = strchr(tkn_e+1, '\\');
+		if (tkn_e) {
+			strcat(mountdata, ",prefixpath=");
+			strcat(mountdata, tkn_e);
+		}
+	}
+
+	/*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
+	/*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
+
+compose_mount_options_out:
+	kfree(srvIP);
+	return mountdata;
+}
+
+
+static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
+		struct dentry *dentry, char *ref_unc)
+{
+	struct cifs_sb_info *cifs_sb;
+	struct vfsmount *mnt;
+	char *mountdata;
+	char *devname = NULL;
+
+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
+	mountdata = compose_mount_options(cifs_sb->mountdata,
+						ref_unc, &devname);
+
+	if (IS_ERR(mountdata))
+		return (struct vfsmount *)mountdata;
+
+	mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
+	kfree(mountdata);
+	kfree(devname);
+	return mnt;
+
+}
+
+static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
+{
+	char *full_path = NULL;
+	char *search_path;
+	char *tmp_path;
+	size_t l_max_len;
+	struct cifs_sb_info *cifs_sb;
+
+	if (dentry->d_inode == NULL)
+		return NULL;
+
+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
+
+	if (cifs_sb->tcon == NULL)
+		return NULL;
+
+	search_path = build_path_from_dentry(dentry);
+	if (search_path == NULL)
+		return NULL;
+
+	if (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS) {
+		/* we should use full path name to correct working with DFS */
+		l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE+1) +
+					strnlen(search_path, MAX_PATHCONF) + 1;
+		tmp_path = kmalloc(l_max_len, GFP_KERNEL);
+		if (tmp_path == NULL) {
+			kfree(search_path);
+			return NULL;
+		}
+		strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
+		strcat(tmp_path, search_path);
+		tmp_path[l_max_len-1] = 0;
+		full_path = tmp_path;
+		kfree(search_path);
+	} else {
+		full_path = search_path;
+	}
+	return full_path;
+}
+
+static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
+				struct list_head *mntlist)
+{
+	/* stolen from afs code */
+	int err;
+
+	mntget(newmnt);
+	err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist);
+	switch (err) {
+	case 0:
+		dput(nd->dentry);
+		mntput(nd->mnt);
+		nd->mnt = newmnt;
+		nd->dentry = dget(newmnt->mnt_root);
+		break;
+	case -EBUSY:
+		/* someone else made a mount here whilst we were busy */
+		while (d_mountpoint(nd->dentry) &&
+		       follow_down(&nd->mnt, &nd->dentry))
+			;
+		err = 0;
+	default:
+		mntput(newmnt);
+		break;
+	}
+	return err;
+}
+
+static void dump_referral(const struct dfs_info3_param *ref)
+{
+	cFYI(1, ("DFS: ref path: %s", ref->path_name));
+	cFYI(1, ("DFS: node path: %s", ref->node_name));
+	cFYI(1, ("DFS: fl: %hd, srv_type: %hd", ref->flags, ref->server_type));
+	cFYI(1, ("DFS: ref_flags: %hd, path_consumed: %hd", ref->ref_flag,
+				ref->PathConsumed));
+}
+
+
+static void*
+cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+{
+	struct dfs_info3_param *referrals = NULL;
+	unsigned int num_referrals = 0;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsSesInfo *ses;
+	char *full_path = NULL;
+	int xid, i;
+	int rc = 0;
+	struct vfsmount *mnt = ERR_PTR(-ENOENT);
+
+	cFYI(1, ("in %s", __FUNCTION__));
+	BUG_ON(IS_ROOT(dentry));
+
+	xid = GetXid();
+
+	dput(nd->dentry);
+	nd->dentry = dget(dentry);
+
+	cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
+	ses = cifs_sb->tcon->ses;
+
+	if (!ses) {
+		rc = -EINVAL;
+		goto out_err;
+	}
+
+	full_path = build_full_dfs_path_from_dentry(dentry);
+	if (full_path == NULL) {
+		rc = -ENOMEM;
+		goto out_err;
+	}
+
+	rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
+		&num_referrals, &referrals,
+		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+	for (i = 0; i < num_referrals; i++) {
+		dump_referral(referrals+i);
+		/* connect to a storage node */
+		if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
+			int len;
+			len = strlen(referrals[i].node_name);
+			if (len < 2) {
+				cERROR(1, ("%s: Net Address path too short: %s",
+					__FUNCTION__, referrals[i].node_name));
+				rc = -EINVAL;
+				goto out_err;
+			}
+			mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry,
+						referrals[i].node_name);
+			cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
+					 __FUNCTION__,
+					referrals[i].node_name, mnt));
+
+			/* complete mount procedure if we accured submount */
+			if (!IS_ERR(mnt))
+				break;
+		}
+	}
+
+	/* we need it cause for() above could exit without valid submount */
+	rc = PTR_ERR(mnt);
+	if (IS_ERR(mnt))
+		goto out_err;
+
+	nd->mnt->mnt_flags |= MNT_SHRINKABLE;
+	rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
+
+out:
+	FreeXid(xid);
+	free_dfs_info_array(referrals, num_referrals);
+	kfree(full_path);
+	cFYI(1, ("leaving %s" , __FUNCTION__));
+	return ERR_PTR(rc);
+out_err:
+	path_release(nd);
+	goto out;
+}
+
+struct inode_operations cifs_dfs_referral_inode_operations = {
+	.follow_link = cifs_dfs_follow_mountpoint,
+};
+
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 34af556..8ad2330 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -43,6 +43,9 @@
 	mode_t	mnt_dir_mode;
 	int     mnt_cifs_flags;
 	int	prepathlen;
-	char   *prepath;
+	char   *prepath; /* relative path under the share to mount to */
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	char   *mountdata; /* mount options received at mount time */
+#endif
 };
 #endif				/* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 1529d2b..d543acc 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -122,11 +122,13 @@
 	cFYI(1, ("key description = %s", description));
 	spnego_key = request_key(&cifs_spnego_key_type, description, "");
 
+#ifdef CONFIG_CIFS_DEBUG2
 	if (cifsFYI && !IS_ERR(spnego_key)) {
 		struct cifs_spnego_msg *msg = spnego_key->payload.data;
-		cifs_dump_mem("SPNEGO reply blob:", msg->data,
-				msg->secblob_len + msg->sesskey_len);
+		cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024,
+				msg->secblob_len + msg->sesskey_len));
 	}
+#endif /* CONFIG_CIFS_DEBUG2 */
 
 out:
 	kfree(description);
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index c312adc..a7035bd 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -129,6 +129,54 @@
 	return (1); /* sids compare/match */
 }
 
+
+/* copy ntsd, owner sid, and group sid from a security descriptor to another */
+static void copy_sec_desc(const struct cifs_ntsd *pntsd,
+				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
+{
+	int i;
+
+	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
+	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
+
+	/* copy security descriptor control portion */
+	pnntsd->revision = pntsd->revision;
+	pnntsd->type = pntsd->type;
+	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
+	pnntsd->sacloffset = 0;
+	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
+	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
+
+	/* copy owner sid */
+	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+				le32_to_cpu(pntsd->osidoffset));
+	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
+
+	nowner_sid_ptr->revision = owner_sid_ptr->revision;
+	nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
+	for (i = 0; i < 6; i++)
+		nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
+	for (i = 0; i < 5; i++)
+		nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
+
+	/* copy group sid */
+	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+				le32_to_cpu(pntsd->gsidoffset));
+	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
+					sizeof(struct cifs_sid));
+
+	ngroup_sid_ptr->revision = group_sid_ptr->revision;
+	ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
+	for (i = 0; i < 6; i++)
+		ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
+	for (i = 0; i < 5; i++)
+		ngroup_sid_ptr->sub_auth[i] =
+				cpu_to_le32(group_sid_ptr->sub_auth[i]);
+
+	return;
+}
+
+
 /*
    change posix mode to reflect permissions
    pmode is the existing mode (we only want to overwrite part of this
@@ -220,6 +268,33 @@
 	return;
 }
 
+static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
+			const struct cifs_sid *psid, __u64 nmode, umode_t bits)
+{
+	int i;
+	__u16 size = 0;
+	__u32 access_req = 0;
+
+	pntace->type = ACCESS_ALLOWED;
+	pntace->flags = 0x0;
+	mode_to_access_flags(nmode, bits, &access_req);
+	if (!access_req)
+		access_req = SET_MINIMUM_RIGHTS;
+	pntace->access_req = cpu_to_le32(access_req);
+
+	pntace->sid.revision = psid->revision;
+	pntace->sid.num_subauth = psid->num_subauth;
+	for (i = 0; i < 6; i++)
+		pntace->sid.authority[i] = psid->authority[i];
+	for (i = 0; i < psid->num_subauth; i++)
+		pntace->sid.sub_auth[i] = psid->sub_auth[i];
+
+	size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
+	pntace->size = cpu_to_le16(size);
+
+	return (size);
+}
+
 
 #ifdef CONFIG_CIFS_DEBUG2
 static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
@@ -243,7 +318,7 @@
 		int i;
 		cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
 			pace->sid.revision, pace->sid.num_subauth, pace->type,
-			pace->flags, pace->size));
+			pace->flags, le16_to_cpu(pace->size)));
 		for (i = 0; i < num_subauth; ++i) {
 			cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
 				le32_to_cpu(pace->sid.sub_auth[i])));
@@ -346,6 +421,28 @@
 }
 
 
+static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
+			struct cifs_sid *pgrpsid, __u64 nmode)
+{
+	__le16 size = 0;
+	struct cifs_acl *pnndacl;
+
+	pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
+
+	size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
+					pownersid, nmode, S_IRWXU);
+	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
+					pgrpsid, nmode, S_IRWXG);
+	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
+					 &sid_everyone, nmode, S_IRWXO);
+
+	pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
+	pndacl->num_aces = 3;
+
+	return (0);
+}
+
+
 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 {
 	/* BB need to add parm so we can store the SID BB */
@@ -432,6 +529,46 @@
 }
 
 
+/* Convert permission bits from mode to equivalent CIFS ACL */
+static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
+				int acl_len, struct inode *inode, __u64 nmode)
+{
+	int rc = 0;
+	__u32 dacloffset;
+	__u32 ndacloffset;
+	__u32 sidsoffset;
+	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
+	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
+	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
+
+	if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
+		return (-EIO);
+
+	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+				le32_to_cpu(pntsd->osidoffset));
+	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
+				le32_to_cpu(pntsd->gsidoffset));
+
+	dacloffset = le32_to_cpu(pntsd->dacloffset);
+	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
+
+	ndacloffset = sizeof(struct cifs_ntsd);
+	ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
+	ndacl_ptr->revision = dacl_ptr->revision;
+	ndacl_ptr->size = 0;
+	ndacl_ptr->num_aces = 0;
+
+	rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
+
+	sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
+
+	/* copy security descriptor control portion and owner and group sid */
+	copy_sec_desc(pntsd, pnntsd, sidsoffset);
+
+	return (rc);
+}
+
+
 /* Retrieve an ACL from the server */
 static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
 				       const char *path)
@@ -487,6 +624,64 @@
 	return pntsd;
 }
 
+/* Set an ACL on the server */
+static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
+				struct inode *inode, const char *path)
+{
+	struct cifsFileInfo *open_file;
+	int unlock_file = FALSE;
+	int xid;
+	int rc = -EIO;
+	__u16 fid;
+	struct super_block *sb;
+	struct cifs_sb_info *cifs_sb;
+
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
+#endif
+
+	if (!inode)
+		return (rc);
+
+	sb = inode->i_sb;
+	if (sb == NULL)
+		return (rc);
+
+	cifs_sb = CIFS_SB(sb);
+	xid = GetXid();
+
+	open_file = find_readable_file(CIFS_I(inode));
+	if (open_file) {
+		unlock_file = TRUE;
+		fid = open_file->netfid;
+	} else {
+		int oplock = FALSE;
+		/* open file */
+		rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
+				WRITE_DAC, 0, &fid, &oplock, NULL,
+				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc != 0) {
+			cERROR(1, ("Unable to open file to set ACL"));
+			FreeXid(xid);
+			return (rc);
+		}
+	}
+
+	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1, ("SetCIFSACL rc = %d", rc));
+#endif
+	if (unlock_file == TRUE)
+		atomic_dec(&open_file->wrtPending);
+	else
+		CIFSSMBClose(xid, cifs_sb->tcon, fid);
+
+	FreeXid(xid);
+
+	return (rc);
+}
+
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
 void acl_to_uid_mode(struct inode *inode, const char *path)
 {
@@ -510,24 +705,53 @@
 }
 
 /* Convert mode bits to an ACL so we can update the ACL on the server */
-int mode_to_acl(struct inode *inode, const char *path)
+int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
 {
 	int rc = 0;
 	__u32 acllen = 0;
-	struct cifs_ntsd *pntsd = NULL;
+	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
+	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
 
+#ifdef CONFIG_CIFS_DEBUG2
 	cFYI(1, ("set ACL from mode for %s", path));
+#endif
 
 	/* Get the security descriptor */
 	pntsd = get_cifs_acl(&acllen, inode, path);
 
-	/* Add/Modify the three ACEs for owner, group, everyone
-	   while retaining the other ACEs */
+	/* Add three ACEs for owner, group, everyone getting rid of
+	   other ACEs as chmod disables ACEs and set the security descriptor */
 
-	/* Set the security descriptor */
+	if (pntsd) {
+		/* allocate memory for the smb header,
+		   set security descriptor request security descriptor
+		   parameters, and secuirty descriptor itself */
 
+		pnntsd = kmalloc(acllen, GFP_KERNEL);
+		if (!pnntsd) {
+			cERROR(1, ("Unable to allocate security descriptor"));
+			kfree(pntsd);
+			return (-ENOMEM);
+		}
 
-	kfree(pntsd);
-	return rc;
+		rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode);
+
+#ifdef CONFIG_CIFS_DEBUG2
+		cFYI(1, ("build_sec_desc rc: %d", rc));
+#endif
+
+		if (!rc) {
+			/* Set the security descriptor */
+			rc = set_cifs_acl(pnntsd, acllen, inode, path);
+#ifdef CONFIG_CIFS_DEBUG2
+			cFYI(1, ("set_cifs_acl rc: %d", rc));
+#endif
+		}
+
+		kfree(pnntsd);
+		kfree(pntsd);
+	}
+
+	return (rc);
 }
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 093beaa..e9f4ec7 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -44,6 +44,7 @@
 #include "cifs_fs_sb.h"
 #include <linux/mm.h>
 #include <linux/key-type.h>
+#include "dns_resolve.h"
 #include "cifs_spnego.h"
 #define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of SMB PDUs */
 
@@ -96,6 +97,9 @@
 {
 	struct inode *inode;
 	struct cifs_sb_info *cifs_sb;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	int len;
+#endif
 	int rc = 0;
 
 	/* BB should we make this contingent on mount parm? */
@@ -105,6 +109,25 @@
 	if (cifs_sb == NULL)
 		return -ENOMEM;
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	/* copy mount params to sb for use in submounts */
+	/* BB: should we move this after the mount so we
+	 * do not have to do the copy on failed mounts?
+	 * BB: May be it is better to do simple copy before
+	 * complex operation (mount), and in case of fail
+	 * just exit instead of doing mount and attempting
+	 * undo it if this copy fails?*/
+	len = strlen(data);
+	cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL);
+	if (cifs_sb->mountdata == NULL) {
+		kfree(sb->s_fs_info);
+		sb->s_fs_info = NULL;
+		return -ENOMEM;
+	}
+	strncpy(cifs_sb->mountdata, data, len + 1);
+	cifs_sb->mountdata[len] = '\0';
+#endif
+
 	rc = cifs_mount(sb, cifs_sb, data, devname);
 
 	if (rc) {
@@ -154,6 +177,12 @@
 
 out_mount_failed:
 	if (cifs_sb) {
+#ifdef CONFIG_CIFS_DFS_UPCALL
+		if (cifs_sb->mountdata) {
+			kfree(cifs_sb->mountdata);
+			cifs_sb->mountdata = NULL;
+		}
+#endif
 		if (cifs_sb->local_nls)
 			unload_nls(cifs_sb->local_nls);
 		kfree(cifs_sb);
@@ -177,6 +206,13 @@
 	if (rc) {
 		cERROR(1, ("cifs_umount failed with return code %d", rc));
 	}
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	if (cifs_sb->mountdata) {
+		kfree(cifs_sb->mountdata);
+		cifs_sb->mountdata = NULL;
+	}
+#endif
+
 	unload_nls(cifs_sb->local_nls);
 	kfree(cifs_sb);
 	return;
@@ -435,6 +471,10 @@
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *tcon;
 
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	dfs_shrink_umount_helper(vfsmnt);
+#endif /* CONFIG CIFS_DFS_UPCALL */
+
 	if (!(flags & MNT_FORCE))
 		return;
 	cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
@@ -552,7 +592,7 @@
 	return remote_llseek(file, offset, origin);
 }
 
-static struct file_system_type cifs_fs_type = {
+struct file_system_type cifs_fs_type = {
 	.owner = THIS_MODULE,
 	.name = "cifs",
 	.get_sb = cifs_get_sb,
@@ -1015,11 +1055,16 @@
 	if (rc)
 		goto out_unregister_filesystem;
 #endif
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	rc = register_key_type(&key_type_dns_resolver);
+	if (rc)
+		goto out_unregister_key_type;
+#endif
 	oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
 	if (IS_ERR(oplockThread)) {
 		rc = PTR_ERR(oplockThread);
 		cERROR(1, ("error %d create oplock thread", rc));
-		goto out_unregister_key_type;
+		goto out_unregister_dfs_key_type;
 	}
 
 	dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
@@ -1033,7 +1078,11 @@
 
  out_stop_oplock_thread:
 	kthread_stop(oplockThread);
+ out_unregister_dfs_key_type:
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	unregister_key_type(&key_type_dns_resolver);
  out_unregister_key_type:
+#endif
 #ifdef CONFIG_CIFS_UPCALL
 	unregister_key_type(&cifs_spnego_key_type);
  out_unregister_filesystem:
@@ -1059,6 +1108,9 @@
 #ifdef CONFIG_PROC_FS
 	cifs_proc_clean();
 #endif
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	unregister_key_type(&key_type_dns_resolver);
+#endif
 #ifdef CONFIG_CIFS_UPCALL
 	unregister_key_type(&cifs_spnego_key_type);
 #endif
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 2a21dc6..195b14d 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -32,6 +32,7 @@
 #define TRUE 1
 #endif
 
+extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
@@ -60,6 +61,10 @@
 
 extern const struct inode_operations cifs_file_inode_ops;
 extern const struct inode_operations cifs_symlink_inode_ops;
+extern struct list_head cifs_dfs_automount_list;
+extern struct inode_operations cifs_dfs_referral_inode_operations;
+
+
 
 /* Functions related to files and directories */
 extern const struct file_operations cifs_file_ops;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1fde219..5d32d8d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsglob.h
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Jeremy Allison (jra@samba.org)
  *
@@ -70,14 +70,6 @@
 #endif
 
 /*
- * This information is kept on every Server we know about.
- *
- * Some things to note:
- *
- */
-#define SERVER_NAME_LEN_WITH_NULL	(SERVER_NAME_LENGTH + 1)
-
-/*
  * CIFS vfs client Status information (based on what we know.)
  */
 
@@ -460,6 +452,37 @@
        struct file *pfile;
 };
 
+struct dfs_info3_param {
+	int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
+	int PathConsumed;
+	int server_type;
+	int ref_flag;
+	char *path_name;
+	char *node_name;
+};
+
+static inline void free_dfs_info_param(struct dfs_info3_param *param)
+{
+	if (param) {
+		kfree(param->path_name);
+		kfree(param->node_name);
+		kfree(param);
+	}
+}
+
+static inline void free_dfs_info_array(struct dfs_info3_param *param,
+				       int number_of_items)
+{
+	int i;
+	if ((number_of_items == 0) || (param == NULL))
+		return;
+	for (i = 0; i < number_of_items; i++) {
+		kfree(param[i].path_name);
+		kfree(param[i].node_name);
+	}
+	kfree(param);
+}
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index dbe6b84..47f7950 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -237,6 +237,9 @@
 				| DELETE | READ_CONTROL | WRITE_DAC \
 				| WRITE_OWNER | SYNCHRONIZE)
 
+#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
+				| READ_CONTROL | SYNCHRONIZE)
+
 
 /*
  * Invalid readdir handle
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8350eec..2f09f56 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2007
+ *   Copyright (c) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -97,11 +97,14 @@
 			const unsigned char *search_path,
 			struct super_block *sb, int xid);
 extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
-extern int mode_to_acl(struct inode *inode, const char *path);
+extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
 			const char *);
 extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+#ifdef CONFIG_CIFS_DFS_UPCALL
+extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
+#endif
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
@@ -153,7 +156,7 @@
 			const char *old_path,
 			const struct nls_table *nls_codepage,
 			unsigned int *pnum_referrals,
-			unsigned char **preferrals,
+			struct dfs_info3_param **preferrals,
 			int remap);
 extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 				 struct super_block *sb, struct smb_vol *vol);
@@ -342,6 +345,8 @@
 		const struct nls_table *nls_codepage, int remap_special_chars);
 extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
 			__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
+extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16,
+			struct cifs_ntsd *, __u32);
 extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
 		const unsigned char *searchName,
 		char *acl_inf, const int buflen, const int acl_type,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9e8a6be..9409524 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3156,6 +3156,71 @@
 /*	cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
 	return rc;
 }
+
+int
+CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
+			struct cifs_ntsd *pntsd, __u32 acllen)
+{
+	__u16 byte_count, param_count, data_count, param_offset, data_offset;
+	int rc = 0;
+	int bytes_returned = 0;
+	SET_SEC_DESC_REQ *pSMB = NULL;
+	NTRANSACT_RSP *pSMBr = NULL;
+
+setCifsAclRetry:
+	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
+			(void **) &pSMBr);
+	if (rc)
+			return (rc);
+
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+
+	param_count = 8;
+	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
+	data_count = acllen;
+	data_offset = param_offset + param_count;
+	byte_count = 3 /* pad */  + param_count;
+
+	pSMB->DataCount = cpu_to_le32(data_count);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->MaxParameterCount = cpu_to_le32(4);
+	pSMB->MaxDataCount = cpu_to_le32(16384);
+	pSMB->ParameterCount = cpu_to_le32(param_count);
+	pSMB->ParameterOffset = cpu_to_le32(param_offset);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->DataOffset = cpu_to_le32(data_offset);
+	pSMB->SetupCount = 0;
+	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
+	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
+
+	pSMB->Fid = fid; /* file handle always le */
+	pSMB->Reserved2 = 0;
+	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
+
+	if (pntsd && acllen) {
+		memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
+			(char *) pntsd,
+			acllen);
+		pSMB->hdr.smb_buf_length += (byte_count + data_count);
+
+	} else
+		pSMB->hdr.smb_buf_length += byte_count;
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
+	if (rc)
+		cFYI(1, ("Set CIFS ACL returned %d", rc));
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto setCifsAclRetry;
+
+	return (rc);
+}
+
 #endif /* CONFIG_CIFS_EXPERIMENTAL */
 
 /* Legacy Query Path Information call for lookup to old servers such
@@ -5499,7 +5564,7 @@
 	else
 		name_len = strnlen(ea_name, 255);
 
-	count = sizeof(*parm_data) + ea_value_len + name_len + 1;
+	count = sizeof(*parm_data) + ea_value_len + name_len;
 	pSMB->MaxParameterCount = cpu_to_le16(2);
 	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
 	pSMB->MaxSetupCount = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index fd9147c..65d0ba7 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2007
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -1410,7 +1410,7 @@
 		    const char *old_path, const struct nls_table *nls_codepage,
 		    int remap)
 {
-	unsigned char *referrals = NULL;
+	struct dfs_info3_param *referrals = NULL;
 	unsigned int num_referrals;
 	int rc = 0;
 
@@ -1429,12 +1429,14 @@
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
-	     unsigned char **preferrals, int remap)
+	     struct dfs_info3_param **preferrals, int remap)
 {
 	char *temp_unc;
 	int rc = 0;
+	unsigned char *targetUNCs;
 
 	*pnum_referrals = 0;
+	*preferrals = NULL;
 
 	if (pSesInfo->ipc_tid == 0) {
 		temp_unc = kmalloc(2 /* for slashes */ +
@@ -1454,8 +1456,10 @@
 		kfree(temp_unc);
 	}
 	if (rc == 0)
-		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
+		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
 				     pnum_referrals, nls_codepage, remap);
+	/* BB map targetUNCs to dfs_info3 structures, here or
+		in CIFSGetDFSRefer BB */
 
 	return rc;
 }
@@ -1964,7 +1968,15 @@
 
 	if (existingCifsSes) {
 		pSesInfo = existingCifsSes;
-		cFYI(1, ("Existing smb sess found"));
+		cFYI(1, ("Existing smb sess found (status=%d)",
+			pSesInfo->status));
+		down(&pSesInfo->sesSem);
+		if (pSesInfo->status == CifsNeedReconnect) {
+			cFYI(1, ("Session needs reconnect"));
+			rc = cifs_setup_session(xid, pSesInfo,
+						cifs_sb->local_nls);
+		}
+		up(&pSesInfo->sesSem);
 	} else if (!rc) {
 		cFYI(1, ("Existing smb sess not found"));
 		pSesInfo = sesInfoAlloc();
@@ -3514,7 +3526,7 @@
 		sesInfoFree(ses);
 
 	FreeXid(xid);
-	return rc;	/* BB check if we should always return zero here */
+	return rc;
 }
 
 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 37dc97a..699ec11 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -517,12 +517,10 @@
 		d_add(direntry, NULL);
 	/*	if it was once a directory (but how can we tell?) we could do
 		shrink_dcache_parent(direntry); */
-	} else {
-		cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
-			   rc, full_path));
-		/* BB special case check for Access Denied - watch security
-		exposure of returning dir info implicitly via different rc
-		if file exists or not but no access BB */
+	} else if (rc != -EACCES) {
+		cERROR(1, ("Unexpected lookup error %d", rc));
+		/* We special case check for Access Denied - since that
+		is a common return code */
 	}
 
 	kfree(full_path);
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
new file mode 100644
index 0000000..ef7f438
--- /dev/null
+++ b/fs/cifs/dns_resolve.c
@@ -0,0 +1,124 @@
+/*
+ *  fs/cifs/dns_resolve.c
+ *
+ *   Copyright (c) 2007 Igor Mammedov
+ *   Author(s): Igor Mammedov (niallain@gmail.com)
+ *              Steve French (sfrench@us.ibm.com)
+ *
+ *   Contains the CIFS DFS upcall routines used for hostname to
+ *   IP address translation.
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <keys/user-type.h>
+#include "dns_resolve.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+static int dns_resolver_instantiate(struct key *key, const void *data,
+		size_t datalen)
+{
+	int rc = 0;
+	char *ip;
+
+	ip = kmalloc(datalen+1, GFP_KERNEL);
+	if (!ip)
+		return -ENOMEM;
+
+	memcpy(ip, data, datalen);
+	ip[datalen] = '\0';
+
+	rcu_assign_pointer(key->payload.data, ip);
+
+	return rc;
+}
+
+struct key_type key_type_dns_resolver = {
+	.name        = "dns_resolver",
+	.def_datalen = sizeof(struct in_addr),
+	.describe    = user_describe,
+	.instantiate = dns_resolver_instantiate,
+	.match       = user_match,
+};
+
+
+/* Resolves server name to ip address.
+ * input:
+ * 	unc - server UNC
+ * output:
+ * 	*ip_addr - pointer to server ip, caller responcible for freeing it.
+ * return 0 on success
+ */
+int
+dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
+{
+	int rc = -EAGAIN;
+	struct key *rkey;
+	char *name;
+	int len;
+
+	if (!ip_addr || !unc)
+		return -EINVAL;
+
+	/* search for server name delimiter */
+	len = strlen(unc);
+	if (len < 3) {
+		cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
+		return -EINVAL;
+	}
+	len -= 2;
+	name = memchr(unc+2, '\\', len);
+	if (!name) {
+		cFYI(1, ("%s: probably server name is whole unc: %s",
+					__FUNCTION__, unc));
+	} else {
+		len = (name - unc) - 2/* leading // */;
+	}
+
+	name = kmalloc(len+1, GFP_KERNEL);
+	if (!name) {
+		rc = -ENOMEM;
+		return rc;
+	}
+	memcpy(name, unc+2, len);
+	name[len] = 0;
+
+	rkey = request_key(&key_type_dns_resolver, name, "");
+	if (!IS_ERR(rkey)) {
+		len = strlen(rkey->payload.data);
+		*ip_addr = kmalloc(len+1, GFP_KERNEL);
+		if (*ip_addr) {
+			memcpy(*ip_addr, rkey->payload.data, len);
+			(*ip_addr)[len] = '\0';
+			cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
+					rkey->description,
+					*ip_addr
+				));
+			rc = 0;
+		} else {
+			rc = -ENOMEM;
+		}
+		key_put(rkey);
+	} else {
+		cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
+	}
+
+	kfree(name);
+	return rc;
+}
+
+
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
new file mode 100644
index 0000000..073fdc3
--- /dev/null
+++ b/fs/cifs/dns_resolve.h
@@ -0,0 +1,32 @@
+/*
+ *   fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS
+ *                            Handles host name to IP address resolution
+ * 
+ *   Copyright (c) International Business Machines  Corp., 2008
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _DNS_RESOLVE_H
+#define _DNS_RESOLVE_H
+
+#ifdef __KERNEL__
+#include <linux/key-type.h>
+extern struct key_type key_type_dns_resolver;
+extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
+#endif /* KERNEL */
+
+#endif /* _DNS_RESOLVE_H */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index dd26e27..5f7c374 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1179,12 +1179,10 @@
 		atomic_dec(&open_file->wrtPending);
 		/* Does mm or vfs already set times? */
 		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
-		if ((bytes_written > 0) && (offset)) {
+		if ((bytes_written > 0) && (offset))
 			rc = 0;
-		} else if (bytes_written < 0) {
-			if (rc != -EBADF)
-				rc = bytes_written;
-		}
+		else if (bytes_written < 0)
+			rc = bytes_written;
 	} else {
 		cFYI(1, ("No writeable filehandles for inode"));
 		rc = -EIO;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e915eb1..d9567ba 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -54,9 +54,9 @@
 					    MAX_TREE_SIZE + 1) +
 				    strnlen(search_path, MAX_PATHCONF) + 1,
 				    GFP_KERNEL);
-			if (tmp_path == NULL) {
+			if (tmp_path == NULL)
 				return -ENOMEM;
-			}
+
 			/* have to skip first of the double backslash of
 			   UNC name */
 			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
@@ -511,7 +511,8 @@
 		}
 
 		spin_lock(&inode->i_lock);
-		if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
+		if (is_size_safe_to_change(cifsInfo,
+					   le64_to_cpu(pfindData->EndOfFile))) {
 			/* can not safely shrink the file size here if the
 			   client is writing to it due to potential races */
 			i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
@@ -931,7 +932,7 @@
 		(CIFS_UNIX_POSIX_PATH_OPS_CAP &
 			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
 		u32 oplock = 0;
-		FILE_UNIX_BASIC_INFO * pInfo =
+		FILE_UNIX_BASIC_INFO *pInfo =
 			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
 		if (pInfo == NULL) {
 			rc = -ENOMEM;
@@ -1607,7 +1608,14 @@
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 	else if (attrs->ia_valid & ATTR_MODE) {
 		rc = 0;
-		if ((mode & S_IWUGO) == 0) /* not writeable */ {
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+			rc = mode_to_acl(direntry->d_inode, full_path, mode);
+		else if ((mode & S_IWUGO) == 0) {
+#else
+		if ((mode & S_IWUGO) == 0) {
+#endif
+			/* not writeable */
 			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
 				set_dosattr = TRUE;
 				time_buf.Attributes =
@@ -1626,10 +1634,10 @@
 			if (time_buf.Attributes == 0)
 				time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
 		}
-		/* BB to be implemented -
-		   via Windows security descriptors or streams */
-		/* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
-				      cifs_sb->local_nls); */
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
+			mode_to_acl(direntry->d_inode, full_path, mode);
+#endif
 	}
 
 	if (attrs->ia_valid & ATTR_ATIME) {
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 11f2657..1d6fb01 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/link.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2003
+ *   Copyright (C) International Business Machines  Corp., 2002,2008
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -236,8 +236,6 @@
 	char *full_path = NULL;
 	char *tmp_path = NULL;
 	char *tmpbuffer;
-	unsigned char *referrals = NULL;
-	unsigned int num_referrals = 0;
 	int len;
 	__u16 fid;
 
@@ -297,8 +295,11 @@
 				cFYI(1, ("Error closing junction point "
 					 "(open for ioctl)"));
 			}
+			/* BB unwind this long, nested function, or remove BB */
 			if (rc == -EIO) {
 				/* Query if DFS Junction */
+				unsigned int num_referrals = 0;
+				struct dfs_info3_param *refs = NULL;
 				tmp_path =
 					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
 						GFP_KERNEL);
@@ -310,7 +311,7 @@
 					rc = get_dfs_path(xid, pTcon->ses,
 						tmp_path,
 						cifs_sb->local_nls,
-						&num_referrals, &referrals,
+						&num_referrals, &refs,
 						cifs_sb->mnt_cifs_flags &
 						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 					cFYI(1, ("Get DFS for %s rc = %d ",
@@ -320,14 +321,13 @@
 					else {
 						cFYI(1, ("num referral: %d",
 							num_referrals));
-						if (referrals) {
-							cFYI(1,("referral string: %s", referrals));
+						if (refs && refs->path_name) {
 							strncpy(tmpbuffer,
-								referrals,
+								refs->path_name,
 								len-1);
 						}
 					}
-					kfree(referrals);
+					kfree(refs);
 					kfree(tmp_path);
 }
 				/* BB add code like else decode referrals
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index d0cb469..d2153ab 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -528,9 +528,11 @@
 			rc = -EOVERFLOW;
 			goto ssetup_exit;
 		}
-		ses->server->mac_signing_key.len = msg->sesskey_len;
-		memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
-			msg->sesskey_len);
+		if (first_time) {
+			ses->server->mac_signing_key.len = msg->sesskey_len;
+			memcpy(ses->server->mac_signing_key.data.krb5,
+				msg->data, msg->sesskey_len);
+		}
 		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 		capabilities |= CAP_EXTENDED_SECURITY;
 		pSMB->req.Capabilities = cpu_to_le32(capabilities);
@@ -540,7 +542,7 @@
 
 		if (ses->capabilities & CAP_UNICODE) {
 			/* unicode strings must be word aligned */
-			if (iov[0].iov_len % 2) {
+			if ((iov[0].iov_len + iov[1].iov_len) % 2) {
 				*bcc_ptr = 0;
 				bcc_ptr++;
 			}
diff --git a/include/asm-arm/arch-at91/at91_lcdc.h b/include/asm-arm/arch-at91/at91_lcdc.h
deleted file mode 100644
index ab040a4..0000000
--- a/include/asm-arm/arch-at91/at91_lcdc.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * include/asm-arm/arch-at91/at91_lcdc.h
- *
- * LCD Controller (LCDC).
- * Based on AT91SAM9261 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_LCDC_H
-#define AT91_LCDC_H
-
-#define AT91_LCDC_DMABADDR1	0x00		/* DMA Base Address Register 1 */
-#define AT91_LCDC_DMABADDR2	0x04		/* DMA Base Address Register 2 */
-#define AT91_LCDC_DMAFRMPT1	0x08		/* DMA Frame Pointer Register 1 */
-#define AT91_LCDC_DMAFRMPT2	0x0c		/* DMA Frame Pointer Register 2 */
-#define AT91_LCDC_DMAFRMADD1	0x10		/* DMA Frame Address Register 1 */
-#define AT91_LCDC_DMAFRMADD2	0x14		/* DMA Frame Address Register 2 */
-
-#define AT91_LCDC_DMAFRMCFG	0x18		/* DMA Frame Configuration Register */
-#define		AT91_LCDC_FRSIZE	(0x7fffff <<  0)	/* Frame Size */
-#define		AT91_LCDC_BLENGTH	(0x7f     << 24)	/* Burst Length */
-
-#define AT91_LCDC_DMACON	0x1c		/* DMA Control Register */
-#define		AT91_LCDC_DMAEN		(0x1 << 0)	/* DMA Enable */
-#define		AT91_LCDC_DMARST	(0x1 << 1)	/* DMA Reset */
-#define		AT91_LCDC_DMABUSY	(0x1 << 2)	/* DMA Busy */
-
-#define AT91_LCDC_LCDCON1	0x0800		/* LCD Control Register 1 */
-#define		AT91_LCDC_BYPASS	(1     <<  0)	/* Bypass lcd_dotck divider */
-#define		AT91_LCDC_CLKVAL	(0x1ff << 12)	/* Clock Divider */
-#define		AT91_LCDC_LINCNT	(0x7ff << 21)	/* Line Counter */
-
-#define AT91_LCDC_LCDCON2	0x0804		/* LCD Control Register 2 */
-#define		AT91_LCDC_DISTYPE	(3 << 0)	/* Display Type */
-#define			AT91_LCDC_DISTYPE_STNMONO	(0 << 0)
-#define			AT91_LCDC_DISTYPE_STNCOLOR	(1 << 0)
-#define			AT91_LCDC_DISTYPE_TFT		(2 << 0)
-#define		AT91_LCDC_SCANMOD	(1 << 2)	/* Scan Mode */
-#define			AT91_LCDC_SCANMOD_SINGLE	(0 << 2)
-#define			AT91_LCDC_SCANMOD_DUAL		(1 << 2)
-#define		AT91_LCDC_IFWIDTH	(3 << 3)	/*Interface Width */
-#define			AT91_LCDC_IFWIDTH_4		(0 << 3)
-#define			AT91_LCDC_IFWIDTH_8		(1 << 3)
-#define			AT91_LCDC_IFWIDTH_16		(2 << 3)
-#define		AT91_LCDC_PIXELSIZE	(7 << 5)	/* Bits per pixel */
-#define			AT91_LCDC_PIXELSIZE_1		(0 << 5)
-#define			AT91_LCDC_PIXELSIZE_2		(1 << 5)
-#define			AT91_LCDC_PIXELSIZE_4		(2 << 5)
-#define			AT91_LCDC_PIXELSIZE_8		(3 << 5)
-#define			AT91_LCDC_PIXELSIZE_16		(4 << 5)
-#define			AT91_LCDC_PIXELSIZE_24		(5 << 5)
-#define		AT91_LCDC_INVVD		(1 << 8)	/* LCD Data polarity */
-#define			AT91_LCDC_INVVD_NORMAL		(0 << 8)
-#define			AT91_LCDC_INVVD_INVERTED	(1 << 8)
-#define		AT91_LCDC_INVFRAME	(1 << 9 )	/* LCD VSync polarity */
-#define			AT91_LCDC_INVFRAME_NORMAL	(0 << 9)
-#define			AT91_LCDC_INVFRAME_INVERTED	(1 << 9)
-#define		AT91_LCDC_INVLINE	(1 << 10)	/* LCD HSync polarity */
-#define			AT91_LCDC_INVLINE_NORMAL	(0 << 10)
-#define			AT91_LCDC_INVLINE_INVERTED	(1 << 10)
-#define		AT91_LCDC_INVCLK	(1 << 11)	/* LCD dotclk polarity */
-#define			AT91_LCDC_INVCLK_NORMAL		(0 << 11)
-#define			AT91_LCDC_INVCLK_INVERTED	(1 << 11)
-#define		AT91_LCDC_INVDVAL	(1 << 12)	/* LCD dval polarity */
-#define			AT91_LCDC_INVDVAL_NORMAL	(0 << 12)
-#define			AT91_LCDC_INVDVAL_INVERTED	(1 << 12)
-#define		AT91_LCDC_CLKMOD	(1 << 15)	/* LCD dotclk mode */
-#define			AT91_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
-#define			AT91_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
-#define		AT91_LCDC_MEMOR		(1 << 31)	/* Memory Ordering Format */
-#define			AT91_LCDC_MEMOR_BIG		(0 << 31)
-#define			AT91_LCDC_MEMOR_LITTLE		(1 << 31)
-
-#define AT91_LCDC_TIM1		0x0808		/* LCD Timing Register 1 */
-#define		AT91_LCDC_VFP		(0xff <<  0)	/* Vertical Front Porch */
-#define		AT91_LCDC_VBP		(0xff <<  8)	/* Vertical Back Porch */
-#define		AT91_LCDC_VPW		(0x3f << 16)	/* Vertical Synchronization Pulse Width */
-#define		AT91_LCDC_VHDLY		(0xf  << 24)	/* Vertical to Horizontal Delay */
-
-#define AT91_LCDC_TIM2		0x080c		/* LCD Timing Register 2 */
-#define		AT91_LCDC_HBP		(0xff  <<  0)	/* Horizontal Back Porch */
-#define		AT91_LCDC_HPW		(0x3f  <<  8)	/* Horizontal Synchronization Pulse Width */
-#define		AT91_LCDC_HFP		(0x7ff << 21)	/* Horizontal Front Porch */
-
-#define AT91_LCDC_LCDFRMCFG	0x0810		/* LCD Frame Configuration Register */
-#define		AT91_LCDC_LINEVAL	(0x7ff <<  0)	/* Vertical Size of LCD Module */
-#define		AT91_LCDC_HOZVAL	(0x7ff << 21)	/* Horizontal Size of LCD Module */
-
-#define AT91_LCDC_FIFO		0x0814		/* LCD FIFO Register */
-#define		AT91_LCDC_FIFOTH	(0xffff)	/* FIFO Threshold */
-
-#define AT91_LCDC_DP1_2		0x081c		/* Dithering Pattern DP1_2 Register */
-#define AT91_LCDC_DP4_7		0x0820		/* Dithering Pattern DP4_7 Register */
-#define AT91_LCDC_DP3_5		0x0824		/* Dithering Pattern DP3_5 Register */
-#define AT91_LCDC_DP2_3		0x0828		/* Dithering Pattern DP2_3 Register */
-#define AT91_LCDC_DP5_7		0x082c		/* Dithering Pattern DP5_7 Register */
-#define AT91_LCDC_DP3_4		0x0830		/* Dithering Pattern DP3_4 Register */
-#define AT91_LCDC_DP4_5		0x0834		/* Dithering Pattern DP4_5 Register */
-#define AT91_LCDC_DP6_7		0x0838		/* Dithering Pattern DP6_7 Register */
-#define		AT91_LCDC_DP1_2_VAL	(0xff)
-#define		AT91_LCDC_DP4_7_VAL	(0xfffffff)
-#define		AT91_LCDC_DP3_5_VAL	(0xfffff)
-#define		AT91_LCDC_DP2_3_VAL	(0xfff)
-#define		AT91_LCDC_DP5_7_VAL	(0xfffffff)
-#define		AT91_LCDC_DP3_4_VAL	(0xffff)
-#define		AT91_LCDC_DP4_5_VAL	(0xfffff)
-#define		AT91_LCDC_DP6_7_VAL	(0xfffffff)
-
-#define AT91_LCDC_PWRCON	0x083c		/* Power Control Register */
-#define		AT91_LCDC_PWR		(1    <<  0)	/* LCD Module Power Control */
-#define		AT91_LCDC_GUARDT	(0x7f <<  1)	/* Delay in Frame Period */
-#define		AT91_LCDC_BUSY		(1    << 31)	/* LCD Busy */
-
-#define AT91_LCDC_CONTRAST_CTR	0x0840		/* Contrast Control Register */
-#define		AT91_LCDC_PS		(3 << 0)	/* Contrast Counter Prescaler */
-#define			AT91_LCDC_PS_DIV1		(0 << 0)
-#define			AT91_LCDC_PS_DIV2		(1 << 0)
-#define			AT91_LCDC_PS_DIV4		(2 << 0)
-#define			AT91_LCDC_PS_DIV8		(3 << 0)
-#define		AT91_LCDC_POL		(1 << 2)	/* Polarity of output Pulse */
-#define			AT91_LCDC_POL_NEGATIVE		(0 << 2)
-#define			AT91_LCDC_POL_POSITIVE		(1 << 2)
-#define		AT91_LCDC_ENA		(1 << 3)	/* PWM generator Control */
-#define			AT91_LCDC_ENA_PWMDISABLE	(0 << 3)
-#define			AT91_LCDC_ENA_PWMENABLE		(1 << 3)
-
-#define AT91_LCDC_CONTRAST_VAL	0x0844		/* Contrast Value Register */
-#define		AT91_LCDC_CVAL		(0xff)		/* PWM compare value */
-
-#define AT91_LCDC_IER		0x0848		/* Interrupt Enable Register */
-#define AT91_LCDC_IDR		0x084c		/* Interrupt Disable Register */
-#define AT91_LCDC_IMR		0x0850		/* Interrupt Mask Register */
-#define AT91_LCDC_ISR		0x0854		/* Interrupt Enable Register */
-#define AT91_LCDC_ICR		0x0858		/* Interrupt Clear Register */
-#define		AT91_LCDC_LNI		(1 << 0)	/* Line Interrupt */
-#define		AT91_LCDC_LSTLNI	(1 << 1)	/* Last Line Interrupt */
-#define		AT91_LCDC_EOFI		(1 << 2)	/* DMA End Of Frame Interrupt */
-#define		AT91_LCDC_UFLWI		(1 << 4)	/* FIFO Underflow Interrupt */
-#define		AT91_LCDC_OWRI		(1 << 5)	/* FIFO Overwrite Interrupt */
-#define		AT91_LCDC_MERI		(1 << 6)	/* DMA Memory Error Interrupt */
-
-#define AT91_LCDC_LUT_(n)	(0x0c00 + ((n)*4))	/* Palette Entry 0..255 */
-
-#endif
diff --git a/include/asm-arm/arch-at91/at91_pmc.h b/include/asm-arm/arch-at91/at91_pmc.h
index 33ff5b6..52cd8e5 100644
--- a/include/asm-arm/arch-at91/at91_pmc.h
+++ b/include/asm-arm/arch-at91/at91_pmc.h
@@ -25,6 +25,7 @@
 #define		AT91RM9200_PMC_MCKUDP	(1 <<  2)		/* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
 #define		AT91RM9200_PMC_UHP	(1 <<  4)		/* USB Host Port Clock [AT91RM9200 only] */
 #define		AT91SAM926x_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91SAM926x only] */
+#define		AT91CAP9_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91CAP9 only] */
 #define		AT91SAM926x_PMC_UDP	(1 <<  7)		/* USB Devcice Port Clock [AT91SAM926x only] */
 #define		AT91_PMC_PCK0		(1 <<  8)		/* Programmable Clock 0 */
 #define		AT91_PMC_PCK1		(1 <<  9)		/* Programmable Clock 1 */
@@ -37,7 +38,9 @@
 #define	AT91_PMC_PCDR		(AT91_PMC + 0x14)	/* Peripheral Clock Disable Register */
 #define	AT91_PMC_PCSR		(AT91_PMC + 0x18)	/* Peripheral Clock Status Register */
 
-#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register */
+#define	AT91_CKGR_UCKR		(AT91_PMC + 0x1C)	/* UTMI Clock Register [SAM9RL, CAP9] */
+
+#define	AT91_CKGR_MOR		(AT91_PMC + 0x20)	/* Main Oscillator Register [not on SAM9RL] */
 #define		AT91_PMC_MOSCEN		(1    << 0)		/* Main Oscillator Enable */
 #define		AT91_PMC_OSCBYPASS	(1    << 1)		/* Oscillator Bypass [AT91SAM926x only] */
 #define		AT91_PMC_OSCOUNT	(0xff << 8)		/* Main Oscillator Start-up Time */
@@ -52,6 +55,10 @@
 #define		AT91_PMC_PLLCOUNT	(0x3f  <<  8)		/* PLL Counter */
 #define		AT91_PMC_OUT		(3     << 14)		/* PLL Clock Frequency Range */
 #define		AT91_PMC_MUL		(0x7ff << 16)		/* PLL Multiplier */
+#define		AT91_PMC_USBDIV		(3     << 28)		/* USB Divisor (PLLB only) */
+#define			AT91_PMC_USBDIV_1		(0 << 28)
+#define			AT91_PMC_USBDIV_2		(1 << 28)
+#define			AT91_PMC_USBDIV_4		(2 << 28)
 #define		AT91_PMC_USB96M		(1     << 28)		/* Divider by 2 Enable (PLLB only) */
 
 #define	AT91_PMC_MCKR		(AT91_PMC + 0x30)	/* Master Clock Register */
diff --git a/include/asm-arm/arch-at91/at91_rtt.h b/include/asm-arm/arch-at91/at91_rtt.h
index bae1103..39a3263 100644
--- a/include/asm-arm/arch-at91/at91_rtt.h
+++ b/include/asm-arm/arch-at91/at91_rtt.h
@@ -13,19 +13,19 @@
 #ifndef AT91_RTT_H
 #define AT91_RTT_H
 
-#define AT91_RTT_MR		(AT91_RTT + 0x00)	/* Real-time Mode Register */
+#define AT91_RTT_MR		0x00			/* Real-time Mode Register */
 #define		AT91_RTT_RTPRES		(0xffff << 0)		/* Real-time Timer Prescaler Value */
 #define		AT91_RTT_ALMIEN		(1 << 16)		/* Alarm Interrupt Enable */
 #define		AT91_RTT_RTTINCIEN	(1 << 17)		/* Real Time Timer Increment Interrupt Enable */
 #define		AT91_RTT_RTTRST		(1 << 18)		/* Real Time Timer Restart */
 
-#define AT91_RTT_AR		(AT91_RTT + 0x04)	/* Real-time Alarm Register */
+#define AT91_RTT_AR		0x04			/* Real-time Alarm Register */
 #define		AT91_RTT_ALMV		(0xffffffff)		/* Alarm Value */
 
-#define AT91_RTT_VR		(AT91_RTT + 0x08)	/* Real-time Value Register */
+#define AT91_RTT_VR		0x08			/* Real-time Value Register */
 #define		AT91_RTT_CRTV		(0xffffffff)		/* Current Real-time Value */
 
-#define AT91_RTT_SR		(AT91_RTT + 0x0c)	/* Real-time Status Register */
+#define AT91_RTT_SR		0x0c			/* Real-time Status Register */
 #define		AT91_RTT_ALMS		(1 << 0)		/* Real-time Alarm Status */
 #define		AT91_RTT_RTTINC		(1 << 1)		/* Real-time Timer Increment */
 
diff --git a/include/asm-arm/arch-at91/at91_twi.h b/include/asm-arm/arch-at91/at91_twi.h
index ca9a907..f9f2e3c 100644
--- a/include/asm-arm/arch-at91/at91_twi.h
+++ b/include/asm-arm/arch-at91/at91_twi.h
@@ -21,6 +21,8 @@
 #define		AT91_TWI_STOP		(1 <<  1)	/* Send a Stop Condition */
 #define		AT91_TWI_MSEN		(1 <<  2)	/* Master Transfer Enable */
 #define		AT91_TWI_MSDIS		(1 <<  3)	/* Master Transfer Disable */
+#define		AT91_TWI_SVEN		(1 <<  4)	/* Slave Transfer Enable [SAM9260 only] */
+#define		AT91_TWI_SVDIS		(1 <<  5)	/* Slave Transfer Disable [SAM9260 only] */
 #define		AT91_TWI_SWRST		(1 <<  7)	/* Software Reset */
 
 #define	AT91_TWI_MMR		0x04		/* Master Mode Register */
@@ -32,6 +34,9 @@
 #define		AT91_TWI_MREAD		(1    << 12)	/* Master Read Direction */
 #define		AT91_TWI_DADR		(0x7f << 16)	/* Device Address */
 
+#define	AT91_TWI_SMR		0x08		/* Slave Mode Register [SAM9260 only] */
+#define		AT91_TWI_SADR		(0x7f << 16)	/* Slave Address */
+
 #define	AT91_TWI_IADR		0x0c		/* Internal Address Register */
 
 #define	AT91_TWI_CWGR		0x10		/* Clock Waveform Generator Register */
@@ -43,9 +48,15 @@
 #define		AT91_TWI_TXCOMP		(1 <<  0)	/* Transmission Complete */
 #define		AT91_TWI_RXRDY		(1 <<  1)	/* Receive Holding Register Ready */
 #define		AT91_TWI_TXRDY		(1 <<  2)	/* Transmit Holding Register Ready */
+#define		AT91_TWI_SVREAD		(1 <<  3)	/* Slave Read [SAM9260 only] */
+#define		AT91_TWI_SVACC		(1 <<  4)	/* Slave Access [SAM9260 only] */
+#define		AT91_TWI_GACC		(1 <<  5)	/* General Call Access [SAM9260 only] */
 #define		AT91_TWI_OVRE		(1 <<  6)	/* Overrun Error [AT91RM9200 only] */
 #define		AT91_TWI_UNRE		(1 <<  7)	/* Underrun Error [AT91RM9200 only] */
 #define		AT91_TWI_NACK		(1 <<  8)	/* Not Acknowledged */
+#define		AT91_TWI_ARBLST		(1 <<  9)	/* Arbitration Lost [SAM9260 only] */
+#define		AT91_TWI_SCLWS		(1 << 10)	/* Clock Wait State [SAM9260 only] */
+#define		AT91_TWI_EOSACC		(1 << 11)	/* End of Slave Address [SAM9260 only] */
 
 #define	AT91_TWI_IER		0x24		/* Interrupt Enable Register */
 #define	AT91_TWI_IDR		0x28		/* Interrupt Disable Register */
diff --git a/include/asm-arm/arch-at91/at91cap9.h b/include/asm-arm/arch-at91/at91cap9.h
new file mode 100644
index 0000000..73e1fcf
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91cap9.h
@@ -0,0 +1,121 @@
+/*
+ * include/asm-arm/arch-at91/at91cap9.h
+ *
+ *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
+ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91CAP9 datasheet revision B (Preliminary).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91CAP9_H
+#define AT91CAP9_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ		0	/* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS		1	/* System Peripherals */
+#define AT91CAP9_ID_PIOABCD	2	/* Parallel IO Controller A, B, C and D */
+#define AT91CAP9_ID_MPB0	3	/* MP Block Peripheral 0 */
+#define AT91CAP9_ID_MPB1	4	/* MP Block Peripheral 1 */
+#define AT91CAP9_ID_MPB2	5	/* MP Block Peripheral 2 */
+#define AT91CAP9_ID_MPB3	6	/* MP Block Peripheral 3 */
+#define AT91CAP9_ID_MPB4	7	/* MP Block Peripheral 4 */
+#define AT91CAP9_ID_US0		8	/* USART 0 */
+#define AT91CAP9_ID_US1		9	/* USART 1 */
+#define AT91CAP9_ID_US2		10	/* USART 2 */
+#define AT91CAP9_ID_MCI0	11	/* Multimedia Card Interface 0 */
+#define AT91CAP9_ID_MCI1	12	/* Multimedia Card Interface 1 */
+#define AT91CAP9_ID_CAN		13	/* CAN */
+#define AT91CAP9_ID_TWI		14	/* Two-Wire Interface */
+#define AT91CAP9_ID_SPI0	15	/* Serial Peripheral Interface 0 */
+#define AT91CAP9_ID_SPI1	16	/* Serial Peripheral Interface 0 */
+#define AT91CAP9_ID_SSC0	17	/* Serial Synchronous Controller 0 */
+#define AT91CAP9_ID_SSC1	18	/* Serial Synchronous Controller 1 */
+#define AT91CAP9_ID_AC97C	19	/* AC97 Controller */
+#define AT91CAP9_ID_TCB		20	/* Timer Counter 0, 1 and 2 */
+#define AT91CAP9_ID_PWMC	21	/* Pulse Width Modulation Controller */
+#define AT91CAP9_ID_EMAC	22	/* Ethernet */
+#define AT91CAP9_ID_AESTDES	23	/* Advanced Encryption Standard, Triple DES */
+#define AT91CAP9_ID_ADC		24	/* Analog-to-Digital Converter */
+#define AT91CAP9_ID_ISI		25	/* Image Sensor Interface */
+#define AT91CAP9_ID_LCDC	26	/* LCD Controller */
+#define AT91CAP9_ID_DMA		27	/* DMA Controller */
+#define AT91CAP9_ID_UDPHS	28	/* USB High Speed Device Port */
+#define AT91CAP9_ID_UHP		29	/* USB Host Port */
+#define AT91CAP9_ID_IRQ0	30	/* Advanced Interrupt Controller (IRQ0) */
+#define AT91CAP9_ID_IRQ1	31	/* Advanced Interrupt Controller (IRQ1) */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91CAP9_BASE_UDPHS		0xfff78000
+#define AT91CAP9_BASE_TCB0		0xfff7c000
+#define AT91CAP9_BASE_TC0		0xfff7c000
+#define AT91CAP9_BASE_TC1		0xfff7c040
+#define AT91CAP9_BASE_TC2		0xfff7c080
+#define AT91CAP9_BASE_MCI0		0xfff80000
+#define AT91CAP9_BASE_MCI1		0xfff84000
+#define AT91CAP9_BASE_TWI		0xfff88000
+#define AT91CAP9_BASE_US0		0xfff8c000
+#define AT91CAP9_BASE_US1		0xfff90000
+#define AT91CAP9_BASE_US2		0xfff94000
+#define AT91CAP9_BASE_SSC0		0xfff98000
+#define AT91CAP9_BASE_SSC1		0xfff9c000
+#define AT91CAP9_BASE_AC97C		0xfffa0000
+#define AT91CAP9_BASE_SPI0		0xfffa4000
+#define AT91CAP9_BASE_SPI1		0xfffa8000
+#define AT91CAP9_BASE_CAN		0xfffac000
+#define AT91CAP9_BASE_PWMC		0xfffb8000
+#define AT91CAP9_BASE_EMAC		0xfffbc000
+#define AT91CAP9_BASE_ADC		0xfffc0000
+#define AT91CAP9_BASE_ISI		0xfffc4000
+#define AT91_BASE_SYS			0xffffe200
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_ECC	(0xffffe200 - AT91_BASE_SYS)
+#define AT91_BCRAMC	(0xffffe400 - AT91_BASE_SYS)
+#define AT91_DDRSDRC	(0xffffe600 - AT91_BASE_SYS)
+#define AT91_SMC	(0xffffe800 - AT91_BASE_SYS)
+#define AT91_MATRIX	(0xffffea00 - AT91_BASE_SYS)
+#define AT91_CCFG	(0xffffeb10 - AT91_BASE_SYS)
+#define AT91_DMA	(0xffffec00 - AT91_BASE_SYS)
+#define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
+#define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
+#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
+#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
+#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
+#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
+#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
+#define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
+#define AT91_SHDC	(0xfffffd10 - AT91_BASE_SYS)
+#define AT91_RTT	(0xfffffd20 - AT91_BASE_SYS)
+#define AT91_PIT	(0xfffffd30 - AT91_BASE_SYS)
+#define AT91_WDT	(0xfffffd40 - AT91_BASE_SYS)
+#define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
+
+/*
+ * Internal Memory.
+ */
+#define AT91CAP9_SRAM_BASE	0x00100000	/* Internal SRAM base address */
+#define AT91CAP9_SRAM_SIZE	(32 * SZ_1K)	/* Internal SRAM size (32Kb) */
+
+#define AT91CAP9_ROM_BASE	0x00400000	/* Internal ROM base address */
+#define AT91CAP9_ROM_SIZE	(32 * SZ_1K)	/* Internal ROM size (32Kb) */
+
+#define AT91CAP9_LCDC_BASE	0x00500000	/* LCD Controller */
+#define AT91CAP9_UDPHS_BASE	0x00600000	/* USB High Speed Device Port */
+#define AT91CAP9_UHP_BASE	0x00700000	/* USB Host controller */
+
+#define CONFIG_DRAM_BASE	AT91_CHIPSELECT_6
+
+#endif
diff --git a/include/asm-arm/arch-at91/at91cap9_matrix.h b/include/asm-arm/arch-at91/at91cap9_matrix.h
new file mode 100644
index 0000000..a641686
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91cap9_matrix.h
@@ -0,0 +1,132 @@
+/*
+ * include/asm-arm/arch-at91/at91cap9_matrix.h
+ *
+ *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
+ *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
+ *  Copyright (C) 2006 Atmel Corporation.
+ *
+ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
+ * Based on AT91CAP9 datasheet revision B (Preliminary).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91CAP9_MATRIX_H
+#define AT91CAP9_MATRIX_H
+
+#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG9	(AT91_MATRIX + 0x24)	/* Master Configuration Register 9 */
+#define AT91_MATRIX_MCFG10	(AT91_MATRIX + 0x28)	/* Master Configuration Register 10 */
+#define AT91_MATRIX_MCFG11	(AT91_MATRIX + 0x2C)	/* Master Configuration Register 11 */
+#define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
+#define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
+#define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
+#define			AT91_MATRIX_ULBT_FOUR		(2 << 0)
+#define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
+#define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
+
+#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
+#define AT91_MATRIX_SCFG8	(AT91_MATRIX + 0x60)	/* Slave Configuration Register 8 */
+#define AT91_MATRIX_SCFG9	(AT91_MATRIX + 0x64)	/* Slave Configuration Register 9 */
+#define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
+#define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
+#define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
+#define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
+#define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
+#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
+#define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
+#define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
+#define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
+
+#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
+#define AT91_MATRIX_PRAS8	(AT91_MATRIX + 0xC0)	/* Priority Register A for Slave 8 */
+#define AT91_MATRIX_PRBS8	(AT91_MATRIX + 0xC4)	/* Priority Register B for Slave 8 */
+#define AT91_MATRIX_PRAS9	(AT91_MATRIX + 0xC8)	/* Priority Register A for Slave 9 */
+#define AT91_MATRIX_PRBS9	(AT91_MATRIX + 0xCC)	/* Priority Register B for Slave 9 */
+#define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
+#define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
+#define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
+#define		AT91_MATRIX_M3PR		(3 << 12)	/* Master 3 Priority */
+#define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
+#define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
+#define		AT91_MATRIX_M6PR		(3 << 24)	/* Master 6 Priority */
+#define		AT91_MATRIX_M7PR		(3 << 28)	/* Master 7 Priority */
+#define		AT91_MATRIX_M8PR		(3 << 0)	/* Master 8 Priority (in Register B) */
+#define		AT91_MATRIX_M9PR		(3 << 4)	/* Master 9 Priority (in Register B) */
+#define		AT91_MATRIX_M10PR		(3 << 8)	/* Master 10 Priority (in Register B) */
+#define		AT91_MATRIX_M11PR		(3 << 12)	/* Master 11 Priority (in Register B) */
+
+#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
+#define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
+#define		AT91_MATRIX_RCB2		(1 << 2)
+#define		AT91_MATRIX_RCB3		(1 << 3)
+#define		AT91_MATRIX_RCB4		(1 << 4)
+#define		AT91_MATRIX_RCB5		(1 << 5)
+#define		AT91_MATRIX_RCB6		(1 << 6)
+#define		AT91_MATRIX_RCB7		(1 << 7)
+#define		AT91_MATRIX_RCB8		(1 << 8)
+#define		AT91_MATRIX_RCB9		(1 << 9)
+#define		AT91_MATRIX_RCB10		(1 << 10)
+#define		AT91_MATRIX_RCB11		(1 << 11)
+
+#define AT91_MPBS0_SFR		(AT91_MATRIX + 0x114)	/* MPBlock Slave 0 Special Function Register */
+#define AT91_MPBS1_SFR		(AT91_MATRIX + 0x11C)	/* MPBlock Slave 1 Special Function Register */
+
+#define AT91_MATRIX_EBICSA	(AT91_MATRIX + 0x120)	/* EBI Chip Select Assignment Register */
+#define		AT91_MATRIX_EBI_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
+#define			AT91_MATRIX_EBI_CS1A_SMC		(0 << 1)
+#define			AT91_MATRIX_EBI_CS1A_BCRAMC		(1 << 1)
+#define		AT91_MATRIX_EBI_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
+#define			AT91_MATRIX_EBI_CS3A_SMC		(0 << 3)
+#define			AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA	(1 << 3)
+#define		AT91_MATRIX_EBI_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
+#define			AT91_MATRIX_EBI_CS4A_SMC		(0 << 4)
+#define			AT91_MATRIX_EBI_CS4A_SMC_CF1		(1 << 4)
+#define		AT91_MATRIX_EBI_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
+#define			AT91_MATRIX_EBI_CS5A_SMC		(0 << 5)
+#define			AT91_MATRIX_EBI_CS5A_SMC_CF2		(1 << 5)
+#define		AT91_MATRIX_EBI_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+#define		AT91_MATRIX_EBI_DQSPDC		(1 << 9)	/* Data Qualifier Strobe Pull-Down Configuration */
+#define		AT91_MATRIX_EBI_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
+#define			AT91_MATRIX_EBI_VDDIOMSEL_1_8V		(0 << 16)
+#define			AT91_MATRIX_EBI_VDDIOMSEL_3_3V		(1 << 16)
+
+#define AT91_MPBS2_SFR		(AT91_MATRIX + 0x12C)	/* MPBlock Slave 2 Special Function Register */
+#define AT91_MPBS3_SFR		(AT91_MATRIX + 0x130)	/* MPBlock Slave 3 Special Function Register */
+#define AT91_APB_SFR		(AT91_MATRIX + 0x134)	/* APB Bridge Special Function Register */
+
+#endif
diff --git a/include/asm-arm/arch-at91/at91sam9260_matrix.h b/include/asm-arm/arch-at91/at91sam9260_matrix.h
index aacb1e9..a8e9fec 100644
--- a/include/asm-arm/arch-at91/at91sam9260_matrix.h
+++ b/include/asm-arm/arch-at91/at91sam9260_matrix.h
@@ -67,7 +67,7 @@
 #define		AT91_MATRIX_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
 #define			AT91_MATRIX_CS4A_SMC		(0 << 4)
 #define			AT91_MATRIX_CS4A_SMC_CF1	(1 << 4)
-#define		AT91_MATRIX_CS5A		(1 << 5 )	/* Chip Select 5 Assignment */
+#define		AT91_MATRIX_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
 #define			AT91_MATRIX_CS5A_SMC		(0 << 5)
 #define			AT91_MATRIX_CS5A_SMC_CF2	(1 << 5)
 #define		AT91_MATRIX_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
diff --git a/include/asm-arm/arch-at91/at91sam9263_matrix.h b/include/asm-arm/arch-at91/at91sam9263_matrix.h
index 6fc6e4b..72f6e66 100644
--- a/include/asm-arm/arch-at91/at91sam9263_matrix.h
+++ b/include/asm-arm/arch-at91/at91sam9263_matrix.h
@@ -44,7 +44,7 @@
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
 #define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
 #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
-#define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
+#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
 #define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
 #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
 #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
diff --git a/include/asm-arm/arch-at91/at91sam9rl_matrix.h b/include/asm-arm/arch-at91/at91sam9rl_matrix.h
index b15f11b..8422417 100644
--- a/include/asm-arm/arch-at91/at91sam9rl_matrix.h
+++ b/include/asm-arm/arch-at91/at91sam9rl_matrix.h
@@ -38,7 +38,7 @@
 #define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
 #define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
 #define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
-#define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
+#define		AT91_MATRIX_FIXED_DEFMSTR	(0xf  << 18)	/* Fixed Index of Default Master */
 #define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
 #define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
 #define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 7905496..55b07bd 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -34,6 +34,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/device.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
 #include <linux/spi/spi.h>
 
  /* USB Device */
@@ -71,7 +72,7 @@
 };
 extern void __init at91_add_device_eth(struct at91_eth_data *data);
 
-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263)
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
 #define eth_platform_data	at91_eth_data
 #endif
 
@@ -101,13 +102,23 @@
 extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
 
  /* Serial */
+#define ATMEL_UART_CTS	0x01
+#define ATMEL_UART_RTS	0x02
+#define ATMEL_UART_DSR	0x04
+#define ATMEL_UART_DTR	0x08
+#define ATMEL_UART_DCD	0x10
+#define ATMEL_UART_RI	0x20
+
+extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
+extern void __init at91_set_serial_console(unsigned portnr);
+
 struct at91_uart_config {
 	unsigned short	console_tty;	/* tty number of serial console */
 	unsigned short	nr_tty;		/* number of serial tty's */
 	short		tty_map[];	/* map UART to tty number */
 };
 extern struct platform_device *atmel_default_console_device;
-extern void __init at91_init_serial(struct at91_uart_config *config);
+extern void __init __deprecated at91_init_serial(struct at91_uart_config *config);
 
 struct atmel_uart_data {
 	short		use_dma_tx;	/* use transmit DMA? */
@@ -116,6 +127,23 @@
 };
 extern void __init at91_add_device_serial(void);
 
+/*
+ * SSC -- accessed through ssc_request(id).  Drivers don't bind to SSC
+ * platform devices.  Their SSC ID is part of their configuration data,
+ * along with information about which SSC signals they should use.
+ */
+#define ATMEL_SSC_TK	0x01
+#define ATMEL_SSC_TF	0x02
+#define ATMEL_SSC_TD	0x04
+#define ATMEL_SSC_TX	(ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
+
+#define ATMEL_SSC_RK	0x10
+#define ATMEL_SSC_RF	0x20
+#define ATMEL_SSC_RD	0x40
+#define ATMEL_SSC_RX	(ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
+
+extern void __init at91_add_device_ssc(unsigned id, unsigned pins);
+
  /* LCD Controller */
 struct atmel_lcdfb_info;
 extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
@@ -126,10 +154,12 @@
 };
 extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
 
+ /* ISI */
+extern void __init at91_add_device_isi(void);
+
  /* LEDs */
-extern u8 at91_leds_cpu;
-extern u8 at91_leds_timer;
 extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
+extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 
 /* FIXME: this needs a better location, but gets stuff building again */
 extern int at91_suspend_entering_slow_clock(void);
diff --git a/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
index 080cbb4..7145166 100644
--- a/include/asm-arm/arch-at91/cpu.h
+++ b/include/asm-arm/arch-at91/cpu.h
@@ -21,13 +21,13 @@
 #define ARCH_ID_AT91SAM9260	0x019803a0
 #define ARCH_ID_AT91SAM9261	0x019703a0
 #define ARCH_ID_AT91SAM9263	0x019607a0
+#define ARCH_ID_AT91SAM9RL64	0x019b03a0
+#define ARCH_ID_AT91CAP9	0x039A03A0
 
 #define ARCH_ID_AT91SAM9XE128	0x329973a0
 #define ARCH_ID_AT91SAM9XE256	0x329a93a0
 #define ARCH_ID_AT91SAM9XE512	0x329aa3a0
 
-#define ARCH_ID_AT91SAM9RL64	0x019b03a0
-
 #define ARCH_ID_AT91M40800	0x14080044
 #define ARCH_ID_AT91R40807	0x44080746
 #define ARCH_ID_AT91M40807	0x14080745
@@ -81,6 +81,11 @@
 #define cpu_is_at91sam9rl()	(0)
 #endif
 
+#ifdef CONFIG_ARCH_AT91CAP9
+#define cpu_is_at91cap9()	(at91_cpu_identify() == ARCH_ID_AT91CAP9)
+#else
+#define cpu_is_at91cap9()	(0)
+#endif
 
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
diff --git a/include/asm-arm/arch-at91/entry-macro.S b/include/asm-arm/arch-at91/entry-macro.S
index cc1d850..1005eee 100644
--- a/include/asm-arm/arch-at91/entry-macro.S
+++ b/include/asm-arm/arch-at91/entry-macro.S
@@ -17,13 +17,13 @@
 	.endm
 
 	.macro  get_irqnr_preamble, base, tmp
+	ldr	\base, =(AT91_VA_BASE_SYS + AT91_AIC)		@ base virtual address of AIC peripheral
 	.endm
 
 	.macro  arch_ret_to_user, tmp1, tmp2
 	.endm
 
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	ldr	\base, =(AT91_VA_BASE_SYS + AT91_AIC)		@ base virtual address of AIC peripheral
 	ldr	\irqnr, [\base, #(AT91_AIC_IVR - AT91_AIC)]	@ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
 	ldr	\irqstat, [\base, #(AT91_AIC_ISR - AT91_AIC)]	@ read interrupt source number
 	teq	\irqstat, #0					@ ISR is 0 when no current interrupt, or spurious interrupt
diff --git a/include/asm-arm/arch-at91/hardware.h b/include/asm-arm/arch-at91/hardware.h
index 8f1cdd3..2c826d82 100644
--- a/include/asm-arm/arch-at91/hardware.h
+++ b/include/asm-arm/arch-at91/hardware.h
@@ -26,6 +26,8 @@
 #include <asm/arch/at91sam9263.h>
 #elif defined(CONFIG_ARCH_AT91SAM9RL)
 #include <asm/arch/at91sam9rl.h>
+#elif defined(CONFIG_ARCH_AT91CAP9)
+#include <asm/arch/at91cap9.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <asm/arch/at91x40.h>
 #else
diff --git a/include/asm-arm/arch-at91/timex.h b/include/asm-arm/arch-at91/timex.h
index a310698..f1933b0 100644
--- a/include/asm-arm/arch-at91/timex.h
+++ b/include/asm-arm/arch-at91/timex.h
@@ -42,6 +42,11 @@
 #define AT91SAM9_MASTER_CLOCK	100000000
 #define CLOCK_TICK_RATE		(AT91SAM9_MASTER_CLOCK/16)
 
+#elif defined(CONFIG_ARCH_AT91CAP9)
+
+#define AT91CAP9_MASTER_CLOCK	100000000
+#define CLOCK_TICK_RATE		(AT91CAP9_MASTER_CLOCK/16)
+
 #elif defined(CONFIG_ARCH_AT91X40)
 
 #define AT91X40_MASTER_CLOCK	40000000
diff --git a/include/asm-arm/arch-ep93xx/gpio.h b/include/asm-arm/arch-ep93xx/gpio.h
index 1ee14a1..9b1864b 100644
--- a/include/asm-arm/arch-ep93xx/gpio.h
+++ b/include/asm-arm/arch-ep93xx/gpio.h
@@ -5,16 +5,6 @@
 #ifndef __ASM_ARCH_GPIO_H
 #define __ASM_ARCH_GPIO_H
 
-#define GPIO_IN				0
-#define GPIO_OUT			1
-
-#define EP93XX_GPIO_LOW			0
-#define EP93XX_GPIO_HIGH		1
-
-extern void gpio_line_config(int line, int direction);
-extern int  gpio_line_get(int line);
-extern void gpio_line_set(int line, int value);
-
 /* GPIO port A.  */
 #define EP93XX_GPIO_LINE_A(x)		((x) + 0)
 #define EP93XX_GPIO_LINE_EGPIO0		EP93XX_GPIO_LINE_A(0)
@@ -38,7 +28,7 @@
 #define EP93XX_GPIO_LINE_EGPIO15	EP93XX_GPIO_LINE_B(7)
 
 /* GPIO port C.  */
-#define EP93XX_GPIO_LINE_C(x)		((x) + 16)
+#define EP93XX_GPIO_LINE_C(x)		((x) + 40)
 #define EP93XX_GPIO_LINE_ROW0		EP93XX_GPIO_LINE_C(0)
 #define EP93XX_GPIO_LINE_ROW1		EP93XX_GPIO_LINE_C(1)
 #define EP93XX_GPIO_LINE_ROW2		EP93XX_GPIO_LINE_C(2)
@@ -71,7 +61,7 @@
 #define EP93XX_GPIO_LINE_IDEDA2		EP93XX_GPIO_LINE_E(7)
 
 /* GPIO port F.  */
-#define EP93XX_GPIO_LINE_F(x)		((x) + 40)
+#define EP93XX_GPIO_LINE_F(x)		((x) + 16)
 #define EP93XX_GPIO_LINE_WP		EP93XX_GPIO_LINE_F(0)
 #define EP93XX_GPIO_LINE_MCCD1		EP93XX_GPIO_LINE_F(1)
 #define EP93XX_GPIO_LINE_MCCD2		EP93XX_GPIO_LINE_F(2)
@@ -103,5 +93,49 @@
 #define EP93XX_GPIO_LINE_DD6		EP93XX_GPIO_LINE_H(6)
 #define EP93XX_GPIO_LINE_DD7		EP93XX_GPIO_LINE_H(7)
 
+/* maximum value for gpio line identifiers */
+#define EP93XX_GPIO_LINE_MAX		EP93XX_GPIO_LINE_H(7)
+
+/* maximum value for irq capable line identifiers */
+#define EP93XX_GPIO_LINE_MAX_IRQ	EP93XX_GPIO_LINE_F(7)
+
+/* new generic GPIO API - see Documentation/gpio.txt */
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+	if (gpio > EP93XX_GPIO_LINE_MAX)
+		return -EINVAL;
+	return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+}
+
+int gpio_direction_input(unsigned gpio);
+int gpio_direction_output(unsigned gpio, int value);
+int gpio_get_value(unsigned gpio);
+void gpio_set_value(unsigned gpio, int value);
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+/*
+ * Map GPIO A0..A7  (0..7)  to irq 64..71,
+ *          B0..B7  (7..15) to irq 72..79, and
+ *          F0..F7 (16..24) to irq 80..87.
+ */
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ)
+		return 64 + gpio;
+
+	return -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return irq - gpio_to_irq(0);
+}
 
 #endif
diff --git a/include/asm-arm/arch-ep93xx/irqs.h b/include/asm-arm/arch-ep93xx/irqs.h
index 2a8c636..53d4a68 100644
--- a/include/asm-arm/arch-ep93xx/irqs.h
+++ b/include/asm-arm/arch-ep93xx/irqs.h
@@ -67,12 +67,6 @@
 #define IRQ_EP93XX_SAI			60
 #define EP93XX_VIC2_VALID_IRQ_MASK	0x1fffffff
 
-/*
- * Map GPIO A0..A7 to irq 64..71, B0..B7 to 72..79, and
- * F0..F7 to 80..87.
- */
-#define IRQ_EP93XX_GPIO(x)		(64 + (((x) + (((x) >> 2) & 8)) & 0x1f))
-
 #define NR_EP93XX_IRQS			(64 + 24)
 
 #define EP93XX_BOARD_IRQ(x)		(NR_EP93XX_IRQS + (x))
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index eeeea90..9c5d235 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -61,13 +61,13 @@
 	if((addr < PCIBIOS_MIN_MEM) || (addr > 0x4fffffff))
 		return __arm_ioremap(addr, size, mtype);
 
-	return (void *)addr;
+	return (void __iomem *)addr;
 }
 
 static inline void
 __ixp4xx_iounmap(void __iomem *addr)
 {
-	if ((u32)addr >= VMALLOC_START)
+	if ((__force u32)addr >= VMALLOC_START)
 		__iounmap(addr);
 }
 
@@ -141,9 +141,9 @@
 static inline void 
 __ixp4xx_writel(u32 value, volatile void __iomem *p)
 {
-	u32 addr = (u32)p;
+	u32 addr = (__force u32)p;
 	if (addr >= VMALLOC_START) {
-		__raw_writel(value, addr);
+		__raw_writel(value, p);
 		return;
 	}
 
@@ -208,11 +208,11 @@
 static inline unsigned long 
 __ixp4xx_readl(const volatile void __iomem *p)
 {
-	u32 addr = (u32)p;
+	u32 addr = (__force u32)p;
 	u32 data;
 
 	if (addr >= VMALLOC_START)
-		return __raw_readl(addr);
+		return __raw_readl(p);
 
 	if (ixp4xx_pci_read(addr, NP_CMD_MEMREAD, &data))
 		return 0xffffffff;
@@ -438,7 +438,7 @@
 		return	(unsigned int)__ixp4xx_inl(port & PIO_MASK);
 	else {
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-		return le32_to_cpu(__raw_readl((u32)port));
+		return le32_to_cpu((__force __le32)__raw_readl(addr));
 #else
 		return (unsigned int)__ixp4xx_readl(addr);
 #endif
@@ -523,7 +523,7 @@
 		__ixp4xx_outl(value, port & PIO_MASK);
 	else
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
-		__raw_writel(cpu_to_le32(value), port);
+		__raw_writel((u32 __force)cpu_to_le32(value), addr);
 #else
 		__ixp4xx_writel(value, addr);
 #endif
diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
index 2a44d3d..2ce28e3 100644
--- a/include/asm-arm/arch-ixp4xx/platform.h
+++ b/include/asm-arm/arch-ixp4xx/platform.h
@@ -76,17 +76,6 @@
 #define IXP4XX_UART_XTAL        	14745600
 
 /*
- * The IXP4xx chips do not have an I2C unit, so GPIO lines are just
- * used to 
- * Used as platform_data to provide GPIO pin information to the ixp42x
- * I2C driver.
- */
-struct ixp4xx_i2c_pins {
-	unsigned long sda_pin;
-	unsigned long scl_pin;
-};
-
-/*
  * This structure provide a means for the board setup code
  * to give information to th pata_ixp4xx driver. It is
  * passed as platform_data.
diff --git a/include/asm-arm/arch-ks8695/regs-gpio.h b/include/asm-arm/arch-ks8695/regs-gpio.h
index 57fcf9f..6b95d77 100644
--- a/include/asm-arm/arch-ks8695/regs-gpio.h
+++ b/include/asm-arm/arch-ks8695/regs-gpio.h
@@ -49,5 +49,7 @@
 #define IOPC_TM_FALLING		(4)		/* Falling Edge Detection */
 #define IOPC_TM_EDGE		(6)		/* Both Edge Detection */
 
+/* Port Data Register */
+#define IOPD_(x)		(1 << (x))	/* Signal Level of GPIO Pin x */
 
 #endif
diff --git a/include/asm-arm/arch-msm/board.h b/include/asm-arm/arch-msm/board.h
new file mode 100644
index 0000000..763051f
--- /dev/null
+++ b/include/asm-arm/arch-msm/board.h
@@ -0,0 +1,37 @@
+/* linux/include/asm-arm/arch-msm/board.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_BOARD_H
+#define __ASM_ARCH_MSM_BOARD_H
+
+#include <linux/types.h>
+
+/* platform device data structures */
+
+struct msm_mddi_platform_data
+{
+	void (*panel_power)(int on);
+	unsigned has_vsync_irq:1;
+};
+
+/* common init routines for use by arch/arm/mach-msm/board-*.c */
+
+void __init msm_add_devices(void);
+void __init msm_map_common_io(void);
+void __init msm_init_irq(void);
+void __init msm_init_gpio(void);
+
+#endif
diff --git a/include/asm-arm/arch-msm/debug-macro.S b/include/asm-arm/arch-msm/debug-macro.S
new file mode 100644
index 0000000..393d527
--- /dev/null
+++ b/include/asm-arm/arch-msm/debug-macro.S
@@ -0,0 +1,40 @@
+/* include/asm-arm/arch-msm7200/debug-macro.S
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <asm/hardware.h>
+#include <asm/arch/msm_iomap.h>
+
+	.macro	addruart,rx
+	@ see if the MMU is enabled and select appropriate base address
+	mrc	p15, 0, \rx, c1, c0
+	tst	\rx, #1
+	ldreq	\rx, =MSM_UART1_PHYS
+	ldrne	\rx, =MSM_UART1_BASE
+	.endm
+
+	.macro	senduart,rd,rx
+	str	\rd, [\rx, #0x0C]
+	.endm
+
+	.macro	waituart,rd,rx
+	@ wait for TX_READY
+1:	ldr	\rd, [\rx, #0x08]
+	tst	\rd, #0x04
+	beq	1b
+	.endm
+
+	.macro	busyuart,rd,rx
+	.endm
diff --git a/include/asm-arm/arch-msm/dma.h b/include/asm-arm/arch-msm/dma.h
new file mode 100644
index 0000000..e4b565b
--- /dev/null
+++ b/include/asm-arm/arch-msm/dma.h
@@ -0,0 +1,151 @@
+/* linux/include/asm-arm/arch-msm/dma.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_DMA_H
+
+#include <linux/list.h>
+#include <asm/arch/msm_iomap.h>
+
+struct msm_dmov_cmd {
+	struct list_head list;
+	unsigned int cmdptr;
+	void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result);
+/*	void (*user_result_func)(struct msm_dmov_cmd *cmd); */
+};
+
+void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
+void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd);
+int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
+/* int msm_dmov_exec_cmd_etc(unsigned id, unsigned int cmdptr, int timeout, int interruptible); */
+
+
+
+#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
+#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2))
+#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2))
+#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2))
+
+/* only security domain 3 is available to the ARM11
+ * SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM
+ */
+
+#define DMOV_CMD_PTR(ch)      DMOV_SD3(0x000, ch)
+#define DMOV_CMD_LIST         (0 << 29) /* does not work */
+#define DMOV_CMD_PTR_LIST     (1 << 29) /* works */
+#define DMOV_CMD_INPUT_CFG    (2 << 29) /* untested */
+#define DMOV_CMD_OUTPUT_CFG   (3 << 29) /* untested */
+#define DMOV_CMD_ADDR(addr)   ((addr) >> 3)
+
+#define DMOV_RSLT(ch)         DMOV_SD3(0x040, ch)
+#define DMOV_RSLT_VALID       (1 << 31) /* 0 == host has empties result fifo */
+#define DMOV_RSLT_ERROR       (1 << 3)
+#define DMOV_RSLT_FLUSH       (1 << 2)
+#define DMOV_RSLT_DONE        (1 << 1)  /* top pointer done */
+#define DMOV_RSLT_USER        (1 << 0)  /* command with FR force result */
+
+#define DMOV_FLUSH0(ch)       DMOV_SD3(0x080, ch)
+#define DMOV_FLUSH1(ch)       DMOV_SD3(0x0C0, ch)
+#define DMOV_FLUSH2(ch)       DMOV_SD3(0x100, ch)
+#define DMOV_FLUSH3(ch)       DMOV_SD3(0x140, ch)
+#define DMOV_FLUSH4(ch)       DMOV_SD3(0x180, ch)
+#define DMOV_FLUSH5(ch)       DMOV_SD3(0x1C0, ch)
+
+#define DMOV_STATUS(ch)       DMOV_SD3(0x200, ch)
+#define DMOV_STATUS_RSLT_COUNT(n)    (((n) >> 29))
+#define DMOV_STATUS_CMD_COUNT(n)     (((n) >> 27) & 3)
+#define DMOV_STATUS_RSLT_VALID       (1 << 1)
+#define DMOV_STATUS_CMD_PTR_RDY      (1 << 0)
+
+#define DMOV_ISR              DMOV_SD3(0x380, 0)
+
+#define DMOV_CONFIG(ch)       DMOV_SD3(0x300, ch)
+#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2)
+#define DMOV_CONFIG_FORCE_FLUSH_RSLT   (1 << 1)
+#define DMOV_CONFIG_IRQ_EN             (1 << 0)
+
+/* channel assignments */
+
+#define DMOV_NAND_CHAN        7
+#define DMOV_NAND_CRCI_CMD    5
+#define DMOV_NAND_CRCI_DATA   4
+
+#define DMOV_SDC1_CHAN        8
+#define DMOV_SDC1_CRCI        6
+
+#define DMOV_SDC2_CHAN        8
+#define DMOV_SDC2_CRCI        7
+
+#define DMOV_TSIF_CHAN        10
+#define DMOV_TSIF_CRCI        10
+
+#define DMOV_USB_CHAN         11
+
+/* no client rate control ifc (eg, ram) */
+#define DMOV_NONE_CRCI        0
+
+
+/* If the CMD_PTR register has CMD_PTR_LIST selected, the data mover
+ * is going to walk a list of 32bit pointers as described below.  Each
+ * pointer points to a *array* of dmov_s, etc structs.  The last pointer
+ * in the list is marked with CMD_PTR_LP.  The last struct in each array
+ * is marked with CMD_LC (see below).
+ */
+#define CMD_PTR_ADDR(addr)  ((addr) >> 3)
+#define CMD_PTR_LP          (1 << 31) /* last pointer */
+#define CMD_PTR_PT          (3 << 29) /* ? */
+
+/* Single Item Mode */
+typedef struct {
+	unsigned cmd;
+	unsigned src;
+	unsigned dst;
+	unsigned len;
+} dmov_s;
+
+/* Scatter/Gather Mode */
+typedef struct {
+	unsigned cmd;
+	unsigned src_dscr;
+	unsigned dst_dscr;
+	unsigned _reserved;
+} dmov_sg;
+
+/* bits for the cmd field of the above structures */
+
+#define CMD_LC      (1 << 31)  /* last command */
+#define CMD_FR      (1 << 22)  /* force result -- does not work? */
+#define CMD_OCU     (1 << 21)  /* other channel unblock */
+#define CMD_OCB     (1 << 20)  /* other channel block */
+#define CMD_TCB     (1 << 19)  /* ? */
+#define CMD_DAH     (1 << 18)  /* destination address hold -- does not work?*/
+#define CMD_SAH     (1 << 17)  /* source address hold -- does not work? */
+
+#define CMD_MODE_SINGLE     (0 << 0) /* dmov_s structure used */
+#define CMD_MODE_SG         (1 << 0) /* untested */
+#define CMD_MODE_IND_SG     (2 << 0) /* untested */
+#define CMD_MODE_BOX        (3 << 0) /* untested */
+
+#define CMD_DST_SWAP_BYTES  (1 << 14) /* exchange each byte n with byte n+1 */
+#define CMD_DST_SWAP_SHORTS (1 << 15) /* exchange each short n with short n+1 */
+#define CMD_DST_SWAP_WORDS  (1 << 16) /* exchange each word n with word n+1 */
+
+#define CMD_SRC_SWAP_BYTES  (1 << 11) /* exchange each byte n with byte n+1 */
+#define CMD_SRC_SWAP_SHORTS (1 << 12) /* exchange each short n with short n+1 */
+#define CMD_SRC_SWAP_WORDS  (1 << 13) /* exchange each word n with word n+1 */
+
+#define CMD_DST_CRCI(n)     (((n) & 15) << 7)
+#define CMD_SRC_CRCI(n)     (((n) & 15) << 3)
+
+#endif
diff --git a/include/asm-arm/arch-msm/entry-macro.S b/include/asm-arm/arch-msm/entry-macro.S
new file mode 100644
index 0000000..ee24aec
--- /dev/null
+++ b/include/asm-arm/arch-msm/entry-macro.S
@@ -0,0 +1,38 @@
+/* include/asm-arm/arch-msm7200/entry-macro.S
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <asm/arch/msm_iomap.h>
+
+ 	.macro	disable_fiq
+	.endm
+
+	.macro	get_irqnr_preamble, base, tmp
+	@ enable imprecise aborts
+	cpsie	a
+	mov	\base, #MSM_VIC_BASE
+	.endm
+
+	.macro	arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	@ 0xD0 has irq# or old irq# if the irq has been handled
+	@ 0xD4 has irq# or -1 if none pending *but* if you just
+	@ read 0xD4 you never get the first irq for some reason
+	ldr	\irqnr, [\base, #0xD0]
+	ldr	\irqnr, [\base, #0xD4]
+	cmp	\irqnr, #0xffffffff
+	.endm
diff --git a/include/asm-arm/arch-msm/hardware.h b/include/asm-arm/arch-msm/hardware.h
new file mode 100644
index 0000000..89af2b7
--- /dev/null
+++ b/include/asm-arm/arch-msm/hardware.h
@@ -0,0 +1,18 @@
+/* linux/include/asm-arm/arch-msm/hardware.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_HARDWARE_H
+
+#endif
diff --git a/include/asm-arm/arch-msm/io.h b/include/asm-arm/arch-msm/io.h
new file mode 100644
index 0000000..4645ae2
--- /dev/null
+++ b/include/asm-arm/arch-msm/io.h
@@ -0,0 +1,33 @@
+/* include/asm-arm/arch-msm/io.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __arch_ioremap __msm_ioremap
+#define __arch_iounmap __iounmap
+
+void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype);
+
+static inline void __iomem *__io(unsigned long addr)
+{
+	return (void __iomem *)addr;
+}
+#define __io(a)         __io(a)
+#define __mem_pci(a)    (a)
+
+#endif
diff --git a/include/asm-arm/arch-msm/irqs.h b/include/asm-arm/arch-msm/irqs.h
new file mode 100644
index 0000000..565430c
--- /dev/null
+++ b/include/asm-arm/arch-msm/irqs.h
@@ -0,0 +1,89 @@
+/* linux/include/asm-arm/arch-msm/irqs.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_H
+
+/* MSM ARM11 Interrupt Numbers */
+/* See 80-VE113-1 A, pp219-221     */
+
+#define INT_A9_M2A_0         0
+#define INT_A9_M2A_1         1
+#define INT_A9_M2A_2         2
+#define INT_A9_M2A_3         3
+#define INT_A9_M2A_4         4
+#define INT_A9_M2A_5         5
+#define INT_A9_M2A_6         6
+#define INT_GP_TIMER_EXP     7
+#define INT_DEBUG_TIMER_EXP  8
+#define INT_UART1            9
+#define INT_UART2            10
+#define INT_UART3            11
+#define INT_UART1_RX         12
+#define INT_UART2_RX         13
+#define INT_UART3_RX         14
+#define INT_USB_OTG          15
+#define INT_MDDI_PRI         16
+#define INT_MDDI_EXT         17
+#define INT_MDDI_CLIENT      18
+#define INT_MDP              19
+#define INT_GRAPHICS         20
+#define INT_ADM_AARM         21
+#define INT_ADSP_A11         22
+#define INT_ADSP_A9_A11      23
+#define INT_SDC1_0           24
+#define INT_SDC1_1           25
+#define INT_SDC2_0           26
+#define INT_SDC2_1           27
+#define INT_KEYSENSE         28
+#define INT_TCHSCRN_SSBI     29
+#define INT_TCHSCRN1         30
+#define INT_TCHSCRN2         31
+
+#define INT_GPIO_GROUP1      (32 + 0)
+#define INT_GPIO_GROUP2      (32 + 1)
+#define INT_PWB_I2C          (32 + 2)
+#define INT_SOFTRESET        (32 + 3)
+#define INT_NAND_WR_ER_DONE  (32 + 4)
+#define INT_NAND_OP_DONE     (32 + 5)
+#define INT_PBUS_ARM11       (32 + 6)
+#define INT_AXI_MPU_SMI      (32 + 7)
+#define INT_AXI_MPU_EBI1     (32 + 8)
+#define INT_AD_HSSD          (32 + 9)
+#define INT_ARM11_PMU        (32 + 10)
+#define INT_ARM11_DMA        (32 + 11)
+#define INT_TSIF_IRQ         (32 + 12)
+#define INT_UART1DM_IRQ      (32 + 13)
+#define INT_UART1DM_RX       (32 + 14)
+#define INT_USB_HS           (32 + 15)
+#define INT_SDC3_0           (32 + 16)
+#define INT_SDC3_1           (32 + 17)
+#define INT_SDC4_0           (32 + 18)
+#define INT_SDC4_1           (32 + 19)
+#define INT_UART2DM_RX       (32 + 20)
+#define INT_UART2DM_IRQ      (32 + 21)
+
+/* 22-31 are reserved */
+
+#define MSM_IRQ_BIT(irq)     (1 << ((irq) & 31))
+
+#define NR_MSM_IRQS 64
+#define NR_GPIO_IRQS 122
+#define NR_BOARD_IRQS 64
+#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
+
+#define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
+
+#endif
diff --git a/include/asm-arm/arch-msm/memory.h b/include/asm-arm/arch-msm/memory.h
new file mode 100644
index 0000000..b5ce0e9
--- /dev/null
+++ b/include/asm-arm/arch-msm/memory.h
@@ -0,0 +1,27 @@
+/* linux/include/asm-arm/arch-msm/memory.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/* physical offset of RAM */
+#define PHYS_OFFSET		UL(0x10000000)
+
+/* bus address and physical addresses are identical */
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt(x)	__phys_to_virt(x)
+
+#endif
+
diff --git a/include/asm-arm/arch-msm/msm_iomap.h b/include/asm-arm/arch-msm/msm_iomap.h
new file mode 100644
index 0000000..b8955cc
--- /dev/null
+++ b/include/asm-arm/arch-msm/msm_iomap.h
@@ -0,0 +1,104 @@
+/* linux/include/asm-arm/arch-msm/msm_iomap.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_H
+#define __ASM_ARCH_MSM_IOMAP_H
+
+#include <asm/sizes.h>
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * MSM_VIC_BASE must be an value that can be loaded via a "mov"
+ * instruction, otherwise entry-macro.S will not compile.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM_VIC_BASE          0xE0000000
+#define MSM_VIC_PHYS          0xC0000000
+#define MSM_VIC_SIZE          SZ_4K
+
+#define MSM_CSR_BASE          0xE0001000
+#define MSM_CSR_PHYS          0xC0100000
+#define MSM_CSR_SIZE          SZ_4K
+
+#define MSM_GPT_PHYS          MSM_CSR_PHYS
+#define MSM_GPT_BASE          MSM_CSR_BASE
+#define MSM_GPT_SIZE          SZ_4K
+
+#define MSM_DMOV_BASE         0xE0002000
+#define MSM_DMOV_PHYS         0xA9700000
+#define MSM_DMOV_SIZE         SZ_4K
+
+#define MSM_UART1_BASE        0xE0003000
+#define MSM_UART1_PHYS        0xA9A00000
+#define MSM_UART1_SIZE        SZ_4K
+
+#define MSM_UART2_BASE        0xE0004000
+#define MSM_UART2_PHYS        0xA9B00000
+#define MSM_UART2_SIZE        SZ_4K
+
+#define MSM_UART3_BASE        0xE0005000
+#define MSM_UART3_PHYS        0xA9C00000
+#define MSM_UART3_SIZE        SZ_4K
+
+#define MSM_I2C_BASE          0xE0006000
+#define MSM_I2C_PHYS          0xA9900000
+#define MSM_I2C_SIZE          SZ_4K
+
+#define MSM_GPIO1_BASE        0xE0007000
+#define MSM_GPIO1_PHYS        0xA9200000
+#define MSM_GPIO1_SIZE        SZ_4K
+
+#define MSM_GPIO2_BASE        0xE0008000
+#define MSM_GPIO2_PHYS        0xA9300000
+#define MSM_GPIO2_SIZE        SZ_4K
+
+#define MSM_HSUSB_BASE        0xE0009000
+#define MSM_HSUSB_PHYS        0xA0800000
+#define MSM_HSUSB_SIZE        SZ_4K
+
+#define MSM_CLK_CTL_BASE      0xE000A000
+#define MSM_CLK_CTL_PHYS      0xA8600000
+#define MSM_CLK_CTL_SIZE      SZ_4K
+
+#define MSM_PMDH_BASE         0xE000B000
+#define MSM_PMDH_PHYS         0xAA600000
+#define MSM_PMDH_SIZE         SZ_4K
+
+#define MSM_EMDH_BASE         0xE000C000
+#define MSM_EMDH_PHYS         0xAA700000
+#define MSM_EMDH_SIZE         SZ_4K
+
+#define MSM_MDP_BASE          0xE0010000
+#define MSM_MDP_PHYS          0xAA200000
+#define MSM_MDP_SIZE          0x000F0000
+
+#define MSM_SHARED_RAM_BASE   0xE0100000
+#define MSM_SHARED_RAM_PHYS   0x01F00000
+#define MSM_SHARED_RAM_SIZE   SZ_1M
+
+#endif
diff --git a/include/asm-arm/arch-msm/system.h b/include/asm-arm/arch-msm/system.h
new file mode 100644
index 0000000..7c5544b
--- /dev/null
+++ b/include/asm-arm/arch-msm/system.h
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-msm/system.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <asm/hardware.h>
+
+void arch_idle(void);
+
+static inline void arch_reset(char mode)
+{
+	for (;;) ;  /* depends on IPC w/ other core */
+}
diff --git a/include/asm-arm/arch-msm/timex.h b/include/asm-arm/arch-msm/timex.h
new file mode 100644
index 0000000..154b23f
--- /dev/null
+++ b/include/asm-arm/arch-msm/timex.h
@@ -0,0 +1,20 @@
+/* linux/include/asm-arm/arch-msm/timex.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_TIMEX_H
+
+#define CLOCK_TICK_RATE		1000000
+
+#endif
diff --git a/include/asm-arm/arch-msm/uncompress.h b/include/asm-arm/arch-msm/uncompress.h
new file mode 100644
index 0000000..e91ed78
--- /dev/null
+++ b/include/asm-arm/arch-msm/uncompress.h
@@ -0,0 +1,36 @@
+/* linux/include/asm-arm/arch-msm/uncompress.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
+
+#include "hardware.h"
+
+static void putc(int c)
+{
+}
+
+static inline void flush(void)
+{
+}
+
+static inline void arch_decomp_setup(void)
+{
+}
+
+static inline void arch_decomp_wdog(void)
+{
+}
+
+#endif
diff --git a/include/asm-arm/arch-msm/vmalloc.h b/include/asm-arm/arch-msm/vmalloc.h
new file mode 100644
index 0000000..60f8d91
--- /dev/null
+++ b/include/asm-arm/arch-msm/vmalloc.h
@@ -0,0 +1,22 @@
+/* linux/include/asm-arm/arch-msm/vmalloc.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_VMALLOC_H
+#define __ASM_ARCH_MSM_VMALLOC_H
+
+#define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
+
+#endif
+
diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
index e404b23..80596b0 100644
--- a/include/asm-arm/arch-pxa/i2c.h
+++ b/include/asm-arm/arch-pxa/i2c.h
@@ -65,7 +65,13 @@
 	unsigned int		slave_addr;
 	struct i2c_slave_client	*slave;
 	unsigned int		class;
+	int			use_pio;
 };
 
 extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
+
+#ifdef CONFIG_PXA27x
+extern void pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
 #endif
diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S
index 9c8cd9a..89076c3 100644
--- a/include/asm-arm/arch-s3c2410/debug-macro.S
+++ b/include/asm-arm/arch-s3c2410/debug-macro.S
@@ -92,11 +92,9 @@
 #if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
 #define fifo_full  fifo_full_s3c2410
 #define fifo_level fifo_level_s3c2410
-#warning 2410only
 #elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
 #define fifo_full  fifo_full_s3c24xx
 #define fifo_level fifo_level_s3c24xx
-#warning generic
 #endif
 
 /* include the reset of the code which will do the work */
diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
index c6e8d8f..4f291d9 100644
--- a/include/asm-arm/arch-s3c2410/dma.h
+++ b/include/asm-arm/arch-s3c2410/dma.h
@@ -214,6 +214,7 @@
 	unsigned long		 dev_addr;
 	unsigned long		 load_timeout;
 	unsigned int		 flags;		/* channel flags */
+	unsigned int		 hw_cfg;	/* last hw config */
 
 	struct s3c24xx_dma_map	*map;		/* channel hw maps */
 
diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h
index 6dadf58..29592c3 100644
--- a/include/asm-arm/arch-s3c2410/hardware.h
+++ b/include/asm-arm/arch-s3c2410/hardware.h
@@ -50,6 +50,17 @@
 
 extern int s3c2410_gpio_getirq(unsigned int pin);
 
+/* s3c2410_gpio_irq2pin
+ *
+ * turn the given irq number into the corresponding GPIO number
+ *
+ * returns:
+ *	< 0 = no pin
+ *	>=0 = gpio pin number
+*/
+
+extern int s3c2410_gpio_irq2pin(unsigned int irq);
+
 #ifdef CONFIG_CPU_S3C2400
 
 extern int s3c2400_gpio_getirq(unsigned int pin);
@@ -87,6 +98,18 @@
 
 extern void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
 
+/* s3c2410_gpio_getpull
+ *
+ * Read the state of the pull-up on a given pin
+ *
+ * return:
+ *	< 0 => error code
+ *	  0 => enabled
+ *	  1 => disabled
+*/
+
+extern int s3c2410_gpio_getpull(unsigned int pin);
+
 extern void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
 
 extern unsigned int s3c2410_gpio_getpin(unsigned int pin);
@@ -99,6 +122,11 @@
 
 #endif /* CONFIG_CPU_S3C2440 */
 
+#ifdef CONFIG_CPU_S3C2412
+
+extern int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state);
+
+#endif /* CONFIG_CPU_S3C2412 */
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
index 996f654..d858b3e 100644
--- a/include/asm-arm/arch-s3c2410/irqs.h
+++ b/include/asm-arm/arch-s3c2410/irqs.h
@@ -160,4 +160,7 @@
 #define NR_IRQS (IRQ_S3C2440_AC97+1)
 #endif
 
+/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
+#define FIQ_START		IRQ_EINT0
+
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
index e39656b..dba9df9 100644
--- a/include/asm-arm/arch-s3c2410/regs-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-clock.h
@@ -138,6 +138,8 @@
 #define S3C2412_CLKDIVN_PDIVN		(1<<2)
 #define S3C2412_CLKDIVN_HDIVN_MASK	(3<<0)
 #define S3C2421_CLKDIVN_ARMDIVN		(1<<3)
+#define S3C2412_CLKDIVN_DVSEN		(1<<4)
+#define S3C2412_CLKDIVN_HALFHCLK	(1<<5)
 #define S3C2412_CLKDIVN_USB48DIV	(1<<6)
 #define S3C2412_CLKDIVN_UARTDIV_MASK	(15<<8)
 #define S3C2412_CLKDIVN_UARTDIV_SHIFT	(8)
diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
index c074851..1235df7 100644
--- a/include/asm-arm/arch-s3c2410/regs-dsc.h
+++ b/include/asm-arm/arch-s3c2410/regs-dsc.h
@@ -19,7 +19,7 @@
 #define S3C2412_DSC1	   S3C2410_GPIOREG(0xe0)
 #endif
 
-#if defined(CONFIG_CPU_S3C2440)
+#if defined(CONFIG_CPU_S3C244X)
 
 #define S3C2440_DSC0	   S3C2410_GPIOREG(0xc4)
 #define S3C2440_DSC1	   S3C2410_GPIOREG(0xc8)
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index b693158..0ad75d7 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -1133,12 +1133,16 @@
 #define S3C2412_GPBSLPCON	S3C2410_GPIOREG(0x1C)
 #define S3C2412_GPCSLPCON	S3C2410_GPIOREG(0x2C)
 #define S3C2412_GPDSLPCON	S3C2410_GPIOREG(0x3C)
-#define S3C2412_GPESLPCON	S3C2410_GPIOREG(0x4C)
 #define S3C2412_GPFSLPCON	S3C2410_GPIOREG(0x5C)
 #define S3C2412_GPGSLPCON	S3C2410_GPIOREG(0x6C)
 #define S3C2412_GPHSLPCON	S3C2410_GPIOREG(0x7C)
 
 /* definitions for each pin bit */
+#define S3C2412_GPIO_SLPCON_LOW	 ( 0x00 )
+#define S3C2412_GPIO_SLPCON_HIGH ( 0x01 )
+#define S3C2412_GPIO_SLPCON_IN   ( 0x02 )
+#define S3C2412_GPIO_SLPCON_PULL ( 0x03 )
+
 #define S3C2412_SLPCON_LOW(x)	( 0x00 << ((x) * 2))
 #define S3C2412_SLPCON_HIGH(x)	( 0x01 << ((x) * 2))
 #define S3C2412_SLPCON_IN(x)	( 0x02 << ((x) * 2))
diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h
index e4d8234..312ff93 100644
--- a/include/asm-arm/arch-s3c2410/regs-mem.h
+++ b/include/asm-arm/arch-s3c2410/regs-mem.h
@@ -98,16 +98,19 @@
 #define S3C2410_BANKCON_Tacp3		(0x1 << 2)
 #define S3C2410_BANKCON_Tacp4		(0x2 << 2)
 #define S3C2410_BANKCON_Tacp6		(0x3 << 2)
+#define S3C2410_BANKCON_Tacp_SHIFT	(2)
 
 #define S3C2410_BANKCON_Tcah0		(0x0 << 4)
 #define S3C2410_BANKCON_Tcah1		(0x1 << 4)
 #define S3C2410_BANKCON_Tcah2		(0x2 << 4)
 #define S3C2410_BANKCON_Tcah4		(0x3 << 4)
+#define S3C2410_BANKCON_Tcah_SHIFT	(4)
 
 #define S3C2410_BANKCON_Tcoh0		(0x0 << 6)
 #define S3C2410_BANKCON_Tcoh1		(0x1 << 6)
 #define S3C2410_BANKCON_Tcoh2		(0x2 << 6)
 #define S3C2410_BANKCON_Tcoh4		(0x3 << 6)
+#define S3C2410_BANKCON_Tcoh_SHIFT	(6)
 
 #define S3C2410_BANKCON_Tacc1		(0x0 << 8)
 #define S3C2410_BANKCON_Tacc2		(0x1 << 8)
@@ -117,16 +120,19 @@
 #define S3C2410_BANKCON_Tacc8		(0x5 << 8)
 #define S3C2410_BANKCON_Tacc10		(0x6 << 8)
 #define S3C2410_BANKCON_Tacc14		(0x7 << 8)
+#define S3C2410_BANKCON_Tacc_SHIFT	(8)
 
 #define S3C2410_BANKCON_Tcos0		(0x0 << 11)
 #define S3C2410_BANKCON_Tcos1		(0x1 << 11)
 #define S3C2410_BANKCON_Tcos2		(0x2 << 11)
 #define S3C2410_BANKCON_Tcos4		(0x3 << 11)
+#define S3C2410_BANKCON_Tcos_SHIFT	(11)
 
 #define S3C2410_BANKCON_Tacs0		(0x0 << 13)
 #define S3C2410_BANKCON_Tacs1		(0x1 << 13)
 #define S3C2410_BANKCON_Tacs2		(0x2 << 13)
 #define S3C2410_BANKCON_Tacs4		(0x3 << 13)
+#define S3C2410_BANKCON_Tacs_SHIFT	(13)
 
 #define S3C2410_BANKCON_SRAM		(0x0 << 15)
 #define S3C2400_BANKCON_EDODRAM		(0x2 << 15)
diff --git a/include/asm-arm/arch-s3c2410/regs-power.h b/include/asm-arm/arch-s3c2410/regs-power.h
index f79987b..13d13b7 100644
--- a/include/asm-arm/arch-s3c2410/regs-power.h
+++ b/include/asm-arm/arch-s3c2410/regs-power.h
@@ -23,7 +23,8 @@
 #define S3C2412_INFORM2		S3C24XX_PWRREG(0x78)
 #define S3C2412_INFORM3		S3C24XX_PWRREG(0x7C)
 
-#define S3C2412_PWRCFG_BATF_IGNORE		(0<<0)
+#define S3C2412_PWRCFG_BATF_IRQ			(1<<0)
+#define S3C2412_PWRCFG_BATF_IGNORE		(2<<0)
 #define S3C2412_PWRCFG_BATF_SLEEP		(3<<0)
 #define S3C2412_PWRCFG_BATF_MASK		(3<<0)
 
diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
index 6389178..14de4e5 100644
--- a/include/asm-arm/arch-s3c2410/system.h
+++ b/include/asm-arm/arch-s3c2410/system.h
@@ -20,6 +20,9 @@
 #include <asm/plat-s3c/regs-watchdog.h>
 #include <asm/arch/regs-clock.h>
 
+#include <linux/clk.h>
+#include <linux/err.h>
+
 void (*s3c24xx_idle)(void);
 void (*s3c24xx_reset_hook)(void);
 
@@ -59,6 +62,8 @@
 static void
 arch_reset(char mode)
 {
+	struct clk *wdtclk;
+
 	if (mode == 's') {
 		cpu_reset(0);
 	}
@@ -70,19 +75,28 @@
 
 	__raw_writel(0, S3C2410_WTCON);	  /* disable watchdog, to be safe  */
 
+	wdtclk = clk_get(NULL, "watchdog");
+	if (!IS_ERR(wdtclk)) {
+		clk_enable(wdtclk);
+	} else
+		printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
+
 	/* put initial values into count and data */
-	__raw_writel(0x100, S3C2410_WTCNT);
-	__raw_writel(0x100, S3C2410_WTDAT);
+	__raw_writel(0x80, S3C2410_WTCNT);
+	__raw_writel(0x80, S3C2410_WTDAT);
 
 	/* set the watchdog to go and reset... */
 	__raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN |
 		     S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON);
 
 	/* wait for reset to assert... */
-	mdelay(5000);
+	mdelay(500);
 
 	printk(KERN_ERR "Watchdog reset failed to assert reset\n");
 
+	/* delay to allow the serial port to show the message */
+	mdelay(50);
+
 	/* we'll take a jump through zero as a poor second */
 	cpu_reset(0);
 }
diff --git a/include/asm-arm/fpstate.h b/include/asm-arm/fpstate.h
index f31cda5..392eb53 100644
--- a/include/asm-arm/fpstate.h
+++ b/include/asm-arm/fpstate.h
@@ -17,14 +17,18 @@
 /*
  * VFP storage area has:
  *  - FPEXC, FPSCR, FPINST and FPINST2.
- *  - 16 double precision data registers
- *  - an implementation-dependant word of state for FLDMX/FSTMX
+ *  - 16 or 32 double precision data registers
+ *  - an implementation-dependant word of state for FLDMX/FSTMX (pre-ARMv6)
  * 
  *  FPEXC will always be non-zero once the VFP has been used in this process.
  */
 
 struct vfp_hard_struct {
+#ifdef CONFIG_VFPv3
+	__u64 fpregs[32];
+#else
 	__u64 fpregs[16];
+#endif
 #if __LINUX_ARM_ARCH__ < 6
 	__u32 fpmx_state;
 #endif
@@ -35,6 +39,7 @@
 	 */
 	__u32 fpinst;
 	__u32 fpinst2;
+
 #ifdef CONFIG_SMP
 	__u32 cpu;
 #endif
diff --git a/include/asm-arm/kprobes.h b/include/asm-arm/kprobes.h
new file mode 100644
index 0000000..4e7bd32
--- /dev/null
+++ b/include/asm-arm/kprobes.h
@@ -0,0 +1,79 @@
+/*
+ * include/asm-arm/kprobes.h
+ *
+ * Copyright (C) 2006, 2007 Motorola Inc.
+ *
+ * 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.
+ */
+
+#ifndef _ARM_KPROBES_H
+#define _ARM_KPROBES_H
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+
+#define ARCH_SUPPORTS_KRETPROBES
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE			2
+#define MAX_STACK_SIZE			64	/* 32 would probably be OK */
+
+/*
+ * This undefined instruction must be unique and
+ * reserved solely for kprobes' use.
+ */
+#define KPROBE_BREAKPOINT_INSTRUCTION	0xe7f001f8
+
+#define regs_return_value(regs)		((regs)->ARM_r0)
+#define flush_insn_slot(p)		do { } while (0)
+#define kretprobe_blacklist_size	0
+
+typedef u32 kprobe_opcode_t;
+
+struct kprobe;
+typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
+
+/* Architecture specific copy of original instruction. */
+struct arch_specific_insn {
+	kprobe_opcode_t		*insn;
+	kprobe_insn_handler_t	*insn_handler;
+};
+
+struct prev_kprobe {
+	struct kprobe *kp;
+	unsigned int status;
+};
+
+/* per-cpu kprobe control block */
+struct kprobe_ctlblk {
+	unsigned int kprobe_status;
+	struct prev_kprobe prev_kprobe;
+	struct pt_regs jprobe_saved_regs;
+	char jprobes_stack[MAX_STACK_SIZE];
+};
+
+void arch_remove_kprobe(struct kprobe *);
+
+int kprobe_trap_handler(struct pt_regs *regs, unsigned int instr);
+int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
+int kprobe_exceptions_notify(struct notifier_block *self,
+			     unsigned long val, void *data);
+
+enum kprobe_insn {
+	INSN_REJECTED,
+	INSN_GOOD,
+	INSN_GOOD_NO_SLOT
+};
+
+enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
+					struct arch_specific_insn *);
+void __init arm_kprobe_decode_init(void);
+
+#endif /* _ARM_KPROBES_H */
diff --git a/include/asm-arm/plat-s3c24xx/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
index 2c59406..c78efe3 100644
--- a/include/asm-arm/plat-s3c24xx/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -32,6 +32,7 @@
 	struct s3c24xx_dma_addr  hw_addr;
 
 	unsigned long		 channels[S3C2410_DMA_CHANNELS];
+	unsigned long		 channels_rx[S3C2410_DMA_CHANNELS];
 };
 
 struct s3c24xx_dma_selection {
@@ -41,6 +42,10 @@
 
 	void	(*select)(struct s3c2410_dma_chan *chan,
 			  struct s3c24xx_dma_map *map);
+
+	void	(*direction)(struct s3c2410_dma_chan *chan,
+			     struct s3c24xx_dma_map *map,
+			     enum s3c2410_dmasrc dir);
 };
 
 extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
diff --git a/include/asm-arm/plat-s3c24xx/irq.h b/include/asm-arm/plat-s3c24xx/irq.h
index 8af6d95..45746a9 100644
--- a/include/asm-arm/plat-s3c24xx/irq.h
+++ b/include/asm-arm/plat-s3c24xx/irq.h
@@ -15,7 +15,9 @@
 
 #define EXTINT_OFF (IRQ_EINT4 - 4)
 
+/* these are exported for arch/arm/mach-* usage */
 extern struct irq_chip s3c_irq_level_chip;
+extern struct irq_chip s3c_irq_chip;
 
 static inline void
 s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
diff --git a/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h b/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
new file mode 100644
index 0000000..25d4058
--- /dev/null
+++ b/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
@@ -0,0 +1,72 @@
+/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
+ *
+ * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * 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.
+ *
+ * S3C2412 IIS register definition
+*/
+
+#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
+#define __ASM_ARCH_REGS_S3C2412_IIS_H
+
+#define S3C2412_IISCON			(0x00)
+#define S3C2412_IISMOD			(0x04)
+#define S3C2412_IISFIC			(0x08)
+#define S3C2412_IISPSR			(0x0C)
+#define S3C2412_IISTXD			(0x10)
+#define S3C2412_IISRXD			(0x14)
+
+#define S3C2412_IISCON_LRINDEX		(1 << 11)
+#define S3C2412_IISCON_TXFIFO_EMPTY	(1 << 10)
+#define S3C2412_IISCON_RXFIFO_EMPTY	(1 << 9)
+#define S3C2412_IISCON_TXFIFO_FULL	(1 << 8)
+#define S3C2412_IISCON_RXFIFO_FULL	(1 << 7)
+#define S3C2412_IISCON_TXDMA_PAUSE	(1 << 6)
+#define S3C2412_IISCON_RXDMA_PAUSE	(1 << 5)
+#define S3C2412_IISCON_TXCH_PAUSE	(1 << 4)
+#define S3C2412_IISCON_RXCH_PAUSE	(1 << 3)
+#define S3C2412_IISCON_TXDMA_ACTIVE	(1 << 2)
+#define S3C2412_IISCON_RXDMA_ACTIVE	(1 << 1)
+#define S3C2412_IISCON_IIS_ACTIVE	(1 << 0)
+
+#define S3C2412_IISMOD_MASTER_INTERNAL	(0 << 10)
+#define S3C2412_IISMOD_MASTER_EXTERNAL	(1 << 10)
+#define S3C2412_IISMOD_SLAVE		(2 << 10)
+#define S3C2412_IISMOD_MASTER_MASK	(3 << 10)
+#define S3C2412_IISMOD_MODE_TXONLY	(0 << 8)
+#define S3C2412_IISMOD_MODE_RXONLY	(1 << 8)
+#define S3C2412_IISMOD_MODE_TXRX	(2 << 8)
+#define S3C2412_IISMOD_MODE_MASK	(3 << 8)
+#define S3C2412_IISMOD_LR_LLOW		(0 << 7)
+#define S3C2412_IISMOD_LR_RLOW		(1 << 7)
+#define S3C2412_IISMOD_SDF_IIS		(0 << 5)
+#define S3C2412_IISMOD_SDF_MSB		(0 << 5)
+#define S3C2412_IISMOD_SDF_LSB		(0 << 5)
+#define S3C2412_IISMOD_SDF_MASK		(3 << 5)
+#define S3C2412_IISMOD_RCLK_256FS	(0 << 3)
+#define S3C2412_IISMOD_RCLK_512FS	(1 << 3)
+#define S3C2412_IISMOD_RCLK_384FS	(2 << 3)
+#define S3C2412_IISMOD_RCLK_768FS	(3 << 3)
+#define S3C2412_IISMOD_RCLK_MASK 	(3 << 3)
+#define S3C2412_IISMOD_BCLK_32FS	(0 << 1)
+#define S3C2412_IISMOD_BCLK_48FS	(1 << 1)
+#define S3C2412_IISMOD_BCLK_16FS	(2 << 1)
+#define S3C2412_IISMOD_BCLK_24FS	(3 << 1)
+#define S3C2412_IISMOD_BCLK_MASK	(3 << 1)
+#define S3C2412_IISMOD_8BIT		(1 << 0)
+
+#define S3C2412_IISPSR_PSREN		(1 << 15)
+
+#define S3C2412_IISFIC_TXFLUSH		(1 << 15)
+#define S3C2412_IISFIC_RXFLUSH		(1 << 7)
+#define S3C2412_IISFIC_TXCOUNT(x)	(((x) >>  8) & 0xf)
+#define S3C2412_IISFIC_RXCOUNT(x)	(((x) >>  0) & 0xf)
+
+
+
+#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
+
diff --git a/include/asm-arm/plat-s3c24xx/regs-spi.h b/include/asm-arm/plat-s3c24xx/regs-spi.h
index 4a499a1..ea565b0 100644
--- a/include/asm-arm/plat-s3c24xx/regs-spi.h
+++ b/include/asm-arm/plat-s3c24xx/regs-spi.h
@@ -17,6 +17,21 @@
 
 #define S3C2410_SPCON	(0x00)
 
+#define S3C2412_SPCON_RXFIFO_RB2	(0<<14)
+#define S3C2412_SPCON_RXFIFO_RB4	(1<<14)
+#define S3C2412_SPCON_RXFIFO_RB12	(2<<14)
+#define S3C2412_SPCON_RXFIFO_RB14	(3<<14)
+#define S3C2412_SPCON_TXFIFO_RB2	(0<<12)
+#define S3C2412_SPCON_TXFIFO_RB4	(1<<12)
+#define S3C2412_SPCON_TXFIFO_RB12	(2<<12)
+#define S3C2412_SPCON_TXFIFO_RB14	(3<<12)
+#define S3C2412_SPCON_RXFIFO_RESET	(1<<11) /* RxFIFO reset */
+#define S3C2412_SPCON_TXFIFO_RESET	(1<<10) /* TxFIFO reset */
+#define S3C2412_SPCON_RXFIFO_EN		(1<<9)  /* RxFIFO Enable */
+#define S3C2412_SPCON_TXFIFO_EN		(1<<8)  /* TxFIFO Enable */
+
+#define S3C2412_SPCON_DIRC_RX	  (1<<7)
+
 #define S3C2410_SPCON_SMOD_DMA	  (2<<5)	/* DMA mode */
 #define S3C2410_SPCON_SMOD_INT	  (1<<5)	/* interrupt mode */
 #define S3C2410_SPCON_SMOD_POLL   (0<<5)	/* polling mode */
@@ -34,10 +49,19 @@
 
 #define S3C2410_SPSTA	 (0x04)
 
+#define S3C2412_SPSTA_RXFIFO_AE		(1<<11)
+#define S3C2412_SPSTA_TXFIFO_AE		(1<<10)
+#define S3C2412_SPSTA_RXFIFO_ERROR	(1<<9)
+#define S3C2412_SPSTA_TXFIFO_ERROR	(1<<8)
+#define S3C2412_SPSTA_RXFIFO_FIFO	(1<<7)
+#define S3C2412_SPSTA_RXFIFO_EMPTY	(1<<6)
+#define S3C2412_SPSTA_TXFIFO_NFULL	(1<<5)
+#define S3C2412_SPSTA_TXFIFO_EMPTY	(1<<4)
+
 #define S3C2410_SPSTA_DCOL	  (1<<2)	/* Data Collision Error */
 #define S3C2410_SPSTA_MULD	  (1<<1)	/* Multi Master Error */
 #define S3C2410_SPSTA_READY	  (1<<0)	/* Data Tx/Rx ready */
-
+#define S3C2412_SPSTA_READY_ORG	  (1<<3)
 
 #define S3C2410_SPPIN	 (0x08)
 
@@ -46,9 +70,13 @@
 #define S3C2400_SPPIN_nCS     	  (1<<1)	/* SPI Card Select */
 #define S3C2410_SPPIN_KEEP	  (1<<0)	/* Master Out keep */
 
-
 #define S3C2410_SPPRE	 (0x0C)
 #define S3C2410_SPTDAT	 (0x10)
 #define S3C2410_SPRDAT	 (0x14)
 
+#define S3C2412_TXFIFO	 (0x18)
+#define S3C2412_RXFIFO	 (0x18)
+#define S3C2412_SPFIC	 (0x24)
+
+
 #endif /* __ASM_ARCH_REGS_SPI_H */
diff --git a/include/asm-arm/traps.h b/include/asm-arm/traps.h
index d4f34dc..f1541af 100644
--- a/include/asm-arm/traps.h
+++ b/include/asm-arm/traps.h
@@ -15,4 +15,13 @@
 void register_undef_hook(struct undef_hook *hook);
 void unregister_undef_hook(struct undef_hook *hook);
 
+static inline int in_exception_text(unsigned long ptr)
+{
+	extern char __exception_text_start[];
+	extern char __exception_text_end[];
+
+	return ptr >= (unsigned long)&__exception_text_start &&
+	       ptr < (unsigned long)&__exception_text_end;
+}
+
 #endif
diff --git a/include/asm-arm/vfp.h b/include/asm-arm/vfp.h
index bd6be9d..5f9a2cb 100644
--- a/include/asm-arm/vfp.h
+++ b/include/asm-arm/vfp.h
@@ -7,7 +7,11 @@
 
 #define FPSID			cr0
 #define FPSCR			cr1
+#define MVFR1			cr6
+#define MVFR0			cr7
 #define FPEXC			cr8
+#define FPINST			cr9
+#define FPINST2			cr10
 
 /* FPSID bits */
 #define FPSID_IMPLEMENTER_BIT	(24)
@@ -28,6 +32,19 @@
 /* FPEXC bits */
 #define FPEXC_EX		(1 << 31)
 #define FPEXC_EN		(1 << 30)
+#define FPEXC_DEX		(1 << 29)
+#define FPEXC_FP2V		(1 << 28)
+#define FPEXC_VV		(1 << 27)
+#define FPEXC_TFV		(1 << 26)
+#define FPEXC_LENGTH_BIT	(8)
+#define FPEXC_LENGTH_MASK	(7 << FPEXC_LENGTH_BIT)
+#define FPEXC_IDF		(1 << 7)
+#define FPEXC_IXF		(1 << 4)
+#define FPEXC_UFF		(1 << 3)
+#define FPEXC_OFF		(1 << 2)
+#define FPEXC_DZF		(1 << 1)
+#define FPEXC_IOF		(1 << 0)
+#define FPEXC_TRAP_MASK		(FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
 
 /* FPSCR bits */
 #define FPSCR_DEFAULT_NAN	(1<<25)
@@ -55,20 +72,9 @@
 #define FPSCR_IXC		(1<<4)
 #define FPSCR_IDC		(1<<7)
 
-/*
- * VFP9-S specific.
- */
-#define FPINST			cr9
-#define FPINST2			cr10
-
-/* FPEXC bits */
-#define FPEXC_FPV2		(1<<28)
-#define FPEXC_LENGTH_BIT	(8)
-#define FPEXC_LENGTH_MASK	(7 << FPEXC_LENGTH_BIT)
-#define FPEXC_INV		(1 << 7)
-#define FPEXC_UFC		(1 << 3)
-#define FPEXC_OFC		(1 << 2)
-#define FPEXC_IOC		(1 << 0)
+/* MVFR0 bits */
+#define MVFR0_A_SIMD_BIT	(0)
+#define MVFR0_A_SIMD_MASK	(0xf << MVFR0_A_SIMD_BIT)
 
 /* Bit patterns for decoding the packaged operation descriptors */
 #define VFPOPDESC_LENGTH_BIT	(9)
diff --git a/include/asm-arm/vfpmacros.h b/include/asm-arm/vfpmacros.h
index 27fe028..cccb389 100644
--- a/include/asm-arm/vfpmacros.h
+++ b/include/asm-arm/vfpmacros.h
@@ -15,19 +15,33 @@
 	.endm
 
 	@ read all the working registers back into the VFP
-	.macro	VFPFLDMIA, base
+	.macro	VFPFLDMIA, base, tmp
 #if __LINUX_ARM_ARCH__ < 6
 	LDC	p11, cr0, [\base],#33*4		    @ FLDMIAX \base!, {d0-d15}
 #else
 	LDC	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d0-d15}
 #endif
+#ifdef CONFIG_VFPv3
+	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
+	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
+	cmp	\tmp, #2			    @ 32 x 64bit registers?
+	ldceql	p11, cr0, [\base],#32*4		    @ FLDMIAD \base!, {d16-d31}
+	addne	\base, \base, #32*4		    @ step over unused register space
+#endif
 	.endm
 
 	@ write all the working registers out of the VFP
-	.macro	VFPFSTMIA, base
+	.macro	VFPFSTMIA, base, tmp
 #if __LINUX_ARM_ARCH__ < 6
 	STC	p11, cr0, [\base],#33*4		    @ FSTMIAX \base!, {d0-d15}
 #else
 	STC	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d0-d15}
 #endif
+#ifdef CONFIG_VFPv3
+	VFPFMRX	\tmp, MVFR0			    @ Media and VFP Feature Register 0
+	and	\tmp, \tmp, #MVFR0_A_SIMD_MASK	    @ A_SIMD field
+	cmp	\tmp, #2			    @ 32 x 64bit registers?
+	stceql	p11, cr0, [\base],#32*4		    @ FSTMIAD \base!, {d16-d31}
+	addne	\base, \base, #32*4		    @ step over unused register space
+#endif
 	.endm
diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
index 0dc2026..44d0bfa 100644
--- a/include/asm-avr32/arch-at32ap/cpu.h
+++ b/include/asm-avr32/arch-at32ap/cpu.h
@@ -30,5 +30,6 @@
 #define cpu_is_at91sam9261()	(0)
 #define cpu_is_at91sam9263()	(0)
 #define cpu_is_at91sam9rl()	(0)
+#define cpu_is_at91cap9()	(0)
 
 #endif /* __ASM_ARCH_CPU_H */
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
index 39bdd86..6ae0619 100644
--- a/include/asm-blackfin/bfin-global.h
+++ b/include/asm-blackfin/bfin-global.h
@@ -51,7 +51,7 @@
 extern unsigned long usecs_to_sclk(unsigned long usecs);
 
 extern void dump_bfin_process(struct pt_regs *regs);
-extern void dump_bfin_mem(void *retaddr);
+extern void dump_bfin_mem(struct pt_regs *regs);
 extern void dump_bfin_trace_buffer(void);
 
 extern int init_arch_irq(void);
diff --git a/include/asm-blackfin/cplb-mpu.h b/include/asm-blackfin/cplb-mpu.h
new file mode 100644
index 0000000..75c67b9
--- /dev/null
+++ b/include/asm-blackfin/cplb-mpu.h
@@ -0,0 +1,61 @@
+/*
+ * File:         include/asm-blackfin/cplbinit.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef __ASM_BFIN_CPLB_MPU_H
+#define __ASM_BFIN_CPLB_MPU_H
+
+struct cplb_entry {
+	unsigned long data, addr;
+};
+
+struct mem_region {
+	unsigned long start, end;
+	unsigned long dcplb_data;
+	unsigned long icplb_data;
+};
+
+extern struct cplb_entry dcplb_tbl[MAX_CPLBS];
+extern struct cplb_entry icplb_tbl[MAX_CPLBS];
+extern int first_switched_icplb;
+extern int first_mask_dcplb;
+extern int first_switched_dcplb;
+
+extern int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
+extern int nr_cplb_flush;
+
+extern int page_mask_order;
+extern int page_mask_nelts;
+
+extern unsigned long *current_rwx_mask;
+
+extern void flush_switched_cplbs(void);
+extern void set_mask_dcplbs(unsigned long *);
+
+extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *);
+
+#endif /* __ASM_BFIN_CPLB_MPU_H */
diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
index 06828d7..654375c 100644
--- a/include/asm-blackfin/cplb.h
+++ b/include/asm-blackfin/cplb.h
@@ -65,7 +65,11 @@
 #define SIZE_1M 0x00100000      /* 1M */
 #define SIZE_4M 0x00400000      /* 4M */
 
+#ifdef CONFIG_MPU
+#define MAX_CPLBS 16
+#else
 #define MAX_CPLBS (16 * 2)
+#endif
 
 #define ASYNC_MEMORY_CPLB_COVERAGE	((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
 				 ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
index c4d0596..0eb1c1b 100644
--- a/include/asm-blackfin/cplbinit.h
+++ b/include/asm-blackfin/cplbinit.h
@@ -33,6 +33,12 @@
 #include <asm/blackfin.h>
 #include <asm/cplb.h>
 
+#ifdef CONFIG_MPU
+
+#include <asm/cplb-mpu.h>
+
+#else
+
 #define INITIAL_T 0x1
 #define SWITCH_T  0x2
 #define I_CPLB    0x4
@@ -79,6 +85,8 @@
 extern u_long dpdt_swapcount_table[];
 #endif
 
+#endif /* CONFIG_MPU */
+
 extern unsigned long reserved_mem_dcache_on;
 extern unsigned long reserved_mem_icache_on;
 
diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
index b469505..5abaa2c 100644
--- a/include/asm-blackfin/dma.h
+++ b/include/asm-blackfin/dma.h
@@ -76,6 +76,9 @@
 #define INTR_ON_BUF    2
 #define INTR_ON_ROW    3
 
+#define DMA_NOSYNC_KEEP_DMA_BUF	0
+#define DMA_SYNC_RESTART	1
+
 struct dmasg {
 	unsigned long next_desc_addr;
 	unsigned long start_addr;
@@ -157,7 +160,8 @@
 void set_dma_y_modify(unsigned int channel, short y_modify);
 void set_dma_config(unsigned int channel, unsigned short config);
 unsigned short set_bfin_dma_config(char direction, char flow_mode,
-				   char intr_mode, char dma_mode, char width);
+				   char intr_mode, char dma_mode, char width,
+				   char syncmode);
 void set_dma_curr_addr(unsigned int channel, unsigned long addr);
 
 /* get curr status for polling */
diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
index 33ce98e..d0426c1 100644
--- a/include/asm-blackfin/gpio.h
+++ b/include/asm-blackfin/gpio.h
@@ -7,7 +7,7 @@
  * Description:
  *
  * Modified:
- *               Copyright 2004-2006 Analog Devices Inc.
+ *               Copyright 2004-2008 Analog Devices Inc.
  *
  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
  *
@@ -304,39 +304,39 @@
 **************************************************************/
 
 #ifndef BF548_FAMILY
-void set_gpio_dir(unsigned short, unsigned short);
-void set_gpio_inen(unsigned short, unsigned short);
-void set_gpio_polar(unsigned short, unsigned short);
-void set_gpio_edge(unsigned short, unsigned short);
-void set_gpio_both(unsigned short, unsigned short);
-void set_gpio_data(unsigned short, unsigned short);
-void set_gpio_maska(unsigned short, unsigned short);
-void set_gpio_maskb(unsigned short, unsigned short);
-void set_gpio_toggle(unsigned short);
-void set_gpiop_dir(unsigned short, unsigned short);
-void set_gpiop_inen(unsigned short, unsigned short);
-void set_gpiop_polar(unsigned short, unsigned short);
-void set_gpiop_edge(unsigned short, unsigned short);
-void set_gpiop_both(unsigned short, unsigned short);
-void set_gpiop_data(unsigned short, unsigned short);
-void set_gpiop_maska(unsigned short, unsigned short);
-void set_gpiop_maskb(unsigned short, unsigned short);
-unsigned short get_gpio_dir(unsigned short);
-unsigned short get_gpio_inen(unsigned short);
-unsigned short get_gpio_polar(unsigned short);
-unsigned short get_gpio_edge(unsigned short);
-unsigned short get_gpio_both(unsigned short);
-unsigned short get_gpio_maska(unsigned short);
-unsigned short get_gpio_maskb(unsigned short);
-unsigned short get_gpio_data(unsigned short);
-unsigned short get_gpiop_dir(unsigned short);
-unsigned short get_gpiop_inen(unsigned short);
-unsigned short get_gpiop_polar(unsigned short);
-unsigned short get_gpiop_edge(unsigned short);
-unsigned short get_gpiop_both(unsigned short);
-unsigned short get_gpiop_maska(unsigned short);
-unsigned short get_gpiop_maskb(unsigned short);
-unsigned short get_gpiop_data(unsigned short);
+void set_gpio_dir(unsigned, unsigned short);
+void set_gpio_inen(unsigned, unsigned short);
+void set_gpio_polar(unsigned, unsigned short);
+void set_gpio_edge(unsigned, unsigned short);
+void set_gpio_both(unsigned, unsigned short);
+void set_gpio_data(unsigned, unsigned short);
+void set_gpio_maska(unsigned, unsigned short);
+void set_gpio_maskb(unsigned, unsigned short);
+void set_gpio_toggle(unsigned);
+void set_gpiop_dir(unsigned, unsigned short);
+void set_gpiop_inen(unsigned, unsigned short);
+void set_gpiop_polar(unsigned, unsigned short);
+void set_gpiop_edge(unsigned, unsigned short);
+void set_gpiop_both(unsigned, unsigned short);
+void set_gpiop_data(unsigned, unsigned short);
+void set_gpiop_maska(unsigned, unsigned short);
+void set_gpiop_maskb(unsigned, unsigned short);
+unsigned short get_gpio_dir(unsigned);
+unsigned short get_gpio_inen(unsigned);
+unsigned short get_gpio_polar(unsigned);
+unsigned short get_gpio_edge(unsigned);
+unsigned short get_gpio_both(unsigned);
+unsigned short get_gpio_maska(unsigned);
+unsigned short get_gpio_maskb(unsigned);
+unsigned short get_gpio_data(unsigned);
+unsigned short get_gpiop_dir(unsigned);
+unsigned short get_gpiop_inen(unsigned);
+unsigned short get_gpiop_polar(unsigned);
+unsigned short get_gpiop_edge(unsigned);
+unsigned short get_gpiop_both(unsigned);
+unsigned short get_gpiop_maska(unsigned);
+unsigned short get_gpiop_maskb(unsigned);
+unsigned short get_gpiop_data(unsigned);
 
 struct gpio_port_t {
 	unsigned short data;
@@ -382,8 +382,8 @@
 #define PM_WAKE_LOW	0x8
 #define PM_WAKE_BOTH_EDGES	(PM_WAKE_RISING | PM_WAKE_FALLING)
 
-int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type);
-void gpio_pm_wakeup_free(unsigned short gpio);
+int gpio_pm_wakeup_request(unsigned gpio, unsigned char type);
+void gpio_pm_wakeup_free(unsigned gpio);
 unsigned int gpio_pm_setup(void);
 void gpio_pm_restore(void);
 
@@ -426,19 +426,19 @@
 * MODIFICATION HISTORY :
 **************************************************************/
 
-int gpio_request(unsigned short, const char *);
-void gpio_free(unsigned short);
+int gpio_request(unsigned, const char *);
+void gpio_free(unsigned);
 
-void gpio_set_value(unsigned short gpio, unsigned short arg);
-unsigned short gpio_get_value(unsigned short gpio);
+void gpio_set_value(unsigned gpio, int arg);
+int gpio_get_value(unsigned gpio);
 
 #ifndef BF548_FAMILY
 #define gpio_get_value(gpio) 		get_gpio_data(gpio)
 #define gpio_set_value(gpio, value)	set_gpio_data(gpio, value)
 #endif
 
-void gpio_direction_input(unsigned short gpio);
-void gpio_direction_output(unsigned short gpio);
+int gpio_direction_input(unsigned gpio);
+int gpio_direction_output(unsigned gpio, int value);
 
 #include <asm-generic/gpio.h>		/* cansleep wrappers */
 #include <asm/irq.h>
diff --git a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
index 0b867e6..15dbc21 100644
--- a/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
@@ -146,7 +146,7 @@
 
 	if (uart->rts_pin >= 0) {
 		gpio_request(uart->rts_pin, DRIVER_NAME);
-		gpio_direction_output(uart->rts_pin);
+		gpio_direction_output(uart->rts_pin, 0);
 	}
 #endif
 }
diff --git a/include/asm-blackfin/mach-bf527/portmux.h b/include/asm-blackfin/mach-bf527/portmux.h
index dcf001a..ae4d205 100644
--- a/include/asm-blackfin/mach-bf527/portmux.h
+++ b/include/asm-blackfin/mach-bf527/portmux.h
@@ -1,6 +1,8 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
+
 #define P_PPI0_D0	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
 #define P_PPI0_D1	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
 #define P_PPI0_D2	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
index f36ff5af..98209d4 100644
--- a/include/asm-blackfin/mach-bf533/anomaly.h
+++ b/include/asm-blackfin/mach-bf533/anomaly.h
@@ -7,9 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision X,  March 23, 2007; ADSP-BF533 Blackfin Processor Anomaly List
- *  - Revision AB, March 23, 2007; ADSP-BF532 Blackfin Processor Anomaly List
- *  - Revision W,  March 23, 2007; ADSP-BF531 Blackfin Processor Anomaly List
+ *  - Revision B, 12/10/2007; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -17,7 +15,7 @@
 
 /* We do not support 0.1 or 0.2 silicon - sorry */
 #if __SILICON_REVISION__ < 3
-# error Kernel will not work on BF533 silicon version 0.0, 0.1, or 0.2
+# error will not work on BF533 silicon version 0.0, 0.1, or 0.2
 #endif
 
 #if defined(__ADSPBF531__)
@@ -251,6 +249,12 @@
 #define ANOMALY_05000192 (__SILICON_REVISION__ < 3)
 /* Internal Voltage Regulator may not start up */
 #define ANOMALY_05000206 (__SILICON_REVISION__ < 3)
+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
+#define ANOMALY_05000357 (1)
+/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
+#define ANOMALY_05000366 (1)
+/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
+#define ANOMALY_05000371 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000266 (0)
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
index 69b9f8e..7871d43 100644
--- a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -111,7 +111,7 @@
 	}
 	if (uart->rts_pin >= 0) {
 		gpio_request(uart->rts_pin, DRIVER_NAME);
-		gpio_direction_input(uart->rts_pin);
+		gpio_direction_input(uart->rts_pin, 0);
 	}
 #endif
 }
diff --git a/include/asm-blackfin/mach-bf533/portmux.h b/include/asm-blackfin/mach-bf533/portmux.h
index 137f488..685a265 100644
--- a/include/asm-blackfin/mach-bf533/portmux.h
+++ b/include/asm-blackfin/mach-bf533/portmux.h
@@ -1,6 +1,8 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
+
 #define P_PPI0_CLK	(P_DONTCARE)
 #define P_PPI0_FS1	(P_DONTCARE)
 #define P_PPI0_FS2	(P_DONTCARE)
diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
index 2b66ecf..746a794 100644
--- a/include/asm-blackfin/mach-bf537/anomaly.h
+++ b/include/asm-blackfin/mach-bf537/anomaly.h
@@ -7,9 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision M, March 13, 2007; ADSP-BF537 Blackfin Processor Anomaly List
- *  - Revision L, March 13, 2007; ADSP-BF536 Blackfin Processor Anomaly List
- *  - Revision M, March 13, 2007; ADSP-BF534 Blackfin Processor Anomaly List
+ *  - Revision A, 09/04/2007; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -17,7 +15,7 @@
 
 /* We do not support 0.1 silicon - sorry */
 #if __SILICON_REVISION__ < 2
-# error Kernel will not work on BF537 silicon version 0.0 or 0.1
+# error will not work on BF537 silicon version 0.0 or 0.1
 #endif
 
 #if defined(__ADSPBF534__)
@@ -44,6 +42,8 @@
 #define ANOMALY_05000122 (1)
 /* Killed 32-bit MMR write leads to next system MMR access thinking it should be 32-bit */
 #define ANOMALY_05000157 (__SILICON_REVISION__ < 2)
+/* Turning SPORTs on while External Frame Sync Is Active May Corrupt Data */
+#define ANOMALY_05000167 (1)
 /* PPI_DELAY not functional in PPI modes with 0 frame syncs */
 #define ANOMALY_05000180 (1)
 /* Instruction Cache Is Not Functional */
@@ -130,6 +130,12 @@
 #define ANOMALY_05000321 (__SILICON_REVISION__ < 3)
 /* EMAC RMII mode at 10-Base-T speed: RX frames not received properly */
 #define ANOMALY_05000322 (1)
+/* Ethernet MAC MDIO Reads Do Not Meet IEEE Specification */
+#define ANOMALY_05000341 (__SILICON_REVISION__ >= 3)
+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
+#define ANOMALY_05000357 (1)
+/* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
+#define ANOMALY_05000359 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
index 6fb328f..86e45c3 100644
--- a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -146,7 +146,7 @@
 
 	if (uart->rts_pin >= 0) {
 		gpio_request(uart->rts_pin, DRIVER_NAME);
-		gpio_direction_output(uart->rts_pin);
+		gpio_direction_output(uart->rts_pin, 0);
 	}
 #endif
 }
diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h
index 5a3f7d3b..78fee6e 100644
--- a/include/asm-blackfin/mach-bf537/portmux.h
+++ b/include/asm-blackfin/mach-bf537/portmux.h
@@ -1,6 +1,8 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
+#define MAX_RESOURCES 	(MAX_BLACKFIN_GPIOS + GPIO_BANKSIZE)	/* We additionally handle PORTJ */
+
 #define P_UART0_TX	(P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
 #define P_UART0_RX	(P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
 #define P_UART1_TX	(P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h
index c5b6375..850dc12 100644
--- a/include/asm-blackfin/mach-bf548/anomaly.h
+++ b/include/asm-blackfin/mach-bf548/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision C, July 16, 2007; ADSP-BF549 Silicon Anomaly List
+ *  - Revision E, 11/28/2007; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -26,47 +26,59 @@
 /* Certain Data Cache Writethrough Modes Fail for Vddint <= 0.9V */
 #define ANOMALY_05000272 (1)
 /* False Hardware Error Exception when ISR context is not restored */
-#define ANOMALY_05000281 (1)
+#define ANOMALY_05000281 (__SILICON_REVISION__ < 1)
 /* SSYNCs After Writes To CAN/DMA MMR Registers Are Not Always Handled Correctly */
-#define ANOMALY_05000304 (1)
+#define ANOMALY_05000304 (__SILICON_REVISION__ < 1)
 /* False Hardware Errors Caused by Fetches at the Boundary of Reserved Memory */
 #define ANOMALY_05000310 (1)
 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted */
-#define ANOMALY_05000312 (1)
+#define ANOMALY_05000312 (__SILICON_REVISION__ < 1)
 /* TWI Slave Boot Mode Is Not Functional */
-#define ANOMALY_05000324 (1)
+#define ANOMALY_05000324 (__SILICON_REVISION__ < 1)
 /* External FIFO Boot Mode Is Not Functional */
-#define ANOMALY_05000325 (1)
+#define ANOMALY_05000325 (__SILICON_REVISION__ < 1)
 /* Data Lost When Core and DMA Accesses Are Made to the USB FIFO Simultaneously */
-#define ANOMALY_05000327 (1)
+#define ANOMALY_05000327 (__SILICON_REVISION__ < 1)
 /* Incorrect Access of OTP_STATUS During otp_write() Function */
-#define ANOMALY_05000328 (1)
+#define ANOMALY_05000328 (__SILICON_REVISION__ < 1)
 /* Synchronous Burst Flash Boot Mode Is Not Functional */
-#define ANOMALY_05000329 (1)
+#define ANOMALY_05000329 (__SILICON_REVISION__ < 1)
 /* Host DMA Boot Mode Is Not Functional */
-#define ANOMALY_05000330 (1)
+#define ANOMALY_05000330 (__SILICON_REVISION__ < 1)
 /* Inadequate Timing Margins on DDR DQS to DQ and DQM Skew */
-#define ANOMALY_05000334 (1)
+#define ANOMALY_05000334 (__SILICON_REVISION__ < 1)
 /* Inadequate Rotary Debounce Logic Duration */
-#define ANOMALY_05000335 (1)
+#define ANOMALY_05000335 (__SILICON_REVISION__ < 1)
 /* Phantom Interrupt Occurs After First Configuration of Host DMA Port */
-#define ANOMALY_05000336 (1)
+#define ANOMALY_05000336 (__SILICON_REVISION__ < 1)
 /* Disallowed Configuration Prevents Subsequent Allowed Configuration on Host DMA Port */
-#define ANOMALY_05000337 (1)
+#define ANOMALY_05000337 (__SILICON_REVISION__ < 1)
 /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */
-#define ANOMALY_05000338 (1)
+#define ANOMALY_05000338 (__SILICON_REVISION__ < 1)
 /* If Memory Reads Are Enabled on SDH or HOSTDP, Other DMAC1 Peripherals Cannot Read */
-#define ANOMALY_05000340 (1)
+#define ANOMALY_05000340 (__SILICON_REVISION__ < 1)
 /* Boot Host Wait (HWAIT) and Boot Host Wait Alternate (HWAITA) Signals Are Swapped */
-#define ANOMALY_05000344 (1)
+#define ANOMALY_05000344 (__SILICON_REVISION__ < 1)
 /* USB Calibration Value Is Not Intialized */
-#define ANOMALY_05000346 (1)
+#define ANOMALY_05000346 (__SILICON_REVISION__ < 1)
 /* Boot ROM Kernel Incorrectly Alters Reset Value of USB Register */
-#define ANOMALY_05000347 (1)
+#define ANOMALY_05000347 (__SILICON_REVISION__ < 1)
 /* Data Lost when Core Reads SDH Data FIFO */
-#define ANOMALY_05000349 (1)
+#define ANOMALY_05000349 (__SILICON_REVISION__ < 1)
 /* PLL Status Register Is Inaccurate */
-#define ANOMALY_05000351 (1)
+#define ANOMALY_05000351 (__SILICON_REVISION__ < 1)
+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
+#define ANOMALY_05000357 (1)
+/* External Memory Read Access Hangs Core With PLL Bypass */
+#define ANOMALY_05000360 (1)
+/* DMAs that Go Urgent during Tight Core Writes to External Memory Are Blocked */
+#define ANOMALY_05000365 (1)
+/* Addressing Conflict between Boot ROM and Asynchronous Memory */
+#define ANOMALY_05000369 (1)
+/* Mobile DDR Operation Not Functional */
+#define ANOMALY_05000377 (1)
+/* Security/Authentication Speedpath Causes Authentication To Fail To Initiate */
+#define ANOMALY_05000378 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000125 (0)
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
index f21a162..3770aa3 100644
--- a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
@@ -186,7 +186,7 @@
 
 	if (uart->rts_pin >= 0) {
 		gpio_request(uart->rts_pin, DRIVER_NAME);
-		gpio_direction_output(uart->rts_pin);
+		gpio_direction_output(uart->rts_pin, 0);
 	}
 #endif
 }
diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
index aefab3f..19ddcd8 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
@@ -244,39 +244,6 @@
 #define bfin_read_TWI0_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
 #define bfin_write_TWI0_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
 
-#define bfin_read_TWI_CLKDIV()			bfin_read16(TWI0_CLKDIV)
-#define bfin_write_TWI_CLKDIV(val)		bfin_write16(TWI0_CLKDIV, val)
-#define bfin_read_TWI_CONTROL()			bfin_read16(TWI0_CONTROL)
-#define bfin_write_TWI_CONTROL(val)		bfin_write16(TWI0_CONTROL, val)
-#define bfin_read_TWI_SLAVE_CTRL()		bfin_read16(TWI0_SLAVE_CTRL)
-#define bfin_write_TWI_SLAVE_CTRL(val)		bfin_write16(TWI0_SLAVE_CTRL, val)
-#define bfin_read_TWI_SLAVE_STAT()		bfin_read16(TWI0_SLAVE_STAT)
-#define bfin_write_TWI_SLAVE_STAT(val)		bfin_write16(TWI0_SLAVE_STAT, val)
-#define bfin_read_TWI_SLAVE_ADDR()		bfin_read16(TWI0_SLAVE_ADDR)
-#define bfin_write_TWI_SLAVE_ADDR(val)		bfin_write16(TWI0_SLAVE_ADDR, val)
-#define bfin_read_TWI_MASTER_CTL()		bfin_read16(TWI0_MASTER_CTRL)
-#define bfin_write_TWI_MASTER_CTL(val)		bfin_write16(TWI0_MASTER_CTRL, val)
-#define bfin_read_TWI_MASTER_STAT()		bfin_read16(TWI0_MASTER_STAT)
-#define bfin_write_TWI_MASTER_STAT(val)		bfin_write16(TWI0_MASTER_STAT, val)
-#define bfin_read_TWI_MASTER_ADDR()		bfin_read16(TWI0_MASTER_ADDR)
-#define bfin_write_TWI_MASTER_ADDR(val)		bfin_write16(TWI0_MASTER_ADDR, val)
-#define bfin_read_TWI_INT_STAT()		bfin_read16(TWI0_INT_STAT)
-#define bfin_write_TWI_INT_STAT(val)		bfin_write16(TWI0_INT_STAT, val)
-#define bfin_read_TWI_INT_MASK()		bfin_read16(TWI0_INT_MASK)
-#define bfin_write_TWI_INT_MASK(val)		bfin_write16(TWI0_INT_MASK, val)
-#define bfin_read_TWI_FIFO_CTL()		bfin_read16(TWI0_FIFO_CTRL)
-#define bfin_write_TWI_FIFO_CTL(val)		bfin_write16(TWI0_FIFO_CTRL, val)
-#define bfin_read_TWI_FIFO_STAT()		bfin_read16(TWI0_FIFO_STAT)
-#define bfin_write_TWI_FIFO_STAT(val)		bfin_write16(TWI0_FIFO_STAT, val)
-#define bfin_read_TWI_XMT_DATA8()		bfin_read16(TWI0_XMT_DATA8)
-#define bfin_write_TWI_XMT_DATA8(val)		bfin_write16(TWI0_XMT_DATA8, val)
-#define bfin_read_TWI_XMT_DATA16()		bfin_read16(TWI0_XMT_DATA16)
-#define bfin_write_TWI_XMT_DATA16(val)		bfin_write16(TWI0_XMT_DATA16, val)
-#define bfin_read_TWI_RCV_DATA8()		bfin_read16(TWI0_RCV_DATA8)
-#define bfin_write_TWI_RCV_DATA8(val)		bfin_write16(TWI0_RCV_DATA8, val)
-#define bfin_read_TWI_RCV_DATA16()		bfin_read16(TWI0_RCV_DATA16)
-#define bfin_write_TWI_RCV_DATA16(val)		bfin_write16(TWI0_RCV_DATA16, val)
-
 /* SPORT0 is not defined in the shared file because it is not available on the ADSP-BF542 and ADSP-BF544 bfin_read_()rocessors */
 
 /* SPORT1 Registers */
diff --git a/include/asm-blackfin/mach-bf548/defBF542.h b/include/asm-blackfin/mach-bf548/defBF542.h
index 32d0713..a7c809f 100644
--- a/include/asm-blackfin/mach-bf548/defBF542.h
+++ b/include/asm-blackfin/mach-bf548/defBF542.h
@@ -432,8 +432,8 @@
 
 #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
 #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
-#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
-#define               DAT_TIMEOUT  0x8        /* Data Time Out */
+#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
+#define               DAT_TIME_OUT  0x8        /* Data Time Out */
 #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
 #define                RX_OVERRUN  0x20       /* Receive Overrun */
 #define              CMD_RESP_END  0x40       /* CMD Response End */
diff --git a/include/asm-blackfin/mach-bf548/defBF548.h b/include/asm-blackfin/mach-bf548/defBF548.h
index ecbca95..e46f568 100644
--- a/include/asm-blackfin/mach-bf548/defBF548.h
+++ b/include/asm-blackfin/mach-bf548/defBF548.h
@@ -1095,8 +1095,8 @@
 
 #define              CMD_CRC_FAIL  0x1        /* CMD CRC Fail */
 #define              DAT_CRC_FAIL  0x2        /* Data CRC Fail */
-#define               CMD_TIMEOUT  0x4        /* CMD Time Out */
-#define               DAT_TIMEOUT  0x8        /* Data Time Out */
+#define               CMD_TIME_OUT  0x4        /* CMD Time Out */
+#define               DAT_TIME_OUT  0x8        /* Data Time Out */
 #define               TX_UNDERRUN  0x10       /* Transmit Underrun */
 #define                RX_OVERRUN  0x20       /* Receive Overrun */
 #define              CMD_RESP_END  0x40       /* CMD Response End */
diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h
index 319a485..08f90c2 100644
--- a/include/asm-blackfin/mach-bf548/defBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h
@@ -1772,17 +1772,36 @@
 #define                       TRP  0x3c0000   /* Pre charge-to-active command period */
 #define                      TRAS  0x3c00000  /* Min Active-to-pre charge time */
 #define                       TRC  0x3c000000 /* Active-to-active time */
+#define DDR_TRAS(x)		((x<<22)&TRAS)	/* DDR tRAS = (1~15) cycles */
+#define DDR_TRP(x)		((x<<18)&TRP)	/* DDR tRP = (1~15) cycles */
+#define DDR_TRC(x)		((x<<26)&TRC)	/* DDR tRC = (1~15) cycles */
+#define DDR_TRFC(x)		((x<<14)&TRFC)	/* DDR tRFC = (1~15) cycles */
+#define DDR_TREFI(x)		(x&TREFI)	/* DDR tRFC = (1~15) cycles */
 
 /* Bit masks for EBIU_DDRCTL1 */
 
 #define                      TRCD  0xf        /* Active-to-Read/write delay */
-#define                       MRD  0xf0       /* Mode register set to active */
+#define                      TMRD  0xf0       /* Mode register set to active */
 #define                       TWR  0x300      /* Write Recovery time */
 #define               DDRDATWIDTH  0x3000     /* DDR data width */
 #define                  EXTBANKS  0xc000     /* External banks */
 #define               DDRDEVWIDTH  0x30000    /* DDR device width */
 #define                DDRDEVSIZE  0xc0000    /* DDR device size */
-#define                     TWWTR  0xf0000000 /* Write-to-read delay */
+#define                      TWTR  0xf0000000 /* Write-to-read delay */
+#define DDR_TWTR(x)		((x<<28)&TWTR)	/* DDR tWTR = (1~15) cycles */
+#define DDR_TMRD(x)		((x<<4)&TMRD)	/* DDR tMRD = (1~15) cycles */
+#define DDR_TWR(x)		((x<<8)&TWR)	/* DDR tWR = (1~15) cycles */
+#define DDR_TRCD(x)		(x&TRCD)	/* DDR tRCD = (1~15) cycles */
+#define DDR_DATWIDTH		0x2000		/* DDR data width */
+#define EXTBANK_1		0		/* 1 external bank */
+#define EXTBANK_2		0x4000		/* 2 external banks */
+#define DEVSZ_64		0x40000		/* DDR External Bank Size = 64MB */
+#define DEVSZ_128		0x80000		/* DDR External Bank Size = 128MB */
+#define DEVSZ_256		0xc0000		/* DDR External Bank Size = 256MB */
+#define DEVSZ_512		0		/* DDR External Bank Size = 512MB */
+#define DEVWD_4			0		/* DDR Device Width = 4 Bits    */
+#define DEVWD_8			0x10000		/* DDR Device Width = 8 Bits    */
+#define DEVWD_16		0x20000		/* DDR Device Width = 16 Bits    */
 
 /* Bit masks for EBIU_DDRCTL2 */
 
@@ -1790,6 +1809,10 @@
 #define                CASLATENCY  0x70       /* CAS latency */
 #define                  DLLRESET  0x100      /* DLL Reset */
 #define                      REGE  0x1000     /* Register mode enable */
+#define CL_1_5			0x50		/* DDR CAS Latency = 1.5 cycles */
+#define CL_2			0x20		/* DDR CAS Latency = 2 cycles */
+#define CL_2_5			0x60		/* DDR CAS Latency = 2.5 cycles */
+#define CL_3			0x30		/* DDR CAS Latency = 3 cycles */
 
 /* Bit masks for EBIU_DDRCTL3 */
 
@@ -2257,6 +2280,10 @@
 
 #define                      CSEL  0x30       /* Core Select */
 #define                      SSEL  0xf        /* System Select */
+#define			CSEL_DIV1	0x0000	/* CCLK = VCO / 1 */
+#define			CSEL_DIV2	0x0010	/* CCLK = VCO / 2 */
+#define			CSEL_DIV4	0x0020	/* CCLK = VCO / 4 */
+#define			CSEL_DIV8	0x0030	/* CCLK = VCO / 8 */
 
 /* Bit masks for PLL_CTL */
 
diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h
index 9fb7bc5..c34507a 100644
--- a/include/asm-blackfin/mach-bf548/irq.h
+++ b/include/asm-blackfin/mach-bf548/irq.h
@@ -88,7 +88,7 @@
 #define IRQ_PINT1		BFIN_IRQ(20)	/* PINT1 Interrupt */
 #define IRQ_MDMAS0		BFIN_IRQ(21)	/* MDMA Stream 0 Interrupt */
 #define IRQ_MDMAS1		BFIN_IRQ(22)	/* MDMA Stream 1 Interrupt */
-#define IRQ_WATCHDOG		BFIN_IRQ(23)	/* Watchdog Interrupt */
+#define IRQ_WATCH		BFIN_IRQ(23)	/* Watchdog Interrupt */
 #define IRQ_DMAC1_ERROR		BFIN_IRQ(24)	/* DMAC1 Status (Error) Interrupt */
 #define IRQ_SPORT2_ERROR	BFIN_IRQ(25)	/* SPORT2 Error Interrupt */
 #define IRQ_SPORT3_ERROR	BFIN_IRQ(26)	/* SPORT3 Error Interrupt */
@@ -406,7 +406,7 @@
 #define IRQ_PINT1_POS		16
 #define IRQ_MDMAS0_POS		20
 #define IRQ_MDMAS1_POS		24
-#define IRQ_WATCHDOG_POS	28
+#define IRQ_WATCH_POS		28
 
 /* IAR3 BIT FIELDS */
 #define IRQ_DMAC1_ERR_POS	0
diff --git a/include/asm-blackfin/mach-bf548/mem_init.h b/include/asm-blackfin/mach-bf548/mem_init.h
index 0cb279e..befc290 100644
--- a/include/asm-blackfin/mach-bf548/mem_init.h
+++ b/include/asm-blackfin/mach-bf548/mem_init.h
@@ -28,8 +28,68 @@
  * If not, write to the Free Software Foundation,
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+#define MIN_DDR_SCLK(x)	(x*(CONFIG_SCLK_HZ/1000/1000)/1000 + 1)
 
-#if (CONFIG_MEM_MT46V32M16)
+#if (CONFIG_MEM_MT46V32M16_6T)
+#define DDR_SIZE	DEVSZ_512
+#define DDR_WIDTH	DEVWD_16
+
+#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(60))
+#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(42))
+#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
+#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(72))
+#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
+
+#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
+#define DDR_tWTR	DDR_TWTR(1)
+#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(12))
+#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
+#endif
+
+#if (CONFIG_MEM_MT46V32M16_5B)
+#define DDR_SIZE	DEVSZ_512
+#define DDR_WIDTH	DEVWD_16
+
+#define DDR_tRC		DDR_TRC(MIN_DDR_SCLK(55))
+#define DDR_tRAS	DDR_TRAS(MIN_DDR_SCLK(40))
+#define DDR_tRP		DDR_TRP(MIN_DDR_SCLK(15))
+#define DDR_tRFC	DDR_TRFC(MIN_DDR_SCLK(70))
+#define DDR_tREFI	DDR_TREFI(MIN_DDR_SCLK(7800))
+
+#define DDR_tRCD	DDR_TRCD(MIN_DDR_SCLK(15))
+#define DDR_tWTR	DDR_TWTR(2)
+#define DDR_tMRD	DDR_TMRD(MIN_DDR_SCLK(10))
+#define DDR_tWR		DDR_TWR(MIN_DDR_SCLK(15))
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+#define DDR_SIZE	DEVSZ_512
+#define DDR_WIDTH	DEVWD_16
+
+#define DDR_tRCD	DDR_TRCD(3)
+#define DDR_tWTR	DDR_TWTR(2)
+#define DDR_tWR		DDR_TWR(2)
+#define DDR_tMRD	DDR_TMRD(2)
+#define DDR_tRP		DDR_TRP(3)
+#define DDR_tRAS	DDR_TRAS(7)
+#define DDR_tRC		DDR_TRC(10)
+#define DDR_tRFC	DDR_TRFC(12)
+#define DDR_tREFI	DDR_TREFI(1288)
+#endif
+
+#if (CONFIG_SCLK_HZ <= 133333333)
+#define	DDR_CL		CL_2
+#elif (CONFIG_SCLK_HZ <= 166666666)
+#define	DDR_CL		CL_2_5
+#else
+#define	DDR_CL		CL_3
+#endif
+
+#define mem_DDRCTL0	(DDR_tRP | DDR_tRAS | DDR_tRC | DDR_tRFC | DDR_tREFI)
+#define mem_DDRCTL1	(DDR_DATWIDTH | EXTBANK_1 | DDR_SIZE | DDR_WIDTH | DDR_tWTR \
+			| DDR_tMRD | DDR_tWR | DDR_tRCD)
+#define mem_DDRCTL2	DDR_CL
+
 
 #if defined CONFIG_CLKIN_HALF
 #define CLKIN_HALF       1
diff --git a/include/asm-blackfin/mach-bf548/portmux.h b/include/asm-blackfin/mach-bf548/portmux.h
index 6b48512..8177a56 100644
--- a/include/asm-blackfin/mach-bf548/portmux.h
+++ b/include/asm-blackfin/mach-bf548/portmux.h
@@ -1,6 +1,8 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
+
 #define P_SPORT2_TFS	(P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
 #define P_SPORT2_DTSEC	(P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
 #define P_SPORT2_DTPRI	(P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
index bed9564..0c1d461 100644
--- a/include/asm-blackfin/mach-bf561/anomaly.h
+++ b/include/asm-blackfin/mach-bf561/anomaly.h
@@ -7,7 +7,7 @@
  */
 
 /* This file shoule be up to date with:
- *  - Revision N, March 28, 2007; ADSP-BF561 Silicon Anomaly List
+ *  - Revision O, 11/15/2007; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
@@ -15,7 +15,7 @@
 
 /* We do not support 0.1, 0.2, or 0.4 silicon - sorry */
 #if __SILICON_REVISION__ < 3 || __SILICON_REVISION__ == 4
-# error Kernel will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
+# error will not work on BF561 silicon version 0.0, 0.1, 0.2, or 0.4
 #endif
 
 /* Multi-Issue Instruction with dsp32shiftimm in slot1 and P-reg Store in slot 2 Not Supported */
@@ -208,6 +208,8 @@
 #define ANOMALY_05000275 (__SILICON_REVISION__ > 2)
 /* Timing Requirements Change for External Frame Sync PPI Modes with Non-Zero PPI_DELAY */
 #define ANOMALY_05000276 (__SILICON_REVISION__ < 5)
+/* Writes to an I/O data register one SCLK cycle after an edge is detected may clear interrupt */
+#define ANOMALY_05000277 (__SILICON_REVISION__ < 3)
 /* Disabling Peripherals with DMA Running May Cause DMA System Instability */
 #define ANOMALY_05000278 (__SILICON_REVISION__ < 5)
 /* False Hardware Error Exception When ISR Context Is Not Restored */
@@ -246,6 +248,18 @@
 #define ANOMALY_05000332 (__SILICON_REVISION__ < 5)
 /* Flag Data Register Writes One SCLK Cycle After Edge Is Detected May Clear Interrupt Status */
 #define ANOMALY_05000333 (__SILICON_REVISION__ < 5)
+/* New Feature: Additional PPI Frame Sync Sampling Options (Not Available on Older Silicon) */
+#define ANOMALY_05000339 (__SILICON_REVISION__ < 5)
+/* Memory DMA FIFO Causes Throughput Degradation on Writes to External Memory */
+#define ANOMALY_05000343 (__SILICON_REVISION__ < 5)
+/* Serial Port (SPORT) Multichannel Transmit Failure when Channel 0 Is Disabled */
+#define ANOMALY_05000357 (1)
+/* Conflicting Column Address Widths Causes SDRAM Errors */
+#define ANOMALY_05000362 (1)
+/* PPI Underflow Error Goes Undetected in ITU-R 656 Mode */
+#define ANOMALY_05000366 (1)
+/* Possible RETS Register Corruption when Subroutine Is under 5 Cycles in Duration */
+#define ANOMALY_05000371 (1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000158 (0)
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
index 69b9f8e..7871d43 100644
--- a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -111,7 +111,7 @@
 	}
 	if (uart->rts_pin >= 0) {
 		gpio_request(uart->rts_pin, DRIVER_NAME);
-		gpio_direction_input(uart->rts_pin);
+		gpio_direction_input(uart->rts_pin, 0);
 	}
 #endif
 }
diff --git a/include/asm-blackfin/mach-bf561/portmux.h b/include/asm-blackfin/mach-bf561/portmux.h
index 132ad31..a6ee820 100644
--- a/include/asm-blackfin/mach-bf561/portmux.h
+++ b/include/asm-blackfin/mach-bf561/portmux.h
@@ -1,6 +1,8 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
+#define MAX_RESOURCES 	MAX_BLACKFIN_GPIOS
+
 #define P_PPI0_CLK	(P_DONTCARE)
 #define P_PPI0_FS1	(P_DONTCARE)
 #define P_PPI0_FS2	(P_DONTCARE)
diff --git a/include/asm-blackfin/mmu.h b/include/asm-blackfin/mmu.h
index 11d52f1..757e439 100644
--- a/include/asm-blackfin/mmu.h
+++ b/include/asm-blackfin/mmu.h
@@ -24,7 +24,9 @@
 	unsigned long	exec_fdpic_loadmap;
 	unsigned long	interp_fdpic_loadmap;
 #endif
-
+#ifdef CONFIG_MPU
+	unsigned long *page_rwx_mask;
+#endif
 } mm_context_t;
 
 #endif
diff --git a/include/asm-blackfin/mmu_context.h b/include/asm-blackfin/mmu_context.h
index c5c71a6..b5eb675 100644
--- a/include/asm-blackfin/mmu_context.h
+++ b/include/asm-blackfin/mmu_context.h
@@ -30,9 +30,12 @@
 #ifndef __BLACKFIN_MMU_CONTEXT_H__
 #define __BLACKFIN_MMU_CONTEXT_H__
 
+#include <linux/gfp.h>
+#include <linux/sched.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm/cplbinit.h>
 
 extern void *current_l1_stack_save;
 extern int nr_l1stack_tasks;
@@ -50,6 +53,12 @@
 static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
+#ifdef CONFIG_MPU
+	unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
+	mm->context.page_rwx_mask = (unsigned long *)p;
+	memset(mm->context.page_rwx_mask, 0,
+	       page_mask_nelts * 3 * sizeof(long));
+#endif
 	return 0;
 }
 
@@ -73,6 +82,11 @@
 		sram_free(tmp->addr);
 		kfree(tmp);
 	}
+#ifdef CONFIG_MPU
+	if (current_rwx_mask == mm->context.page_rwx_mask)
+		current_rwx_mask = NULL;
+	free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
+#endif
 }
 
 static inline unsigned long
@@ -106,9 +120,21 @@
 
 #define deactivate_mm(tsk,mm)	do { } while (0)
 
-static inline void activate_mm(struct mm_struct *prev_mm,
-			       struct mm_struct *next_mm)
+#define activate_mm(prev, next) switch_mm(prev, next, NULL)
+
+static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
+			     struct task_struct *tsk)
 {
+	if (prev_mm == next_mm)
+		return;
+#ifdef CONFIG_MPU
+	if (prev_mm->context.page_rwx_mask == current_rwx_mask) {
+		flush_switched_cplbs();
+		set_mask_dcplbs(next_mm->context.page_rwx_mask);
+	}
+#endif
+
+	/* L1 stack switching.  */
 	if (!next_mm->context.l1_stack_save)
 		return;
 	if (next_mm->context.l1_stack_save == current_l1_stack_save)
@@ -120,10 +146,36 @@
 	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
 }
 
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-			     struct task_struct *tsk)
+#ifdef CONFIG_MPU
+static inline void protect_page(struct mm_struct *mm, unsigned long addr,
+				unsigned long flags)
 {
-	activate_mm(prev, next);
+	unsigned long *mask = mm->context.page_rwx_mask;
+	unsigned long page = addr >> 12;
+	unsigned long idx = page >> 5;
+	unsigned long bit = 1 << (page & 31);
+
+	if (flags & VM_MAYREAD)
+		mask[idx] |= bit;
+	else
+		mask[idx] &= ~bit;
+	mask += page_mask_nelts;
+	if (flags & VM_MAYWRITE)
+		mask[idx] |= bit;
+	else
+		mask[idx] &= ~bit;
+	mask += page_mask_nelts;
+	if (flags & VM_MAYEXEC)
+		mask[idx] |= bit;
+	else
+		mask[idx] &= ~bit;
 }
 
+static inline void update_protections(struct mm_struct *mm)
+{
+	flush_switched_cplbs();
+	set_mask_dcplbs(mm->context.page_rwx_mask);
+}
+#endif
+
 #endif
diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
index ee1cbf7..f0e5f94 100644
--- a/include/asm-blackfin/traps.h
+++ b/include/asm-blackfin/traps.h
@@ -45,6 +45,10 @@
 #define VEC_CPLB_I_M	(44)
 #define VEC_CPLB_I_MHIT	(45)
 #define VEC_ILL_RES	(46)	/* including unvalid supervisor mode insn */
+/* The hardware reserves (63) for future use - we use it to tell our
+ * normal exception handling code we have a hardware error
+ */
+#define VEC_HWERR	(63)
 
 #ifndef __ASSEMBLY__
 
diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
index 2233f8f..22a410b 100644
--- a/include/asm-blackfin/uaccess.h
+++ b/include/asm-blackfin/uaccess.h
@@ -31,7 +31,7 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
+#define access_ok(type, addr, size) _access_ok((unsigned long)(addr), (size))
 
 static inline int is_in_rom(unsigned long addr)
 {
diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
index 07ffe8b..e981673 100644
--- a/include/asm-blackfin/unistd.h
+++ b/include/asm-blackfin/unistd.h
@@ -369,8 +369,9 @@
 #define __NR_set_robust_list	354
 #define __NR_get_robust_list	355
 #define __NR_fallocate		356
+#define __NR_semtimedop		357
 
-#define __NR_syscall		357
+#define __NR_syscall		358
 #define NR_syscalls		__NR_syscall
 
 /* Old optional stuff no one actually uses */
diff --git a/include/asm-s390/airq.h b/include/asm-s390/airq.h
new file mode 100644
index 0000000..41d028c
--- /dev/null
+++ b/include/asm-s390/airq.h
@@ -0,0 +1,19 @@
+/*
+ *  include/asm-s390/airq.h
+ *
+ *    Copyright IBM Corp. 2002,2007
+ *    Author(s): Ingo Adlung <adlung@de.ibm.com>
+ *		 Cornelia Huck <cornelia.huck@de.ibm.com>
+ *		 Arnd Bergmann <arndb@de.ibm.com>
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_AIRQ_H
+#define _ASM_S390_AIRQ_H
+
+typedef void (*adapter_int_handler_t)(void *, void *);
+
+void *s390_register_adapter_interrupt(adapter_int_handler_t, void *);
+void s390_unregister_adapter_interrupt(void *);
+
+#endif /* _ASM_S390_AIRQ_H */
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 2f08c16..123b557 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -24,8 +24,8 @@
  * @fmt: format
  * @pfch: prefetch
  * @isic: initial-status interruption control
- * @alcc: adress-limit checking control
- * @ssi: supress-suspended interruption
+ * @alcc: address-limit checking control
+ * @ssi: suppress-suspended interruption
  * @zcc: zero condition code
  * @ectl: extended control
  * @pno: path not operational
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
index 604f68f..3f002e1 100644
--- a/include/asm-s390/dasd.h
+++ b/include/asm-s390/dasd.h
@@ -105,7 +105,7 @@
 } dasd_information_t;
 
 /*
- * Read Subsystem Data - Perfomance Statistics
+ * Read Subsystem Data - Performance Statistics
  */ 
 typedef struct dasd_rssd_perf_stats_t {
 	unsigned char  invalid:1;
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
index 2c40fd3..c1b2e50 100644
--- a/include/asm-s390/ipl.h
+++ b/include/asm-s390/ipl.h
@@ -83,6 +83,8 @@
 extern unsigned int zfcpdump_prefix_array[];
 
 extern void do_reipl(void);
+extern void do_halt(void);
+extern void do_poff(void);
 extern void ipl_save_parameters(void);
 
 enum {
@@ -118,7 +120,7 @@
 };
 
 extern struct ipl_info ipl_info;
-extern void setup_ipl_info(void);
+extern void setup_ipl(void);
 
 /*
  * DIAG 308 support
@@ -141,6 +143,10 @@
 	DIAG308_IPL_OPT_DUMP	= 0x20,
 };
 
+enum diag308_flags {
+	DIAG308_FLAGS_LP_VALID	= 0x80,
+};
+
 enum diag308_rc {
 	DIAG308_RC_OK	= 1,
 };
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index 05b8421..a77d4ba 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -12,10 +12,15 @@
 #include <asm/pgalloc.h>
 #include <asm-generic/mm_hooks.h>
 
-/*
- * get a new mmu context.. S390 don't know about contexts.
- */
-#define init_new_context(tsk,mm)        0
+static inline int init_new_context(struct task_struct *tsk,
+				   struct mm_struct *mm)
+{
+	mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
+#ifdef CONFIG_64BIT
+	mm->context |= _ASCE_TYPE_REGION3;
+#endif
+	return 0;
+}
 
 #define destroy_context(mm)             do { } while (0)
 
@@ -27,19 +32,11 @@
 
 static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
 {
-	pgd_t *pgd = mm->pgd;
-	unsigned long asce_bits;
-
-	/* Calculate asce bits from the first pgd table entry. */
-	asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
-#ifdef CONFIG_64BIT
-	asce_bits |= _ASCE_TYPE_REGION3;
-#endif
-	S390_lowcore.user_asce = asce_bits | __pa(pgd);
+	S390_lowcore.user_asce = mm->context | __pa(mm->pgd);
 	if (switch_amode) {
 		/* Load primary space page table origin. */
-		pgd_t *shadow_pgd = get_shadow_table(pgd) ? : pgd;
-		S390_lowcore.user_exec_asce = asce_bits | __pa(shadow_pgd);
+		pgd_t *shadow_pgd = get_shadow_table(mm->pgd) ? : mm->pgd;
+		S390_lowcore.user_exec_asce = mm->context | __pa(shadow_pgd);
 		asm volatile(LCTL_OPCODE" 1,1,%0\n"
 			     : : "m" (S390_lowcore.user_exec_asce) );
 	} else
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 1f530f8..79b9eab 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -104,41 +104,27 @@
 
 #ifndef __ASSEMBLY__
 /*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- * vmalloc area starts at 4GB to prevent syscall table entry exchanging
- * from modules.
- */
-extern unsigned long vmalloc_end;
-
-#ifdef CONFIG_64BIT
-#define VMALLOC_ADDR	(max(0x100000000UL, (unsigned long) high_memory))
-#else
-#define VMALLOC_ADDR	((unsigned long) high_memory)
-#endif
-#define VMALLOC_OFFSET	(8*1024*1024)
-#define VMALLOC_START	((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-#define VMALLOC_END	vmalloc_end
-
-/*
- * We need some free virtual space to be able to do vmalloc.
- * VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
- * area. On a machine with 2GB memory we make sure that we
- * have at least 128MB free space for vmalloc. On a machine
- * with 4TB we make sure we have at least 128GB.
+ * The vmalloc area will always be on the topmost area of the kernel
+ * mapping. We reserve 96MB (31bit) / 1GB (64bit) for vmalloc,
+ * which should be enough for any sane case.
+ * By putting vmalloc at the top, we maximise the gap between physical
+ * memory and vmalloc to catch misplaced memory accesses. As a side
+ * effect, this also makes sure that 64 bit module code cannot be used
+ * as system call address.
  */
 #ifndef __s390x__
-#define VMALLOC_MIN_SIZE	0x8000000UL
-#define VMALLOC_END_INIT	0x80000000UL
+#define VMALLOC_START	0x78000000UL
+#define VMALLOC_END	0x7e000000UL
+#define VMEM_MAP_MAX	0x80000000UL
 #else /* __s390x__ */
-#define VMALLOC_MIN_SIZE	0x2000000000UL
-#define VMALLOC_END_INIT	0x40000000000UL
+#define VMALLOC_START	0x3e000000000UL
+#define VMALLOC_END	0x3e040000000UL
+#define VMEM_MAP_MAX	0x40000000000UL
 #endif /* __s390x__ */
 
+#define VMEM_MAP	((struct page *) VMALLOC_END)
+#define VMEM_MAP_SIZE	((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
+
 /*
  * A 31 bit pagetable entry of S390 has following format:
  *  |   PFRA          |    |  OS  |
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index 21d40a1..c86b982 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -59,9 +59,6 @@
 extern void print_cpu_info(struct cpuinfo_S390 *);
 extern int get_cpu_capability(unsigned int *);
 
-/* Lazy FPU handling on uni-processor */
-extern struct task_struct *last_task_used_math;
-
 /*
  * User space process size: 2GB for 31 bit, 4TB for 64 bit.
  */
@@ -95,7 +92,6 @@
         unsigned long ksp;              /* kernel stack pointer             */
 	mm_segment_t mm_segment;
         unsigned long prot_addr;        /* address of protection-excep.     */
-        unsigned int error_code;        /* error-code of last prog-excep.   */
         unsigned int trap_no;
         per_struct per_info;
 	/* Used to give failing instruction back to user for ieee exceptions */
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 332ee73..61f6952 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -465,6 +465,14 @@
 #ifdef __KERNEL__
 #define __ARCH_SYS_PTRACE	1
 
+/*
+ * These are defined as per linux/ptrace.h, which see.
+ */
+#define arch_has_single_step()	(1)
+struct task_struct;
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+
 #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
 #define regs_return_value(regs)((regs)->gprs[2])
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index 74db1dc..4b8ff55 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -184,7 +184,7 @@
 #endif /* QDIO_32_BIT */
 	unsigned long qiba;             /* queue-information-block address */
 	unsigned int  res8;             /* reserved */
-	unsigned int  qkey    :  4;     /* queue-informatio-block key */
+	unsigned int  qkey    :  4;	/* queue-information-block key */
 	unsigned int  res9    : 28;     /* reserved */
 /*	union _qd {*/ /* why this? */
 		struct qdesfmt0 qdf0[126];
diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
index 90f4ecc..9d2a179 100644
--- a/include/asm-s390/rwsem.h
+++ b/include/asm-s390/rwsem.h
@@ -91,8 +91,8 @@
 #endif
 
 #define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
-  __RWSEM_DEP_MAP_INIT(name) }
+ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
+   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
 
 #define DECLARE_RWSEM(name) \
 	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
index cb9faf1..b5f2843 100644
--- a/include/asm-s390/sclp.h
+++ b/include/asm-s390/sclp.h
@@ -27,7 +27,25 @@
 	char loadparm[LOADPARM_LEN];
 };
 
-void sclp_readinfo_early(void);
+struct sclp_cpu_entry {
+	u8 address;
+	u8 reserved0[13];
+	u8 type;
+	u8 reserved1;
+} __attribute__((packed));
+
+struct sclp_cpu_info {
+	unsigned int configured;
+	unsigned int standby;
+	unsigned int combined;
+	int has_cpu_type;
+	struct sclp_cpu_entry cpu[255];
+};
+
+int sclp_get_cpu_info(struct sclp_cpu_info *info);
+int sclp_cpu_configure(u8 cpu);
+int sclp_cpu_deconfigure(u8 cpu);
+void sclp_read_info_early(void);
 void sclp_facilities_detect(void);
 unsigned long long sclp_memory_detect(void);
 int sclp_sdias_blk_count(void);
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 07708c0..c7b7432 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -35,8 +35,6 @@
 extern void machine_halt_smp(void);
 extern void machine_power_off_smp(void);
 
-extern void smp_setup_cpu_possible_map(void);
-
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
 /*
@@ -92,6 +90,8 @@
 extern void cpu_die (void) __attribute__ ((noreturn));
 extern int __cpu_up (unsigned int cpu);
 
+extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+	void *info, int wait);
 #endif
 
 #ifndef CONFIG_SMP
@@ -103,7 +103,6 @@
 
 #define hard_smp_processor_id()		0
 #define smp_cpu_not_running(cpu)	1
-#define smp_setup_cpu_possible_map()	do { } while (0)
 #endif
 
 extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
index 3fd4382..df84ae9 100644
--- a/include/asm-s390/spinlock.h
+++ b/include/asm-s390/spinlock.h
@@ -53,44 +53,48 @@
  */
 
 #define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
 #define __raw_spin_unlock_wait(lock) \
 	do { while (__raw_spin_is_locked(lock)) \
 		 _raw_spin_relax(lock); } while (0)
 
-extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
-extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
+extern void _raw_spin_lock_wait(raw_spinlock_t *);
+extern void _raw_spin_lock_wait_flags(raw_spinlock_t *, unsigned long flags);
+extern int _raw_spin_trylock_retry(raw_spinlock_t *);
 extern void _raw_spin_relax(raw_spinlock_t *lock);
 
 static inline void __raw_spin_lock(raw_spinlock_t *lp)
 {
-	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
 	int old;
 
 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-	if (likely(old == 0)) {
-		lp->owner_pc = pc;
+	if (likely(old == 0))
 		return;
-	}
-	_raw_spin_lock_wait(lp, pc);
+	_raw_spin_lock_wait(lp);
+}
+
+static inline void __raw_spin_lock_flags(raw_spinlock_t *lp,
+					 unsigned long flags)
+{
+	int old;
+
+	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+	if (likely(old == 0))
+		return;
+	_raw_spin_lock_wait_flags(lp, flags);
 }
 
 static inline int __raw_spin_trylock(raw_spinlock_t *lp)
 {
-	unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
 	int old;
 
 	old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
-	if (likely(old == 0)) {
-		lp->owner_pc = pc;
+	if (likely(old == 0))
 		return 1;
-	}
-	return _raw_spin_trylock_retry(lp, pc);
+	return _raw_spin_trylock_retry(lp);
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lp)
 {
-	lp->owner_pc = 0;
 	_raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
 }
 		
diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h
index b7ac13f..654abc4 100644
--- a/include/asm-s390/spinlock_types.h
+++ b/include/asm-s390/spinlock_types.h
@@ -7,7 +7,6 @@
 
 typedef struct {
 	volatile unsigned int owner_cpu;
-	volatile unsigned int owner_pc;
 } __attribute__ ((aligned (4))) raw_spinlock_t;
 
 #define __RAW_SPIN_LOCK_UNLOCKED	{ 0 }
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
index a69bd24..70fa5ae 100644
--- a/include/asm-s390/tlbflush.h
+++ b/include/asm-s390/tlbflush.h
@@ -42,11 +42,11 @@
 /*
  * Flush all tlb entries of a page table on all cpus.
  */
-static inline void __tlb_flush_idte(pgd_t *pgd)
+static inline void __tlb_flush_idte(unsigned long asce)
 {
 	asm volatile(
 		"	.insn	rrf,0xb98e0000,0,%0,%1,0"
-		: : "a" (2048), "a" (__pa(pgd) & PAGE_MASK) : "cc" );
+		: : "a" (2048), "a" (asce) : "cc" );
 }
 
 static inline void __tlb_flush_mm(struct mm_struct * mm)
@@ -61,11 +61,11 @@
 	 * only ran on the local cpu.
 	 */
 	if (MACHINE_HAS_IDTE) {
-		pgd_t *shadow_pgd = get_shadow_table(mm->pgd);
+		pgd_t *shadow = get_shadow_table(mm->pgd);
 
-		if (shadow_pgd)
-			__tlb_flush_idte(shadow_pgd);
-		__tlb_flush_idte(mm->pgd);
+		if (shadow)
+			__tlb_flush_idte((unsigned long) shadow | mm->context);
+		__tlb_flush_idte((unsigned long) mm->pgd | mm->context);
 		return;
 	}
 	preempt_disable();
@@ -106,9 +106,23 @@
  */
 #define flush_tlb()				do { } while (0)
 #define flush_tlb_all()				do { } while (0)
-#define flush_tlb_mm(mm)			__tlb_flush_mm_cond(mm)
 #define flush_tlb_page(vma, addr)		do { } while (0)
-#define flush_tlb_range(vma, start, end)	__tlb_flush_mm_cond(mm)
-#define flush_tlb_kernel_range(start, end)	__tlb_flush_mm(&init_mm)
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	__tlb_flush_mm_cond(mm);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	__tlb_flush_mm_cond(vma->vm_mm);
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+					  unsigned long end)
+{
+	__tlb_flush_mm(&init_mm);
+}
 
 #endif /* _S390_TLBFLUSH_H */
diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
index a5dada6..f228f1b 100644
--- a/include/asm-s390/zcrypt.h
+++ b/include/asm-s390/zcrypt.h
@@ -117,7 +117,7 @@
 	unsigned char	padx004[16 - sizeof (char *)];
 	unsigned char *	req_extb;	/* request extension block 'addr'*/
 	unsigned char	padx005[16 - sizeof (char *)];
-	unsigned char *	rpl_extb;	/* reply extension block 'addres'*/
+	unsigned char *	rpl_extb;	/* reply extension block 'address'*/
 	unsigned short	ccp_rtcode;	/* server return code		 */
 	unsigned short	ccp_rscode;	/* server reason code		 */
 	unsigned int	mac_data_len;	/* Mac Data Length		 */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index bd20a4e..49b7a4c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -143,7 +143,6 @@
 	 * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
 	 * private REQ_LB opcodes to differentiate what type of request this is
 	 */
-	REQ_TYPE_ATA_CMD,
 	REQ_TYPE_ATA_TASKFILE,
 	REQ_TYPE_ATA_PC,
 };
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index c7a51a1..f922b06 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -33,23 +33,13 @@
 
 #define I2C_DRIVERID_MSP3400	 1
 #define I2C_DRIVERID_TUNER	 2
-#define I2C_DRIVERID_VIDEOTEX	 3	/* please rename		*/
 #define I2C_DRIVERID_TDA8425	 4	/* stereo sound processor	*/
 #define I2C_DRIVERID_TEA6420	 5	/* audio matrix switch		*/
 #define I2C_DRIVERID_TEA6415C	 6	/* video matrix switch		*/
 #define I2C_DRIVERID_TDA9840	 7	/* stereo sound processor	*/
 #define I2C_DRIVERID_SAA7111A	 8	/* video input processor	*/
-#define I2C_DRIVERID_SAA5281	 9	/* videotext decoder		*/
-#define I2C_DRIVERID_SAA7112	10	/* video decoder, image scaler	*/
-#define I2C_DRIVERID_SAA7120	11	/* video encoder		*/
-#define I2C_DRIVERID_SAA7121	12	/* video encoder		*/
 #define I2C_DRIVERID_SAA7185B	13	/* video encoder		*/
-#define I2C_DRIVERID_CH7003	14	/* digital pc to tv encoder	*/
-#define I2C_DRIVERID_PCF8574A	15	/* i2c expander - 8 bit in/out	*/
-#define I2C_DRIVERID_PCF8582C	16	/* eeprom			*/
-#define I2C_DRIVERID_AT24Cxx	17	/* eeprom 1/2/4/8/16 K		*/
 #define I2C_DRIVERID_TEA6300	18	/* audio mixer			*/
-#define I2C_DRIVERID_BT829	19	/* pc to tv encoder		*/
 #define I2C_DRIVERID_TDA9850	20	/* audio mixer			*/
 #define I2C_DRIVERID_TDA9855	21	/* audio mixer			*/
 #define I2C_DRIVERID_SAA7110	22	/* video decoder		*/
@@ -60,42 +50,19 @@
 #define I2C_DRIVERID_TDA7432	27	/* Stereo sound processor	*/
 #define I2C_DRIVERID_TVMIXER    28      /* Mixer driver for tv cards    */
 #define I2C_DRIVERID_TVAUDIO    29      /* Generic TV sound driver      */
-#define I2C_DRIVERID_DPL3518    30      /* Dolby decoder chip           */
 #define I2C_DRIVERID_TDA9873    31      /* TV sound decoder chip        */
 #define I2C_DRIVERID_TDA9875    32      /* TV sound decoder chip        */
 #define I2C_DRIVERID_PIC16C54_PV9 33    /* Audio mux/ir receiver        */
-
-#define I2C_DRIVERID_SBATT      34     /* Smart Battery Device		*/
-#define I2C_DRIVERID_SBS        35     /* SB System Manager		*/
-#define I2C_DRIVERID_VES1893	36     /* VLSI DVB-S decoder		*/
-#define I2C_DRIVERID_VES1820	37     /* VLSI DVB-C decoder		*/
-#define I2C_DRIVERID_SAA7113	38     /* video decoder			*/
-#define I2C_DRIVERID_TDA8444	39     /* octuple 6-bit DAC             */
 #define I2C_DRIVERID_BT819	40     /* video decoder			*/
 #define I2C_DRIVERID_BT856	41     /* video encoder			*/
 #define I2C_DRIVERID_VPX3220	42     /* video decoder+vbi/vtxt	*/
-#define I2C_DRIVERID_DRP3510	43     /* ADR decoder (Astra Radio)	*/
-#define I2C_DRIVERID_SP5055	44     /* Satellite tuner		*/
-#define I2C_DRIVERID_STV0030	45     /* Multipurpose switch		*/
-#define I2C_DRIVERID_SAA7108	46     /* video decoder, image scaler   */
-#define I2C_DRIVERID_DS1307	47     /* DS1307 real time clock	*/
 #define I2C_DRIVERID_ADV7175	48     /* ADV 7175/7176 video encoder	*/
 #define I2C_DRIVERID_SAA7114	49	/* video decoder		*/
-#define I2C_DRIVERID_ZR36120	50     /* Zoran 36120 video encoder	*/
-#define I2C_DRIVERID_24LC32A	51	/* Microchip 24LC32A 32k EEPROM	*/
-#define I2C_DRIVERID_STM41T00	52	/* real time clock		*/
-#define I2C_DRIVERID_UDA1342	53	/* UDA1342 audio codec		*/
 #define I2C_DRIVERID_ADV7170	54	/* video encoder		*/
-#define I2C_DRIVERID_MAX1617	56	/* temp sensor			*/
 #define I2C_DRIVERID_SAA7191	57	/* video decoder		*/
 #define I2C_DRIVERID_INDYCAM	58	/* SGI IndyCam			*/
-#define I2C_DRIVERID_BT832	59	/* CMOS camera video processor	*/
-#define I2C_DRIVERID_TDA9887	60	/* TDA988x IF-PLL demodulator	*/
 #define I2C_DRIVERID_OVCAMCHIP	61	/* OmniVision CMOS image sens.	*/
-#define I2C_DRIVERID_TDA7313	62	/* TDA7313 audio processor	*/
 #define I2C_DRIVERID_MAX6900	63	/* MAX6900 real-time clock	*/
-#define I2C_DRIVERID_SAA7114H	64	/* video decoder		*/
-#define I2C_DRIVERID_DS1374	65	/* DS1374 real time clock	*/
 #define I2C_DRIVERID_TDA9874	66	/* TV sound decoder		*/
 #define I2C_DRIVERID_SAA6752HS	67	/* MPEG2 encoder		*/
 #define I2C_DRIVERID_TVEEPROM	68	/* TV EEPROM			*/
@@ -114,7 +81,6 @@
 #define I2C_DRIVERID_DS1672	81	/* Dallas/Maxim DS1672 RTC	*/
 #define I2C_DRIVERID_X1205	82	/* Xicor/Intersil X1205 RTC	*/
 #define I2C_DRIVERID_PCF8563	83	/* Philips PCF8563 RTC		*/
-#define I2C_DRIVERID_RS5C372	84	/* Ricoh RS5C372 RTC		*/
 #define I2C_DRIVERID_BT866	85	/* Conexant bt866 video encoder */
 #define I2C_DRIVERID_KS0127	86	/* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87	/* TI TLV320AIC23B audio codec  */
@@ -129,8 +95,6 @@
 #define I2C_DRIVERID_CS5345	96	/* cs5345 audio processor	*/
 
 #define I2C_DRIVERID_I2CDEV	900
-#define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
-#define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
 
 /* IDs --   Use DRIVERIDs 1000-1999 for sensors.
    These were originally in sensors.h in the lm_sensors package */
@@ -176,24 +140,16 @@
 
 /* --- Bit algorithm adapters						*/
 #define I2C_HW_B_LP		0x010000 /* Parallel port Philips style */
-#define I2C_HW_B_SER		0x010002 /* Serial line interface */
 #define I2C_HW_B_BT848		0x010005 /* BT848 video boards */
-#define I2C_HW_B_WNV		0x010006 /* Winnov Videums */
 #define I2C_HW_B_VIA		0x010007 /* Via vt82c586b */
 #define I2C_HW_B_HYDRA		0x010008 /* Apple Hydra Mac I/O */
 #define I2C_HW_B_G400		0x010009 /* Matrox G400 */
 #define I2C_HW_B_I810		0x01000a /* Intel I810 */
 #define I2C_HW_B_VOO		0x01000b /* 3dfx Voodoo 3 / Banshee */
-#define I2C_HW_B_PPORT		0x01000c /* Primitive parallel port adapter */
-#define I2C_HW_B_SAVG		0x01000d /* Savage 4 */
 #define I2C_HW_B_SCX200		0x01000e /* Nat'l Semi SCx200 I2C */
 #define I2C_HW_B_RIVA		0x010010 /* Riva based graphics cards */
 #define I2C_HW_B_IOC		0x010011 /* IOC bit-wiggling */
-#define I2C_HW_B_TSUNA		0x010012 /* DEC Tsunami chipset */
-#define I2C_HW_B_OMAHA		0x010014 /* Omaha I2C interface (ARM) */
-#define I2C_HW_B_GUIDE		0x010015 /* Guide bit-basher */
 #define I2C_HW_B_IXP2000	0x010016 /* GPIO on IXP2000 systems */
-#define I2C_HW_B_IXP4XX		0x010017 /* GPIO on IXP4XX systems */
 #define I2C_HW_B_S3VIA		0x010018 /* S3Via ProSavage adapter */
 #define I2C_HW_B_ZR36067	0x010019 /* Zoran-36057/36067 based boards */
 #define I2C_HW_B_PCILYNX	0x01001a /* TI PCILynx I2C adapter */
@@ -207,22 +163,11 @@
 #define I2C_HW_B_CX23885	0x010022 /* conexant 23885 based tv cards (bus1) */
 
 /* --- PCF 8584 based algorithms					*/
-#define I2C_HW_P_LP		0x020000 /* Parallel port interface */
-#define I2C_HW_P_ISA		0x020001 /* generic ISA Bus inteface card */
 #define I2C_HW_P_ELEK		0x020002 /* Elektor ISA Bus inteface card */
 
 /* --- PCA 9564 based algorithms */
 #define I2C_HW_A_ISA		0x1a0000 /* generic ISA Bus interface card */
 
-/* --- ACPI Embedded controller algorithms                              */
-#define I2C_HW_ACPI_EC          0x1f0000
-
-/* --- MPC824x PowerPC adapters						*/
-#define I2C_HW_MPC824X		0x100001 /* Motorola 8240 / 8245 */
-
-/* --- MPC8xx PowerPC adapters						*/
-#define I2C_HW_MPC8XX_EPON	0x110000 /* Eponymous MPC8xx I2C adapter */
-
 /* --- PowerPC on-chip adapters						*/
 #define I2C_HW_OCP		0x120000 /* IBM on-chip I2C adapter */
 
@@ -231,7 +176,6 @@
 
 /* --- SGI adapters							*/
 #define I2C_HW_SGI_VINO		0x160000
-#define I2C_HW_SGI_MACE		0x160001
 
 /* --- XSCALE on-chip adapters                          */
 #define I2C_HW_IOP3XX		0x140000
@@ -255,17 +199,10 @@
 #define I2C_HW_SMBUS_W9968CF	0x04000d
 #define I2C_HW_SMBUS_OV511	0x04000e /* OV511(+) USB 1.1 webcam ICs */
 #define I2C_HW_SMBUS_OV518	0x04000f /* OV518(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_OV519	0x040010 /* OV519 USB 1.1 webcam IC */
 #define I2C_HW_SMBUS_OVFX2	0x040011 /* Cypress/OmniVision FX2 webcam */
 #define I2C_HW_SMBUS_CAFE	0x040012 /* Marvell 88ALP01 "CAFE" cam  */
 #define I2C_HW_SMBUS_ALI1563	0x040013
 
-/* --- ISA pseudo-adapter						*/
-#define I2C_HW_ISA		0x050000
-
-/* --- IPMB adapter						*/
-#define I2C_HW_IPMB		0x0c0000
-
 /* --- MCP107 adapter */
 #define I2C_HW_MPC107		0x0d0000
 
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a100c9f..76014f8 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -140,7 +140,6 @@
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
 
 	struct device_driver driver;
-	struct list_head list;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
@@ -155,12 +154,11 @@
  *	generic enough to hide second-sourcing and compatible revisions.
  * @adapter: manages the bus segment hosting this I2C device
  * @driver: device's driver, hence pointer to access routines
- * @usage_count: counts current number of users of this client
  * @dev: Driver model device node for the slave.
  * @irq: indicates the IRQ generated by this device (if any)
  * @driver_name: Identifies new-style driver used with this device; also
  *	used as the module name for hotplug/coldplug modprobe support.
- * @list: list of active/busy clients
+ * @list: list of active/busy clients (DEPRECATED)
  * @released: used to synchronize client releases & detaches and references
  *
  * An i2c_client identifies a single device (i.e. chip) connected to an
@@ -175,16 +173,16 @@
 	char name[I2C_NAME_SIZE];
 	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
 	struct i2c_driver *driver;	/* and our access routines	*/
-	int usage_count;		/* How many accesses currently  */
-					/* to the client		*/
 	struct device dev;		/* the device structure		*/
 	int irq;			/* irq issued by device (or -1) */
 	char driver_name[KOBJ_NAME_LEN];
-	struct list_head list;
+	struct list_head list;		/* DEPRECATED */
 	struct completion released;
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
 
+extern struct i2c_client *i2c_verify_client(struct device *dev);
+
 static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
 {
 	struct device * const dev = container_of(kobj, struct device, kobj);
@@ -261,6 +259,12 @@
 		      struct i2c_board_info *info,
 		      unsigned short const *addr_list);
 
+/* For devices that use several addresses, use i2c_new_dummy() to make
+ * client handles for the extra addresses.
+ */
+extern struct i2c_client *
+i2c_new_dummy(struct i2c_adapter *adap, u16 address, const char *type);
+
 extern void i2c_unregister_device(struct i2c_client *);
 
 /* Mainboard arch_initcall() code should register all its I2C devices.
@@ -319,8 +323,7 @@
 	struct device dev;		/* the adapter device */
 
 	int nr;
-	struct list_head clients;
-	struct list_head list;
+	struct list_head clients;	/* DEPRECATED */
 	char name[48];
 	struct completion dev_released;
 };
@@ -357,10 +360,10 @@
  * command line
  */
 struct i2c_client_address_data {
-	unsigned short *normal_i2c;
-	unsigned short *probe;
-	unsigned short *ignore;
-	unsigned short **forces;
+	const unsigned short *normal_i2c;
+	const unsigned short *probe;
+	const unsigned short *ignore;
+	const unsigned short * const *forces;
 };
 
 /* Internal numbers to terminate lists */
@@ -389,11 +392,8 @@
 extern int i2c_attach_client(struct i2c_client *);
 extern int i2c_detach_client(struct i2c_client *);
 
-/* Should be used to make sure that client-struct is valid and that it
-   is okay to access the i2c-client.
-   returns -ENODEV if client has gone in the meantime */
-extern int i2c_use_client(struct i2c_client *);
-extern int i2c_release_client(struct i2c_client *);
+extern struct i2c_client *i2c_use_client(struct i2c_client *client);
+extern void i2c_release_client(struct i2c_client *client);
 
 /* call the i2c_client->command() of all attached clients with
  * the given arguments */
@@ -405,7 +405,7 @@
  * specific address (unless a 'force' matched);
  */
 extern int i2c_probe(struct i2c_adapter *adapter,
-		struct i2c_client_address_data *address_data,
+		const struct i2c_client_address_data *address_data,
 		int (*found_proc) (struct i2c_adapter *, int, int));
 
 extern struct i2c_adapter* i2c_get_adapter(int id);
@@ -598,104 +598,93 @@
 		       "additionally");					\
 I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to "	\
 		       "scan");						\
-static struct i2c_client_address_data addr_data = {			\
+const static struct i2c_client_address_data addr_data = {		\
 	.normal_i2c	= normal_i2c,					\
 	.probe		= probe,					\
 	.ignore		= ignore,					\
 	.forces		= forces,					\
 }
 
+#define I2C_CLIENT_FORCE_TEXT \
+	"List of adapter,address pairs to boldly assume to be present"
+
 /* These are the ones you want to use in your own drivers. Pick the one
    which matches the number of devices the driver differenciates between. */
-#define I2C_CLIENT_INSMOD \
-  I2C_CLIENT_MODULE_PARM(force, \
-                      "List of adapter,address pairs to boldly assume " \
-                      "to be present"); \
-	static unsigned short *forces[] = {				\
-			force,						\
-			NULL						\
-		};							\
+#define I2C_CLIENT_INSMOD						\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
+static const unsigned short * const forces[] = { force, NULL };		\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_1(chip1)					\
 enum chips { any_chip, chip1 };						\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
-static unsigned short *forces[] = { force, force_##chip1, NULL };	\
+static const unsigned short * const forces[] =	{ force,		\
+	force_##chip1, NULL };						\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_2(chip1, chip2)				\
 enum chips { any_chip, chip1, chip2 };					\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, NULL };		\
+static const unsigned short * const forces[] =	{ force,		\
+	force_##chip1, force_##chip2, NULL };				\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3)			\
 enum chips { any_chip, chip1, chip2, chip3 };				\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    NULL };				\
+static const unsigned short * const forces[] =	{ force,		\
+	force_##chip1, force_##chip2, force_##chip3, NULL };		\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4)			\
 enum chips { any_chip, chip1, chip2, chip3, chip4 };			\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip4);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    force_##chip4, NULL};		\
+static const unsigned short * const forces[] =	{ force,		\
+	force_##chip1, force_##chip2, force_##chip3,			\
+	force_##chip4, NULL};						\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5)		\
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 };		\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip4);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip5);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    force_##chip4, force_##chip5,	\
-				    NULL };				\
+static const unsigned short * const forces[] = { force,			\
+	force_##chip1, force_##chip2, force_##chip3,			\
+	force_##chip4, force_##chip5, NULL };				\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6)	\
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 };	\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip4);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip5);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip6);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    force_##chip4, force_##chip5,	\
-				    force_##chip6, NULL };		\
+static const unsigned short * const forces[] = { force,			\
+	force_##chip1, force_##chip2, force_##chip3,			\
+	force_##chip4, force_##chip5, force_##chip6, NULL };		\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,	\
 	     chip7 };							\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
@@ -703,18 +692,16 @@
 I2C_CLIENT_MODULE_PARM_FORCE(chip5);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip6);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip7);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    force_##chip4, force_##chip5,	\
-				    force_##chip6, force_##chip7,	\
-				    NULL };				\
+static const unsigned short * const forces[] = { force,			\
+	force_##chip1, force_##chip2, force_##chip3,			\
+	force_##chip4, force_##chip5, force_##chip6,			\
+	force_##chip7, NULL };						\
 I2C_CLIENT_INSMOD_COMMON
 
 #define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
 enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6,	\
 	     chip7, chip8 };						\
-I2C_CLIENT_MODULE_PARM(force, "List of adapter,address pairs to "	\
-		       "boldly assume to be present");			\
+I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT);			\
 I2C_CLIENT_MODULE_PARM_FORCE(chip1);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip2);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip3);					\
@@ -723,11 +710,10 @@
 I2C_CLIENT_MODULE_PARM_FORCE(chip6);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip7);					\
 I2C_CLIENT_MODULE_PARM_FORCE(chip8);					\
-static unsigned short *forces[] = { force, force_##chip1,		\
-				    force_##chip2, force_##chip3,	\
-				    force_##chip4, force_##chip5,	\
-				    force_##chip6, force_##chip7,	\
-				    force_##chip8, NULL };		\
+static const unsigned short * const forces[] = { force,			\
+	force_##chip1, force_##chip2, force_##chip3,			\
+	force_##chip4, force_##chip5, force_##chip6,			\
+	force_##chip7, force_##chip8, NULL };				\
 I2C_CLIENT_INSMOD_COMMON
 #endif /* __KERNEL__ */
 #endif /* _LINUX_I2C_H */
diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/linux/i2c/tps65010.h
similarity index 96%
rename from include/asm-arm/arch-omap/tps65010.h
rename to include/linux/i2c/tps65010.h
index b9aa2b3..7021635 100644
--- a/include/asm-arm/arch-omap/tps65010.h
+++ b/include/linux/i2c/tps65010.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-omap/tps65010.h
+/* linux/i2c/tps65010.h
  *
  * Functions to access TPS65010 power management device.
  *
@@ -25,8 +25,8 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef __ASM_ARCH_TPS65010_H
-#define __ASM_ARCH_TPS65010_H
+#ifndef __LINUX_I2C_TPS65010_H
+#define __LINUX_I2C_TPS65010_H
 
 /*
  * ----------------------------------------------------------------------------
@@ -152,5 +152,5 @@
  */
 extern int tps65013_set_low_pwr(unsigned mode);
 
-#endif /*  __ASM_ARCH_TPS65010_H */
+#endif /*  __LINUX_I2C_TPS65010_H */
 
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 1e44099..27cb39d 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -107,7 +107,6 @@
 #define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
 #define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
-#define DATA_READY		(DRQ_STAT)
 
 #define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
 
@@ -198,8 +197,11 @@
 } hw_regs_t;
 
 struct hwif_s * ide_find_port(unsigned long);
+void ide_init_port_data(struct hwif_s *, unsigned int);
+void ide_init_port_hw(struct hwif_s *, hw_regs_t *);
 
-int ide_register_hw(hw_regs_t *, void (*)(struct hwif_s *), int,
+struct ide_drive_s;
+int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *),
 		    struct hwif_s **);
 
 void ide_setup_ports(	hw_regs_t *hw,
@@ -391,7 +393,6 @@
 	u8	state;			/* retry state */
 	u8	waiting_for_dma;	/* dma currently in progress */
 	u8	unmask;			/* okay to unmask other irqs */
-	u8	bswap;			/* byte swap data */
 	u8	noflush;		/* don't attempt flushes */
 	u8	dsc_overlap;		/* DSC overlap */
 	u8	nice1;			/* give potential excess bandwidth */
@@ -527,31 +528,26 @@
 	/* special host masking for drive selection */
 	void	(*maskproc)(ide_drive_t *, int);
 	/* check host's drive quirk list */
-	int	(*quirkproc)(ide_drive_t *);
+	void	(*quirkproc)(ide_drive_t *);
 	/* driver soft-power interface */
 	int	(*busproc)(ide_drive_t *, int);
 #endif
 	u8 (*mdma_filter)(ide_drive_t *);
 	u8 (*udma_filter)(ide_drive_t *);
 
-	void (*fixup)(struct hwif_s *);
-
 	void (*ata_input_data)(ide_drive_t *, void *, u32);
 	void (*ata_output_data)(ide_drive_t *, void *, u32);
 
 	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
 	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
 
+	void (*dma_host_set)(ide_drive_t *, int);
 	int (*dma_setup)(ide_drive_t *);
 	void (*dma_exec_cmd)(ide_drive_t *, u8);
 	void (*dma_start)(ide_drive_t *);
 	int (*ide_dma_end)(ide_drive_t *drive);
-	int (*ide_dma_on)(ide_drive_t *drive);
-	void (*dma_off_quietly)(ide_drive_t *drive);
 	int (*ide_dma_test_irq)(ide_drive_t *drive);
 	void (*ide_dma_clear_irq)(ide_drive_t *drive);
-	void (*dma_host_on)(ide_drive_t *drive);
-	void (*dma_host_off)(ide_drive_t *drive);
 	void (*dma_lost_irq)(ide_drive_t *drive);
 	void (*dma_timeout)(ide_drive_t *drive);
 
@@ -874,14 +870,6 @@
 
 extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
-/*
- * Issue ATA command and wait for completion.
- * Use for implementing commands in kernel
- *
- *  (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
- */
-extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
-
 enum {
 	IDE_TFLAG_LBA48			= (1 << 0),
 	IDE_TFLAG_NO_SELECT_MASK	= (1 << 1),
@@ -934,6 +922,14 @@
 	IDE_TFLAG_IN_TF			= IDE_TFLAG_IN_NSECT |
 					  IDE_TFLAG_IN_LBA,
 	IDE_TFLAG_IN_DEVICE		= (1 << 29),
+	IDE_TFLAG_HOB			= IDE_TFLAG_OUT_HOB |
+					  IDE_TFLAG_IN_HOB,
+	IDE_TFLAG_TF			= IDE_TFLAG_OUT_TF |
+					  IDE_TFLAG_IN_TF,
+	IDE_TFLAG_DEVICE		= IDE_TFLAG_OUT_DEVICE |
+					  IDE_TFLAG_IN_DEVICE,
+	/* force 16-bit I/O operations */
+	IDE_TFLAG_IO_16BIT		= (1 << 30),
 };
 
 struct ide_taskfile {
@@ -988,6 +984,10 @@
 
 ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
 
+void task_end_request(ide_drive_t *, struct request *, u8);
+
+u8 wait_drive_not_busy(ide_drive_t *);
+
 int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
 int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
@@ -1015,10 +1015,9 @@
 
 void ide_init_disk(struct gendisk *, ide_drive_t *);
 
-extern int ideprobe_init(void);
-
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-extern void ide_scan_pcibus(int scan_direction) __init;
+extern int ide_scan_direction;
+int __init ide_scan_pcibus(void);
 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
@@ -1095,6 +1094,8 @@
 	/* unmask IRQs */
 	IDE_HFLAG_UNMASK_IRQS		= (1 << 25),
 	IDE_HFLAG_ABUSE_SET_DMA_MODE	= (1 << 26),
+	/* host is CY82C693 */
+	IDE_HFLAG_CY82C693		= (1 << 27),
 };
 
 #ifdef CONFIG_BLK_DEV_OFFBOARD
@@ -1109,7 +1110,6 @@
 	void			(*init_iops)(ide_hwif_t *);
 	void                    (*init_hwif)(ide_hwif_t *);
 	void			(*init_dma)(ide_hwif_t *, unsigned long);
-	void			(*fixup)(ide_hwif_t *);
 	ide_pci_enablebit_t	enablebits[2];
 	hwif_chipset_t		chipset;
 	u8			extra;
@@ -1147,7 +1147,9 @@
 	return ide_find_dma_mode(drive, XFER_UDMA_6);
 }
 
+void ide_dma_off_quietly(ide_drive_t *);
 void ide_dma_off(ide_drive_t *);
+void ide_dma_on(ide_drive_t *);
 int ide_set_dma(ide_drive_t *);
 ide_startstop_t ide_dma_intr(ide_drive_t *);
 
@@ -1158,10 +1160,7 @@
 extern int ide_release_dma(ide_hwif_t *);
 extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
 
-void ide_dma_host_off(ide_drive_t *);
-void ide_dma_off_quietly(ide_drive_t *);
-void ide_dma_host_on(ide_drive_t *);
-extern int __ide_dma_on(ide_drive_t *);
+void ide_dma_host_set(ide_drive_t *, int);
 extern int ide_dma_setup(ide_drive_t *);
 extern void ide_dma_start(ide_drive_t *);
 extern int __ide_dma_end(ide_drive_t *);
@@ -1173,7 +1172,9 @@
 static inline int ide_id_dma_bug(ide_drive_t *drive) { return 0; }
 static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; }
 static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
+static inline void ide_dma_off_quietly(ide_drive_t *drive) { ; }
 static inline void ide_dma_off(ide_drive_t *drive) { ; }
+static inline void ide_dma_on(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; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1203,8 +1204,9 @@
 void ide_register_region(struct gendisk *);
 void ide_unregister_region(struct gendisk *);
 
-void ide_undecoded_slave(ide_hwif_t *);
+void ide_undecoded_slave(ide_drive_t *);
 
+int ide_device_add_all(u8 *idx);
 int ide_device_add(u8 idx[4]);
 
 static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
@@ -1302,4 +1304,9 @@
 	return &hwif->drives[(drive->dn ^ 1) & 1];
 }
 
+static inline void ide_set_irq(ide_drive_t *drive, int on)
+{
+	drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG);
+}
+
 #endif /* _IDE_H */
diff --git a/include/linux/m41t00.h b/include/linux/m41t00.h
deleted file mode 100644
index b423360..0000000
--- a/include/linux/m41t00.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Definitions for the ST M41T00 family of i2c rtc chips.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef _M41T00_H
-#define _M41T00_H
-
-#define	M41T00_DRV_NAME		"m41t00"
-#define	M41T00_I2C_ADDR		0x68
-
-#define	M41T00_TYPE_M41T00	0
-#define	M41T00_TYPE_M41T81	81
-#define	M41T00_TYPE_M41T85	85
-
-struct m41t00_platform_data {
-	u8	type;
-	u8	i2c_addr;
-	u8	sqw_freq;
-};
-
-/* SQW output disabled, this is default value by power on */
-#define M41T00_SQW_DISABLE	(0)
-
-#define M41T00_SQW_32KHZ	(1<<4)		/* 32.768 KHz */
-#define M41T00_SQW_8KHZ		(2<<4)		/* 8.192 KHz */
-#define M41T00_SQW_4KHZ		(3<<4)		/* 4.096 KHz */
-#define M41T00_SQW_2KHZ		(4<<4)		/* 2.048 KHz */
-#define M41T00_SQW_1KHZ		(5<<4)		/* 1.024 KHz */
-#define M41T00_SQW_512HZ	(6<<4)		/* 512 Hz */
-#define M41T00_SQW_256HZ	(7<<4)		/* 256 Hz */
-#define M41T00_SQW_128HZ	(8<<4)		/* 128 Hz */
-#define M41T00_SQW_64HZ		(9<<4)		/* 64 Hz */
-#define M41T00_SQW_32HZ		(10<<4)		/* 32 Hz */
-#define M41T00_SQW_16HZ		(11<<4)		/* 16 Hz */
-#define M41T00_SQW_8HZ		(12<<4)		/* 8 Hz */
-#define M41T00_SQW_4HZ		(13<<4)		/* 4 Hz */
-#define M41T00_SQW_2HZ		(14<<4)		/* 2 Hz */
-#define M41T00_SQW_1HZ		(15<<4)		/* 1 Hz */
-
-extern ulong m41t00_get_rtc_time(void);
-extern int m41t00_set_rtc_time(ulong nowtime);
-
-#endif /* _M41T00_H */
diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h
index 2418542..e764557 100644
--- a/include/media/v4l2-i2c-drv-legacy.h
+++ b/include/media/v4l2-i2c-drv-legacy.h
@@ -34,7 +34,7 @@
 };
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data;
-static struct i2c_client_address_data addr_data;
+static const struct i2c_client_address_data addr_data;
 static struct i2c_driver v4l2_i2c_driver_legacy;
 static char v4l2_i2c_drv_name_legacy[32];
 
diff --git a/kernel/printk.c b/kernel/printk.c
index 423a8c7..3b7c968 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -702,9 +702,7 @@
 					loglev_char = default_message_loglevel
 						+ '0';
 				}
-				t = 0;
-				if (system_state != SYSTEM_BOOTING)
-					t = ktime_to_ns(ktime_get());
+				t = cpu_clock(printk_cpu);
 				nanosec_rem = do_div(t, 1000000000);
 				tlen = sprintf(tbuf,
 						"<%c>[%5lu.%06lu] ",
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index a68425a..d8a5558 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -1,6 +1,5 @@
 #include <linux/stat.h>
 #include <linux/sysctl.h>
-#include "../arch/s390/appldata/appldata.h"
 #include "../fs/xfs/linux-2.6/xfs_sysctl.h"
 #include <linux/sunrpc/debug.h>
 #include <linux/string.h>
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f83b19d..4bf715d 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1744,6 +1744,9 @@
 	struct ocontext *c;
 	int rc = 0, cmp = 0;
 
+	while (path[0] == '/' && path[1] == '/')
+		path++;
+
 	POLICY_RDLOCK;
 
 	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index b48c729..8849041 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -835,7 +835,7 @@
 static irqreturn_t
 waveartist_intr(int irq, void *dev_id)
 {
-	wavnc_info *devc = (wavnc_info *)dev_id;
+	wavnc_info *devc = dev_id;
 	int	   irqstatus, status;
 
 	spin_lock(&waveartist_lock);
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 272ae38..bb7d744 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -34,8 +34,6 @@
 static struct pmac_keywest *keywest_ctx;
 
 
-#define I2C_DRIVERID_KEYWEST	0xFEBA
-
 static int keywest_attach_adapter(struct i2c_adapter *adapter);
 static int keywest_detach_client(struct i2c_client *client);
 
@@ -43,7 +41,6 @@
 	.driver = {
 		.name = "PMac Keywest Audio",
 	},
-	.id = I2C_DRIVERID_KEYWEST,
 	.attach_adapter = &keywest_attach_adapter,
 	.detach_client = &keywest_detach_client,
 };
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index abac628..dab22cc 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -234,7 +234,7 @@
  * lower three bits are determined via the AD2, AD1, and AD0 pins
  * (respectively).
  */
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END
 };
 I2C_CLIENT_INSMOD;
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index d5a8fc2..f1f6b94 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -573,7 +573,7 @@
 
 static struct i2c_client client_template;
 
-static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
 
 /* Magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;