Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm

* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (60 commits)
  [ARM] 4524/1: S3C: Move register out of include/asm-arm/arch-s3c2410
  [ARM] 4523/1: S3C: Remove FIFO_MAX from uncompression headers
  [ARM] 4522/1: S3C: split include/asm-arm/arch/memory.h
  [ARM] 4521/2: S3C: Reorganise VA mapping headers
  [ARM] 4520/1: S3C: Remove old VA values from static map
  [ARM] 4519/1: S3C: split S3C2400 values out of S3C24XX map.h
  [ARM] 4518/1: S3C: Rename watchdog configuration options
  [ARM] 4517/1: S3C: Fix debug macros for ARM926 output
  [ARM] 4516/1: S3C: Fix uncompressor serial output for ARM926
  [ARM] 4515/1: S3C: Move uncompress code to plat-s3c
  [ARM] 4514/1: S3C: Rename DEBUG_S3C2410_PORT and DEBUG_S3C_UART
  [ARM] 4513/1: S3C: Rename CONFIG_S3C2410_LOWLEVEL_UART_PORT
  [ARM] 4512/1: S3C: rename the debug macros for per-cpu updates
  [ARM] 4511/1: S3C: updated LLSERIAL Kconfig defines for CPU support
  [ARM] 4510/1: S3C: split debug-macro support into plat-s3c
  [ARM] 4509/1: S3C: Create initial arch/arm/plat-s3c
  [ARM] 4508/1: S3C: Move items to include/asm-arm/plat-s3c
  [ARM] 4461/1: MXC platform and i.MX31ADS core support
  [ARM] 4507/1: pxa2xx clock_event_device
  [ARM] 4497/1: Only allow safe cache configurations on ARMv6 and later
  ...
diff --git a/.gitignore b/.gitignore
index 8d15830..a232295 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
 tags
 TAGS
 vmlinux*
+!vmlinux.lds.S
 System.map
 Module.symvers
 
diff --git a/CREDITS b/CREDITS
index 79fd13d..10c214d 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2212,13 +2212,13 @@
 S: Denmark
 
 N: Claudio S. Matsuoka
-E: claudio@conectiva.com
-E: claudio@helllabs.org
+E: cmatsuoka@gmail.com
+E: claudio@mandriva.com
 W: http://helllabs.org/~claudio
-D: V4L, OV511 driver hacks
+D: V4L, OV511 and HDA-codec hacks
 S: Conectiva S.A.
-S: R. Tocantins 89
-S: 80050-430  Curitiba PR
+S: Souza Naves 1250
+S: 80050-040  Curitiba PR
 S: Brazil
 
 N: Heinz Mauelshagen
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index a5cb783..c175eed 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -180,24 +180,11 @@
 
 ---------------------------
 
-What:	/sys/firmware/acpi/namespace
-When:	2.6.21
-Why:	The ACPI namespace is effectively the symbol list for
-	the BIOS.  The device names are completely arbitrary
-	and have no place being exposed to user-space.
-
-	For those interested in the BIOS ACPI namespace,
-	the BIOS can be extracted and disassembled with acpidump
-	and iasl as documented in the pmtools package here:
-	http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
-Who:	Len Brown <len.brown@intel.com>
-
----------------------------
-
 What:	ACPI procfs interface
-When:	July 2007
-Why:	After ACPI sysfs conversion, ACPI attributes will be duplicated
-	in sysfs and the ACPI procfs interface should be removed.
+When:	July 2008
+Why:	ACPI sysfs conversion should be finished by January 2008.
+	ACPI procfs interface will be removed in July 2008 so that
+	there is enough time for the user space to catch up.
 Who:	Zhang Rui <rui.zhang@intel.com>
 
 ---------------------------
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a54148..fb80e9f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1154,6 +1154,8 @@
 
 	nointroute	[IA-64]
 
+	nojitter	[IA64] Disables jitter checking for ITC timers.
+
 	nolapic		[IA-32,APIC] Do not enable or use the local APIC.
 
 	nolapic_timer	[IA-32,APIC] Do not use the local APIC timer.
@@ -1880,11 +1882,14 @@
 	usbhid.mousepoll=
 			[USBHID] The interval which mice are to be polled at.
 
-	vdso=		[IA-32,SH]
+	vdso=		[IA-32,SH,x86-64]
 			vdso=2: enable compat VDSO (default with COMPAT_VDSO)
 			vdso=1: enable VDSO (default)
 			vdso=0: disable VDSO mapping
 
+	vector=		[IA-64,SMP]
+			vector=percpu: enable percpu vector domain
+
 	video=		[FB] Frame buffer configuration
 			See Documentation/fb/modedb.txt.
 
diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt
index af1a282..04dc1cf 100644
--- a/Documentation/power/freezing-of-tasks.txt
+++ b/Documentation/power/freezing-of-tasks.txt
@@ -155,6 +155,8 @@
 only through another device that hasn't been resumed yet.  In that case,
 request_firmware() will fail regardless of whether or not the freezing of tasks
 is used.  Consequently, the problem is not really related to the freezing of
-tasks, since it generally exists anyway.  [The solution to this particular
-problem is to keep the firmware in memory after it's loaded for the first time
-and upload if from memory to the device whenever necessary.]
+tasks, since it generally exists anyway.
+
+A driver must have all firmwares it may need in RAM before suspend() is called.
+If keeping them is not practical, for example due to their size, they must be
+requested early enough using the suspend notifier API described in notifiers.txt.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 355ff0a..241e26c 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -467,7 +467,12 @@
     above explicitly.
 
     The power-management is supported.
-    
+
+  Module snd-cs5530
+  _________________
+
+    Module for Cyrix/NatSemi Geode 5530 chip. 
+  
   Module snd-cs5535audio
   ----------------------
 
@@ -759,6 +764,7 @@
 
     model	- force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
     single_cmd  - Use single immediate commands to communicate with
 		codecs (for debugging only)
     enable_msi	- Enable Message Signaled Interrupt (MSI) (default = off)
@@ -803,6 +809,8 @@
 	  hp-3013	HP machines (3013-variant)
 	  fujitsu	Fujitsu S7020
 	  acer		Acer TravelMate
+	  will		Will laptops (PB V7900)
+	  replacer	Replacer 672V
 	  basic		fixed pin assignment (old default model)
 	  auto		auto-config reading BIOS (default)
 
@@ -811,16 +819,31 @@
 	  hp-bpc	HP xw4400/6400/8400/9400 laptops
 	  hp-bpc-d7000	HP BPC D7000
 	  benq		Benq ED8
+	  benq-t31	Benq T31
 	  hippo		Hippo (ATI) with jack detection, Sony UX-90s
 	  hippo_1	Hippo (Benq) with jack detection
+	  sony-assamd	Sony ASSAMD
 	  basic		fixed pin assignment w/o SPDIF
 	  auto		auto-config reading BIOS (default)
 
+	ALC268
+	  3stack	3-stack model
+	  auto		auto-config reading BIOS (default)
+
+	ALC662
+	  3stack-dig	3-stack (2-channel) with SPDIF
+	  3stack-6ch	 3-stack (6-channel)
+	  3stack-6ch-dig 3-stack (6-channel) with SPDIF
+	  6stack-dig	 6-stack with SPDIF
+	  lenovo-101e	 Lenovo laptop
+	  auto		auto-config reading BIOS (default)
+
 	ALC882/885
 	  3stack-dig	3-jack with SPDIF I/O
 	  6stack-dig	6-jack digital with SPDIF I/O
 	  arima		Arima W820Di1
 	  macpro	MacPro support
+	  imac24	iMac 24'' with jack detection
 	  w2jc		ASUS W2JC
 	  auto		auto-config reading BIOS (default)
 
@@ -832,9 +855,15 @@
 	  6stack-dig-demo  6-jack digital for Intel demo board
 	  acer		Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
 	  medion	Medion Laptops
+	  medion-md2	Medion MD2
 	  targa-dig	Targa/MSI
 	  targa-2ch-dig	Targs/MSI with 2-channel
 	  laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+	  lenovo-101e	Lenovo 101E
+	  lenovo-nb0763	Lenovo NB0763
+	  lenovo-ms7195-dig Lenovo MS7195
+	  6stack-hp	HP machines with 6stack (Nettle boards)
+	  3stack-hp	HP machines with 3stack (Lucknow, Samba boards)
 	  auto		auto-config reading BIOS (default)
 
 	ALC861/660
@@ -853,7 +882,9 @@
 	  3stack-dig	3-jack with SPDIF OUT
 	  6stack-dig	6-jack with SPDIF OUT
 	  3stack-660	3-jack (for ALC660VD)
+	  3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
 	  lenovo	Lenovo 3000 C200
+	  dallas	Dallas laptops
 	  auto		auto-config reading BIOS (default)
 
 	CMI9880
@@ -864,12 +895,26 @@
 	  allout	5-jack in back, 2-jack in front, SPDIF out
 	  auto		auto-config reading BIOS (default)
 
+	AD1882
+	  3stack	3-stack mode (default)
+	  6stack	6-stack mode
+
+	AD1884
+	  N/A
+
 	AD1981
 	  basic		3-jack (default)
 	  hp		HP nx6320
 	  thinkpad	Lenovo Thinkpad T60/X60/Z60
 	  toshiba	Toshiba U205
 
+	AD1983
+	  N/A
+
+	AD1984
+	  basic		default configuration
+	  thinkpad	Lenovo Thinkpad T61/X61
+
 	AD1986A
 	  6stack	6-jack, separate surrounds (default)
 	  3stack	3-stack, shared surrounds
@@ -907,11 +952,18 @@
 	  ref		Reference board
 	  3stack	D945 3stack
 	  5stack	D945 5stack + SPDIF
-	  macmini	Intel Mac Mini
-	  macbook	Intel Mac Book
-	  macbook-pro-v1 Intel Mac Book Pro 1st generation
-	  macbook-pro	Intel Mac Book Pro 2nd generation
-	  imac-intel	Intel iMac
+	  dell		Dell XPS M1210
+	  intel-mac-v1	Intel Mac Type 1
+	  intel-mac-v2	Intel Mac Type 2
+	  intel-mac-v3	Intel Mac Type 3
+	  intel-mac-v4	Intel Mac Type 4
+	  intel-mac-v5	Intel Mac Type 5
+	  macmini	Intel Mac Mini (equivalent with type 3)
+	  macbook	Intel Mac Book (eq. type 5)
+	  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+	  macbook-pro	Intel Mac Book Pro 2nd generation (eq. type 3)
+	  imac-intel	Intel iMac (eq. type 2)
+	  imac-intel-20	Intel iMac (newer version) (eq. type 3)
 
 	STAC9202/9250/9251
 	  ref		Reference board, base config
@@ -956,6 +1008,17 @@
     from the irq.  Remember this is a last resort, and should be
     avoided as much as possible...
     
+    MORE NOTES ON "azx_get_response timeout" PROBLEMS:
+    On some hardwares, you may need to add a proper probe_mask option
+    to avoid the "azx_get_response timeout" problem above, instead.
+    This occurs when the access to non-existing or non-working codec slot
+    (likely a modem one) causes a stall of the communication via HD-audio
+    bus.  You can see which codec slots are probed by enabling
+    CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec
+    proc files.  Then limit the slots to probe by probe_mask option.
+    For example, probe_mask=1 means to probe only the first slot, and
+    probe_mask=4 means only the third slot.
+
     The power-management is supported.
 
   Module snd-hdsp
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
index e40cce8..2ad5e63 100644
--- a/Documentation/sound/alsa/Audiophile-Usb.txt
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -1,4 +1,4 @@
-	Guide to using M-Audio Audiophile USB with ALSA and Jack	v1.3
+	Guide to using M-Audio Audiophile USB with ALSA and Jack	v1.5
 	========================================================
 
 	    Thibault Le Meur <Thibault.LeMeur@supelec.fr>
@@ -6,8 +6,19 @@
 This document is a guide to using the M-Audio Audiophile USB (tm) device with 
 ALSA and JACK.
 
+History
+=======
+* v1.4 - Thibault Le Meur (2007-07-11)
+ - Added Low Endianness nature of 16bits-modes
+   found by Hakan Lennestal <Hakan.Lennestal@brfsodrahamn.se>
+ - Modifying document structure
+* v1.5 - Thibault Le Meur (2007-07-12)
+ - Added AC3/DTS passthru info
+
+
 1 - Audiophile USB Specs and correct usage
 ==========================================
+
 This part is a reminder of important facts about the functions and limitations 
 of the device.
 
@@ -25,18 +36,18 @@
 The internal DAC/ADC has the following characteristics:
 * sample depth of 16 or 24 bits
 * sample rate from 8kHz to 96kHz
-* Two ports can't use different sample depths at the same time. Moreover, the 
-Audiophile USB documentation gives the following Warning: "Please exit any 
-audio application running before switching between bit depths"
+* Two interfaces can't use different sample depths at the same time.
+Moreover, the Audiophile USB documentation gives the following Warning:
+"Please exit any audio application running before switching between bit depths"
 
 Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be 
 activated at the same time depending on the audio mode selected:
- * 16-bit/48kHz ==> 4 channels in/4 channels out
+ * 16-bit/48kHz ==> 4 channels in + 4 channels out
    - Ai+Ao+Di+Do
- * 24-bit/48kHz ==> 4 channels in/2 channels out, 
-                    or 2 channels in/4 channels out
+ * 24-bit/48kHz ==> 4 channels in + 2 channels out, 
+                    or 2 channels in + 4 channels out
    - Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
- * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+ * 24-bit/96kHz ==> 2 channels in _or_ 2 channels out (half duplex only)
    - Ai or Ao or Di or Do
 
 Important facts about the Digital interface:
@@ -52,44 +63,56 @@
 synchronization error (for instance sound played at an odd sample rate)
 
 
-2 - Audiophile USB support in ALSA
-==================================
+2 - Audiophile USB MIDI support in ALSA
+=======================================
 
-2.1 - MIDI ports
-----------------
-The Audiophile USB MIDI ports will be automatically supported once the 
+The Audiophile USB MIDI ports will be automatically supported once the
 following modules have been loaded:
  * snd-usb-audio
  * snd-seq-midi
 
 No additional setting is required.
 
-2.2 - Audio ports
------------------
+
+3 - Audiophile USB Audio support in ALSA
+========================================
 
 Audio functions of the Audiophile USB device are handled by the snd-usb-audio 
 module. This module can work in a default mode (without any device-specific 
 parameter), or in an "advanced" mode with the device-specific parameter called 
 "device_setup".
 
-2.2.1 - Default Alsa driver mode
+3.1 - Default Alsa driver mode
+------------------------------
 
-The default behavior of the snd-usb-audio driver is to parse the device 
-capabilities at startup and enable all functions inside the device (including 
-all ports at any supported sample rates and sample depths). This approach 
-has the advantage to let the driver easily switch from sample rates/depths 
-automatically according to the need of the application claiming the device.
+The default behavior of the snd-usb-audio driver is to list the device 
+capabilities at startup and activate the required mode when required 
+by the applications: for instance if the user is recording in a 
+24bit-depth-mode and immediately after wants to switch to a 16bit-depth mode,
+the snd-usb-audio module will reconfigure the device on the fly.
 
-In this case the Audiophile ports are mapped to alsa pcm devices in the 
-following way (I suppose the device's index is 1):
+This approach has the advantage to let the driver automatically switch from sample 
+rates/depths automatically according to the user's needs. However, those who 
+are using the device under windows know that this is not how the device is meant to
+work: under windows applications must be closed before using the m-audio control
+panel to switch the device working mode. Thus as we'll see in next section, this 
+Default Alsa driver mode can lead to device misconfigurations.
+
+Let's get back to the Default Alsa driver mode for now.  In this case the 
+Audiophile interfaces are mapped to alsa pcm devices in the following 
+way (I suppose the device's index is 1):
  * hw:1,0 is Ao in playback and Di in capture
  * hw:1,1 is Do in playback and Ai in capture
  * hw:1,2 is Do in AC3/DTS passthrough mode
 
-You must note as well that the device uses Big Endian byte encoding so that 
-supported audio format are S16_BE  for 16-bit depth modes and S24_3BE for 
-24-bits depth mode. One exception is the hw:1,2 port which is Little Endian 
-compliant and thus uses S16_LE.
+In this mode, the device uses Big Endian byte-encoding so that 
+supported audio format are S16_BE for 16-bit depth modes and S24_3BE for 
+24-bits depth mode.
+
+One exception is the hw:1,2 port which was reported to be Little Endian 
+compliant (supposedly supporting S16_LE) but processes in fact only S16_BE streams.
+This has been fixed in kernel 2.6.23 and above and now the hw:1,2 interface 
+is reported to be big endian in this default driver mode.
 
 Examples:
  * playing a S24_3BE encoded raw file to the Ao port
@@ -98,22 +121,26 @@
    % arecord -D hw:1,1 -c2  -t raw -r48000 -fS24_3BE test.raw
  * playing a S16_BE encoded raw file to the Do port
    % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+ * playing an ac3 sample file to the Do port
+   % aplay -D hw:1,2 --channels=6 ac3_S16_BE_encoded_file.raw
 
-If you're happy with the default Alsa driver setup and don't experience any 
+If you're happy with the default Alsa driver mode and don't experience any 
 issue with this mode, then you can skip the following chapter.
 
-2.2.2 - Advanced module setup
+3.2 - Advanced module setup
+---------------------------
 
 Due to the hardware constraints described above, the device initialization made 
 by the Alsa driver in default mode may result in a corrupted state of the 
 device. For instance, a particularly annoying issue is that the sound captured 
-from the Ai port sounds distorted (as if boosted with an excessive high volume 
-gain).
+from the Ai interface sounds distorted (as if boosted with an excessive high
+volume gain).
 
 For people having this problem, the snd-usb-audio module has a new module 
-parameter called "device_setup".
+parameter called "device_setup" (this parameter was introduced in kernel
+release 2.6.17)
 
-2.2.2.1 - Initializing the working mode of the Audiophile USB
+3.2.1 - Initializing the working mode of the Audiophile USB
 
 As far as the Audiophile USB device is concerned, this value let the user 
 specify:
@@ -121,33 +148,57 @@
  * the sample rate
  * whether the Di port is used or not 
 
-Here is a list of supported device_setup values for this device:
- * device_setup=0x00 (or omitted)
-   - Alsa driver default mode
-   - maintains backward compatibility with setups that do not use this 
-     parameter by not introducing any change
-   - results sometimes in corrupted sound as described earlier
+When initialized with "device_setup=0x00", the snd-usb-audio module has
+the same behaviour as when the parameter is omitted (see paragraph "Default 
+Alsa driver mode" above)
+
+Others modes are described in the following subsections.
+
+3.2.1.1 - 16-bit modes
+
+The two supported modes are:
+
  * device_setup=0x01
    - 16bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x11
    - 16bits 48kHz mode with Di enabled
    - Ai,Ao,Di,Do can be used at the same time
    - hw:1,0 is available in capture mode
    - hw:1,2 is not available
+
+In this modes the device operates only at 16bits-modes. Before kernel 2.6.23,
+the devices where reported to be Big-Endian when in fact they were Little-Endian
+so that playing a file was a matter of using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test_S16_LE.raw
+where "test_S16_LE.raw" was in fact a little-endian sample file.
+
+Thanks to Hakan Lennestal (who discovered the Little-Endiannes of the device in
+these modes) a fix has been committed (expected in kernel 2.6.23) and
+Alsa now reports Little-Endian interfaces. Thus playing a file now is as simple as
+using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_LE test_S16_LE.raw
+
+3.2.1.2 - 24-bit modes
+
+The three supported modes are:
+
  * device_setup=0x09
    - 24bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x19
    - 24bits 48kHz mode with Di enabled
    - 3 ports from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in capture mode and an active digital source must be 
      connected to Di
    - hw:1,2 is not available
+
  * device_setup=0x0D or 0x10
    - 24bits 96kHz mode
    - Di is enabled by default for this mode but does not need to be connected 
@@ -155,34 +206,64 @@
    - Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in captured mode
    - hw:1,2 is not available
+
+In these modes the device is only Big-Endian compliant (see "Default Alsa driver 
+mode" above for an aplay command example)
+
+3.2.1.3 - AC3 w/ DTS passthru mode
+
+Thanks to Hakan Lennestal, I now have a report saying that this mode works.
+
  * device_setup=0x03
    - 16bits 48kHz mode with only the Do port enabled 
-   - AC3 with DTS passthru (not tested)
+   - AC3 with DTS passthru
    - Caution with this setup the Do port is mapped to the pcm device hw:1,0
 
-2.2.2.2 - Setting and switching configurations with the device_setup parameter
+The command line used to playback the AC3/DTS encoded .wav-files in this mode:
+   % aplay -D hw:1,0 --channels=6 ac3_S16_LE_encoded_file.raw
+
+3.2.2 - How to use the device_setup parameter
+----------------------------------------------
 
 The parameter can be given:
+
  * By manually probing the device (as root):
    # modprobe -r snd-usb-audio
    # modprobe snd-usb-audio index=1 device_setup=0x09
+
  * Or while configuring the modules options in your modules configuration file
    - For Fedora distributions, edit the /etc/modprobe.conf file:
        alias snd-card-1 snd-usb-audio
        options snd-usb-audio index=1 device_setup=0x09
 
-IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
--------------------------------------------
- * You may need to _first_ initialize the module with the correct device_setup 
-   parameter and _only_after_ turn on the Audiophile USB device
- * This is especially true when switching the sample depth:
+CAUTION when initializaing the device
+-------------------------------------
+
+ * Correct initialization on the device requires that device_setup is given to
+   the module BEFORE the device is turned on. So, if you use the "manual probing"
+   method described above, take care to power-on the device AFTER this initialization.
+
+ * Failing to respect this will lead in a misconfiguration of the device. In this case
+   turn off the device, unproble the snd-usb-audio module, then probe it again with 
+   correct device_setup parameter and then (and only then) turn on the device again.
+
+ * If you've correctly initialized the device in a valid mode and then want to switch
+   to  another mode (possibly with another sample-depth), please use also the following 
+   procedure:
    - first turn off the device
    - de-register the snd-usb-audio module (modprobe -r)
    - change the device_setup parameter by changing the device_setup
      option in /etc/modprobe.conf 
    - turn on the device
+ * A workaround for this last issue has been applied to kernel 2.6.23, but it may not
+   be enough to ensure the 'stability' of the device initialization.
 
-2.2.2.3 - Audiophile USB's device_setup structure
+3.2.3 - Technical details for hackers
+-------------------------------------
+This section is for hackers, wanting to understand details about the device
+internals and how Alsa supports it.
+
+3.2.3.1 - Audiophile USB's device_setup structure
 
 If you want to understand the device_setup magic numbers for the Audiophile 
 USB, you need some very basic understanding of binary computation. However, 
@@ -228,12 +309,12 @@
    - choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
      only be able to use one at the same time
 
-2.2.3 -  USB implementation details for this device
+3.2.3.2 -  USB implementation details for this device
 
 You may safely skip this section if you're not interested in driver 
-development.
+hacking.
 
-This section describes some internal aspects of the device and summarize the 
+This section describes some internal aspects of the device and summarizes the 
 data I got by usb-snooping the windows and Linux drivers.
 
 The M-Audio Audiophile USB has 7 USB Interfaces:
@@ -293,43 +374,45 @@
 "audiophile_skip_setting_quirk" in order to prevent AltSettings not 
 corresponding to device_setup from being registered in the driver.
 
-3 - Audiophile USB and Jack support
+4 - Audiophile USB and Jack support
 ===================================
 
 This section deals with support of the Audiophile USB device in Jack.
-The main issue regarding this support is that the device is Big Endian 
-compliant.
 
-3.1 - Using the plug alsa plugin
---------------------------------
+There are 2 main potential issues when using Jackd with the device:
+* support for Big-Endian devices in 24-bit modes
+* support for 4-in / 4-out channels
 
-Jack doesn't directly support big endian devices. Thus, one way to have support 
-for this device with Alsa is to use the Alsa "plug" converter.
+4.1 - Direct support in Jackd
+-----------------------------
+
+Jack supports big endian devices only in recent versions (thanks to
+Andreas Steinmetz for his first big-endian patch). I can't remember 
+extacly when this support was released into jackd, let's just say that 
+with jackd version 0.103.0 it's almost ok (just a small bug is affecting 
+16bits Big-Endian devices, but since you've read  carefully the above 
+paragraphs, you're now using kernel >= 2.6.23 and your 16bits devices 
+are now Little Endians ;-) ).
+
+You can run jackd with the following command for playback with Ao and
+record with Ai:
+  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
+4.2 - Using Alsa plughw
+-----------------------
+If you don't have a recent Jackd installed, you can downgrade to using
+the Alsa "plug" converter.
 
 For instance here is one way to run Jack with 2 playback channels on Ao and 2 
 capture channels from Ai:
   % jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
 
-
 However you may see the following warning message:
 "You appear to be using the ALSA software "plug" layer, probably a result of 
 using the "default" ALSA device. This is less efficient than it could be. 
 Consider using a hardware device instead rather than using the plug layer."
 
-3.2 - Patching alsa to use direct pcm device
---------------------------------------------
-A patch for Jack by Andreas Steinmetz adds support for Big Endian devices. 
-However it has not been included in the CVS tree.
-
-You can find it at the following URL:
-http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
-atid=425939
-
-After having applied the patch you can run jackd with the following command 
-line:
-  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
-
-3.2 - Getting 2 input and/or output interfaces in Jack
+4.3 - Getting 2 input and/or output interfaces in Jack
 ------------------------------------------------------
 
 As you can see, starting the Jack server this way will only enable 1 stereo
@@ -339,6 +422,7 @@
 * Jack can only open one capture device and one playback device at a time
 * The Audiophile USB is seen as 2 (or three) Alsa devices: hw:1,0, hw:1,1
   (and optionally hw:1,2)
+
 If you want to get Ai+Di and/or Ao+Do support with Jack, you would need to
 combine the Alsa devices into one logical "complex" device.
 
@@ -348,13 +432,11 @@
 the Audiophile USB.
 
 Enabling multiple Audiophile USB interfaces for Jackd will certainly require:
-* patching Jack with the previously mentioned "Big Endian" patch
-* patching Jackd with the MMAP_COMPLEX patch (see the ice1712 page)
-* patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
+* Making sure your Jackd version has the MMAP_COMPLEX patch (see the ice1712 page)
+* (maybe) patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
 * define a multi device (combination of hw:1,0 and hw:1,1) in your .asoundrc
   file 
 * start jackd with this device
 
-I had no success in testing this for now, but this may be due to my OS
-configuration. If you have any success with this kind of setup, please
-drop me an email.
+I had no success in testing this for now, if you have any success with this kind 
+of setup, please drop me an email.
diff --git a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt
index ec2a025..bfa0c9a 100644
--- a/Documentation/sound/alsa/OSS-Emulation.txt
+++ b/Documentation/sound/alsa/OSS-Emulation.txt
@@ -278,6 +278,21 @@
 image.
 
 
+Duplex Streams
+==============
+
+Note that when attempting to use a single device file for playback and
+capture, the OSS API provides no way to set the format, sample rate or
+number of channels different in each direction.  Thus
+	io_handle = open("device", O_RDWR)
+will only function correctly if the values are the same in each direction.
+
+To use different values in the two directions, use both
+	input_handle = open("device", O_RDONLY)
+	output_handle = open("device", O_WRONLY)
+and set the values for the corresponding handle.
+
+
 Unsupported Features
 ====================
 
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index 9e6b94f..6711fbc 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,11 +1,11 @@
 		     ThinkPad ACPI Extras Driver
 
-                            Version 0.14
-                          April 21st, 2007
+                            Version 0.15
+                           July 1st, 2007
 
                Borislav Deianov <borislav@users.sf.net>
-	     Henrique de Moraes Holschuh <hmh@hmh.eng.br>
-		      http://ibm-acpi.sf.net/
+             Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+                      http://ibm-acpi.sf.net/
 
 
 This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
@@ -134,54 +134,68 @@
 subsystems are not documented here, nor are they tracked by this
 attribute.
 
+Changes to the thinkpad-acpi sysfs interface are only considered
+non-experimental when they are submitted to Linux mainline, at which
+point the changes in this interface are documented and interface_version
+may be updated.  If you are using any thinkpad-acpi features not yet
+sent to mainline for merging, you do so on your own risk: these features
+may disappear, or be implemented in a different and incompatible way by
+the time they are merged in Linux mainline.
+
+Changes that are backwards-compatible by nature (e.g. the addition of
+attributes that do not change the way the other attributes work) do not
+always warrant an update of interface_version.  Therefore, one must
+expect that an attribute might not be there, and deal with it properly
+(an attribute not being there *is* a valid way to make it clear that a
+feature is not available in sysfs).
+
 Hot keys
 --------
 
 procfs: /proc/acpi/ibm/hotkey
 sysfs device attribute: hotkey_*
 
-Without this driver, only the Fn-F4 key (sleep button) generates an
-ACPI event. With the driver loaded, the hotkey feature enabled and the
-mask set (see below), the various hot keys generate ACPI events in the
+In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
+some important events and also keyboard hot key presses to the operating
+system.  Enabling the hotkey functionality of thinkpad-acpi signals the
+firmware that such a driver is present, and modifies how the ThinkPad
+firmware will behave in many situations.
+
+When the hotkey feature is enabled and the hot key mask is set (see
+below), the various hot keys either generate ACPI events in the
 following format:
 
 	ibm/hotkey HKEY 00000080 0000xxxx
 
-The last four digits vary depending on the key combination pressed.
-All labeled Fn-Fx key combinations generate distinct events. In
-addition, the lid microswitch and some docking station buttons may
-also generate such events.
+or events over the input layer.  The input layer support accepts the
+standard IOCTLs to remap the keycodes assigned to each hotkey.
 
-The bit mask allows some control over which hot keys generate ACPI
-events. Not all bits in the mask can be modified. Not all bits that
-can be modified do anything. Not all hot keys can be individually
-controlled by the mask. Most recent ThinkPad models honor the
-following bits (assuming the hot keys feature has been enabled):
+When the input device is open, the driver will suppress any ACPI hot key
+events that get translated into a meaningful input layer event, in order
+to avoid sending duplicate events to userspace.  Hot keys that are
+mapped to KEY_RESERVED in the keymap are not translated, and will always
+generate an ACPI ibm/hotkey HKEY event, and no input layer events.
 
-	key	bit	behavior when set	behavior when unset
+The hot key bit mask allows some control over which hot keys generate
+events.  If a key is "masked" (bit set to 0 in the mask), the firmware
+will handle it.  If it is "unmasked", it signals the firmware that
+thinkpad-acpi would prefer to handle it, if the firmware would be so
+kind to allow it (and it often doesn't!).
 
-	Fn-F3			always generates ACPI event
-	Fn-F4			always generates ACPI event
-	Fn-F5	0010	generate ACPI event	enable/disable Bluetooth
-	Fn-F7	0040	generate ACPI event	switch LCD and external display
-	Fn-F8	0080	generate ACPI event	expand screen or none
-	Fn-F9	0100	generate ACPI event	none
-	Fn-F12			always generates ACPI event
+Not all bits in the mask can be modified.  Not all bits that can be
+modified do anything.  Not all hot keys can be individually controlled
+by the mask.  Some models do not support the mask at all, and in those
+models, hot keys cannot be controlled individually.  The behaviour of
+the mask is, therefore, higly dependent on the ThinkPad model.
 
-Some models do not support all of the above. For example, the T30 does
-not support Fn-F5 and Fn-F9. Other models do not support the mask at
-all. On those models, hot keys cannot be controlled individually.
+Note that unmasking some keys prevents their default behavior.  For
+example, if Fn+F5 is unmasked, that key will no longer enable/disable
+Bluetooth by itself.
 
-Note that enabling ACPI events for some keys prevents their default
-behavior. For example, if events for Fn-F5 are enabled, that key will
-no longer enable/disable Bluetooth by itself. This can still be done
-from an acpid handler for the ibm/hotkey event.
-
-Note also that not all Fn key combinations are supported through
-ACPI. For example, on the X40, the brightness, volume and "Access IBM"
-buttons do not generate ACPI events even with this driver. They *can*
-be used through the "ThinkPad Buttons" utility, see
-http://www.nongnu.org/tpb/
+Note also that not all Fn key combinations are supported through ACPI.
+For example, on the X40, the brightness, volume and "Access IBM" buttons
+do not generate ACPI events even with this driver.  They *can* be used
+through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/
 
 procfs notes:
 
@@ -189,9 +203,9 @@
 
 	echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
 	echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
-	echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
-	echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
-	... any other 4-hex-digit mask ...
+	echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
+	echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+	... any other 8-hex-digit mask ...
 	echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
 
 sysfs notes:
@@ -202,7 +216,7 @@
 		key feature status will be restored to this value.
 
 		0: hot keys were disabled
-		1: hot keys were enabled
+		1: hot keys were enabled (unusual)
 
 	hotkey_bios_mask:
 		Returns the hot keys mask when thinkpad-acpi was loaded.
@@ -217,9 +231,182 @@
 		1: enables the hot keys feature / feature enabled
 
 	hotkey_mask:
-		bit mask to enable ACPI event generation for each hot
-		key (see above).  Returns the current status of the hot
-		keys mask, and allows one to modify it.
+		bit mask to enable driver-handling and ACPI event
+		generation for each hot key (see above).  Returns the
+		current status of the hot keys mask, and allows one to
+		modify it.
+
+	hotkey_all_mask:
+		bit mask that should enable event reporting for all
+		supported hot keys, when echoed to hotkey_mask above.
+		Unless you know which events need to be handled
+		passively (because the firmware *will* handle them
+		anyway), do *not* use hotkey_all_mask.  Use
+		hotkey_recommended_mask, instead. You have been warned.
+
+	hotkey_recommended_mask:
+		bit mask that should enable event reporting for all
+		supported hot keys, except those which are always
+		handled by the firmware anyway.  Echo it to
+		hotkey_mask above, to use.
+
+	hotkey_radio_sw:
+		if the ThinkPad has a hardware radio switch, this
+		attribute will read 0 if the switch is in the "radios
+		disabled" postition, and 1 if the switch is in the
+		"radios enabled" position.
+
+input layer notes:
+
+A Hot key is mapped to a single input layer EV_KEY event, possibly
+followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
+code.  An EV_SYN event will always be generated to mark the end of the
+event block.
+
+Do not use the EV_MSC MSC_SCAN events to process keys.  They are to be
+used as a helper to remap keys, only.  They are particularly useful when
+remapping KEY_UNKNOWN keys.
+
+The events are available in an input device, with the following id:
+
+	Bus:		BUS_HOST
+	vendor:		0x1014 (PCI_VENDOR_ID_IBM)  or
+			0x17aa (PCI_VENDOR_ID_LENOVO)
+	product:	0x5054 ("TP")
+	version:	0x4101
+
+The version will have its LSB incremented if the keymap changes in a
+backwards-compatible way.  The MSB shall always be 0x41 for this input
+device.  If the MSB is not 0x41, do not use the device as described in
+this section, as it is either something else (e.g. another input device
+exported by a thinkpad driver, such as HDAPS) or its functionality has
+been changed in a non-backwards compatible way.
+
+Adding other event types for other functionalities shall be considered a
+backwards-compatible change for this input device.
+
+Thinkpad-acpi Hot Key event map (version 0x4101):
+
+ACPI	Scan
+event	code	Key		Notes
+
+0x1001	0x00	FN+F1		-
+0x1002	0x01	FN+F2		IBM: battery (rare)
+				Lenovo: Screen lock
+
+0x1003	0x02	FN+F3		Many IBM models always report
+				this hot key, even with hot keys
+				disabled or with Fn+F3 masked
+				off
+				IBM: screen lock
+				Lenovo: battery
+
+0x1004	0x03	FN+F4		Sleep button (ACPI sleep button
+				semanthics, i.e. sleep-to-RAM).
+				It is always generate some kind
+				of event, either the hot key
+				event or a ACPI sleep button
+				event. The firmware may
+				refuse to generate further FN+F4
+				key presses until a S3 or S4 ACPI
+				sleep cycle is performed or some
+				time passes.
+
+0x1005	0x04	FN+F5		Radio.  Enables/disables
+				the internal BlueTooth hardware
+				and W-WAN card if left in control
+				of the firmware.  Does not affect
+				the WLAN card.
+				Should be used to turn on/off all
+				radios (bluetooth+W-WAN+WLAN),
+				really.
+
+0x1006	0x05	FN+F6		-
+
+0x1007	0x06	FN+F7		Video output cycle.
+				Do you feel lucky today?
+
+0x1008	0x07	FN+F8		IBM: toggle screen expand
+				Lenovo: configure ultranav
+
+0x1009	0x08	FN+F9		-
+	..	..		..
+0x100B	0x0A	FN+F11		-
+
+0x100C	0x0B	FN+F12		Sleep to disk.  You are always
+				supposed to handle it yourself,
+				either through the ACPI event,
+				or through a hotkey event.
+				The firmware may refuse to
+				generate further FN+F4 key
+				press events until a S3 or S4
+				ACPI sleep cycle is performed,
+				or some time passes.
+
+0x100D	0x0C	FN+BACKSPACE	-
+0x100E	0x0D	FN+INSERT	-
+0x100F	0x0E	FN+DELETE	-
+
+0x1010	0x0F	FN+HOME		Brightness up.  This key is
+				always handled by the firmware
+				in IBM ThinkPads, even when
+				unmasked.  Just leave it alone.
+				For Lenovo ThinkPads with a new
+				BIOS, it has to be handled either
+				by the ACPI OSI, or by userspace.
+0x1011	0x10	FN+END		Brightness down.  See brightness
+				up for details.
+
+0x1012	0x11	FN+PGUP		Thinklight toggle.  This key is
+				always handled by the firmware,
+				even when unmasked.
+
+0x1013	0x12	FN+PGDOWN	-
+
+0x1014	0x13	FN+SPACE	Zoom key
+
+0x1015	0x14	VOLUME UP	Internal mixer volume up. This
+				key is always handled by the
+				firmware, even when unmasked.
+				NOTE: Lenovo seems to be changing
+				this.
+0x1016	0x15	VOLUME DOWN	Internal mixer volume up. This
+				key is always handled by the
+				firmware, even when unmasked.
+				NOTE: Lenovo seems to be changing
+				this.
+0x1017	0x16	MUTE		Mute internal mixer. This
+				key is always handled by the
+				firmware, even when unmasked.
+
+0x1018	0x17	THINKPAD	Thinkpad/Access IBM/Lenovo key
+
+0x1019	0x18	unknown
+..	..	..
+0x1020	0x1F	unknown
+
+The ThinkPad firmware does not allow one to differentiate when most hot
+keys are pressed or released (either that, or we don't know how to, yet).
+For these keys, the driver generates a set of events for a key press and
+immediately issues the same set of events for a key release.  It is
+unknown by the driver if the ThinkPad firmware triggered these events on
+hot key press or release, but the firmware will do it for either one, not
+both.
+
+If a key is mapped to KEY_RESERVED, it generates no input events at all,
+and it may generate a legacy thinkpad-acpi ACPI hotkey event.
+
+If a key is mapped to KEY_UNKNOWN, it generates an input event that
+includes an scan code, and it may also generate a legacy thinkpad-acpi
+ACPI hotkey event.
+
+If a key is mapped to anything else, it will only generate legacy
+thinkpad-acpi ACPI hotkey events if nobody has opened the input device.
+
+Non hot-key ACPI HKEY event map:
+0x5001		Lid closed
+0x5002		Lid opened
+0x7000		Radio Switch may have changed state
 
 
 Bluetooth
@@ -437,27 +624,34 @@
 procfs: /proc/acpi/ibm/cmos
 sysfs device attribute: cmos_command
 
-This feature is used internally by the ACPI firmware to control the
-ThinkLight on most newer ThinkPad models. It may also control LCD
-brightness, sounds volume and more, but only on some models.
+This feature is mostly used internally by the ACPI firmware to keep the legacy
+CMOS NVRAM bits in sync with the current machine state, and to record this
+state so that the ThinkPad will retain such settings across reboots.
+
+Some of these commands actually perform actions in some ThinkPad models, but
+this is expected to disappear more and more in newer models.  As an example, in
+a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
+real, but commands 0 to 2 don't control the mixer anymore (they have been
+phased out) and just update the NVRAM.
 
 The range of valid cmos command numbers is 0 to 21, but not all have an
 effect and the behavior varies from model to model.  Here is the behavior
 on the X40 (tpb is the ThinkPad Buttons utility):
 
-	0 - no effect but tpb reports "Volume down"
-	1 - no effect but tpb reports "Volume up"
-	2 - no effect but tpb reports "Mute on"
-	3 - simulate pressing the "Access IBM" button
-	4 - LCD brightness up
-	5 - LCD brightness down
-	11 - toggle screen expansion
-	12 - ThinkLight on
-	13 - ThinkLight off
-	14 - no effect but tpb reports ThinkLight status change
+	0 - Related to "Volume down" key press
+	1 - Related to "Volume up" key press
+	2 - Related to "Mute on" key press
+	3 - Related to "Access IBM" key press
+	4 - Related to "LCD brightness up" key pess
+	5 - Related to "LCD brightness down" key press
+	11 - Related to "toggle screen expansion" key press/function
+	12 - Related to "ThinkLight on"
+	13 - Related to "ThinkLight off"
+	14 - Related to "ThinkLight" key press (toggle thinklight)
 
 The cmos command interface is prone to firmware split-brain problems, as
-in newer ThinkPads it is just a compatibility layer.
+in newer ThinkPads it is just a compatibility layer.  Do not use it, it is
+exported just as a debug tool.
 
 LED control -- /proc/acpi/ibm/led
 ---------------------------------
@@ -516,23 +710,15 @@
 procfs: /proc/acpi/ibm/thermal
 sysfs device attributes: (hwmon) temp*_input
 
-Most ThinkPads include six or more separate temperature sensors but
-only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors on older
-ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads.
-
-EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
-implementation directly accesses hardware registers and may not work as
-expected. USE WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.  When EXPERIMENTAL
-mode is enabled, reading the first 8 sensors on newer ThinkPads will
-also use an new experimental thermal sensor access mode.
+Most ThinkPads include six or more separate temperature sensors but only
+expose the CPU temperature through the standard ACPI methods.  This
+feature shows readings from up to eight different sensors on older
+ThinkPads, and up to sixteen different sensors on newer ThinkPads.
 
 For example, on the X40, a typical output may be:
 temperatures:   42 42 45 41 36 -128 33 -128
 
-EXPERIMENTAL: On the T43/p, a typical output may be:
+On the T43/p, a typical output may be:
 temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
 
 The mapping of thermal sensors to physical locations varies depending on
@@ -562,7 +748,8 @@
 2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
 3:  PCMCIA slot
 9:  MCH (northbridge) to DRAM Bus
-10: ICH (southbridge), under Mini-PCI card, under touchpad
+10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
+    card, under touchpad
 11: Power regulator, underside of system board, below F2 key
 
 The A31 has a very atypical layout for the thermal sensors
@@ -681,6 +868,12 @@
 The backlight control has eight levels, ranging from 0 to 7.  Some of the
 levels may not be distinct.
 
+There are two interfaces to the firmware for brightness control, EC and CMOS.
+To select which one should be used, use the brightness_mode module parameter:
+brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
+brightness_mode=3 selects both EC and CMOS.  The driver tries to autodetect
+which interface to use.
+
 Procfs notes:
 
 	The available commands are:
@@ -976,3 +1169,9 @@
 
 0x000100:	Initial sysfs support, as a single platform driver and
 		device.
+0x000200:	Hot key support for 32 hot keys, and radio slider switch
+		support.
+0x010000:	Hot keys are now handled by default over the input
+		layer, the radio switch generates input event EV_RADIO,
+		and the driver enables hot key handling by default in
+		the firmware.
diff --git a/Documentation/time_interpolators.txt b/Documentation/time_interpolators.txt
deleted file mode 100644
index e3b6085..0000000
--- a/Documentation/time_interpolators.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-Time Interpolators
-------------------
-
-Time interpolators are a base of time calculation between timer ticks and
-allow an accurate determination of time down to the accuracy of the time
-source in nanoseconds.
-
-The architecture specific code typically provides gettimeofday and
-settimeofday under Linux. The time interpolator provides both if an arch
-defines CONFIG_TIME_INTERPOLATION. The arch still must set up timer tick
-operations and call the necessary functions to advance the clock.
-
-With the time interpolator a standardized interface exists for time
-interpolation between ticks. The provided logic is highly scalable
-and has been tested in SMP situations of up to 512 CPUs.
-
-If CONFIG_TIME_INTERPOLATION is defined then the architecture specific code
-(or the device drivers - like HPET) may register time interpolators.
-These are typically defined in the following way:
-
-static struct time_interpolator my_interpolator {
-	.frequency = MY_FREQUENCY,
-	.source = TIME_SOURCE_MMIO32,
-	.shift = 8,		/* scaling for higher accuracy */
-	.drift = -1,		/* Unknown drift */
-	.jitter = 0		/* time source is stable */
-};
-
-void time_init(void)
-{
-	....
-	/* Initialization of the timer *.
-	my_interpolator.address = &my_timer;
-	register_time_interpolator(&my_interpolator);
-	....
-}
-
-For more details see include/linux/timex.h and kernel/timer.c.
-
-Christoph Lameter <christoph@lameter.com>, October 31, 2004
-
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 6177d88..9453118 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -14,9 +14,11 @@
    mce=nobootlog
 		Disable boot machine check logging.
    mce=tolerancelevel (number)
-		0: always panic, 1: panic if deadlock possible,
-		2: try to avoid panic, 3: never panic or exit (for testing)
-		default is 1
+		0: always panic on uncorrected errors, log corrected errors
+		1: panic or SIGBUS on uncorrected errors, log corrected errors
+		2: SIGBUS or log uncorrected errors, log corrected errors
+		3: never panic or SIGBUS, log all errors (for testing only)
+		Default is 1
 		Can be also set using sysfs which is preferable.
 
    nomce (for compatibility with i386): same as mce=off
@@ -134,12 +136,6 @@
 
 SMP
 
-  nosmp	Only use a single CPU
-
-  maxcpus=NUMBER only use upto NUMBER CPUs
-
-  cpumask=MASK   only use cpus with bits set in mask
-
   additional_cpus=NUM Allow NUM more CPUs for hotplug
 		 (defaults are specified by the BIOS, see Documentation/x86_64/cpu-hotplug-spec)
 
diff --git a/Documentation/x86_64/machinecheck b/Documentation/x86_64/machinecheck
index feaeaf6..a05e58e 100644
--- a/Documentation/x86_64/machinecheck
+++ b/Documentation/x86_64/machinecheck
@@ -49,12 +49,14 @@
 	Since machine check exceptions can happen any time it is sometimes
 	risky for the kernel to kill a process because it defies
 	normal kernel locking rules. The tolerance level configures
-	how hard the kernel tries to recover even at some risk of deadlock.
+	how hard the kernel tries to recover even at some risk of
+	deadlock.  Higher tolerant values trade potentially better uptime
+	with the risk of a crash or even corruption (for tolerant >= 3).
 
-	0: always panic,
-	1: panic if deadlock possible,
-	2: try to avoid panic,
-   	3: never panic or exit (for testing only)
+	0: always panic on uncorrected errors, log corrected errors
+	1: panic or SIGBUS on uncorrected errors, log corrected errors
+	2: SIGBUS or log uncorrected errors, log corrected errors
+	3: never panic or SIGBUS, log all errors (for testing only)
 
 	Default: 1
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 57c07c2..01f222e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -225,15 +225,15 @@
 S:	Supported
 
 ACPI BATTERY DRIVERS
-P:	Vladimir P. Lebedev
-M:	vladimir.p.lebedev@intel.com
+P:	Alexey Starikovskiy
+M:	astarikovskiy@suse.de
 L:	linux-acpi@vger.kernel.org
 W:	http://acpi.sourceforge.net/
 S:	Supported
 
 ACPI EC DRIVER
 P:	Alexey Starikovskiy
-M:	alexey.y.starikovskiy@linux.intel.com
+M:	astarikovskiy@suse.de
 L:	linux-acpi@vger.kernel.org
 W:	http://acpi.sourceforge.net/
 S:	Supported
@@ -329,6 +329,12 @@
 M:	ink@jurassic.park.msu.ru
 S:	Maintained for 2.4; PCI support for 2.6.
 
+AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
+P:	Thomas Dahlmann
+M:	thomas.dahlmann@amd.com
+L:	info-linux@geode.amd.com
+S:	Supported
+
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:	Jordan Crouse
 M:	info-linux@geode.amd.com
@@ -645,7 +651,12 @@
 S:	Maintained
 
 ATMEL AT91 MCI DRIVER
-S:	Orphan
+P:	Nicolas Ferre
+M:	nicolas.ferre@rfo.atmel.com
+L:	linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:	http://www.atmel.com/products/AT91/
+W:	http://www.at91.com/
+S:	Maintained
 
 ATMEL MACB ETHERNET DRIVER
 P:	Haavard Skinnemoen
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 4d8425d..e96a3dc 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -285,6 +285,8 @@
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		t->opts = TIMER_OPTS_DISABLED;
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 010f6fa..d86d124 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -159,6 +159,7 @@
 		break;
 	case CLOCK_EVT_MODE_SHUTDOWN:
 	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_RESUME:
 		/* Left event sources disabled, no more interrupts appears */
 		break;
 	}
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 4c54a86..c1271c4 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -459,6 +459,8 @@
 	default:
 		osrt = opts = 0;
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 
 	*IXP4XX_OSRT1 = osrt | opts;
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 3705d20..237651e 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -156,6 +156,7 @@
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	}
 }
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index c04124a..846cce4 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -145,8 +145,8 @@
 		__do_kernel_fault(mm, addr, fsr, regs);
 }
 
-#define VM_FAULT_BADMAP		(-20)
-#define VM_FAULT_BADACCESS	(-21)
+#define VM_FAULT_BADMAP		0x010000
+#define VM_FAULT_BADACCESS	0x020000
 
 static int
 __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
@@ -249,7 +249,7 @@
 	/*
 	 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
 	 */
-	if (likely(!(fault & VM_FAULT_ERROR)))
+	if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
 		return 0;
 
 	/*
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 2feceec..b0af014 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -156,6 +156,8 @@
 	case CLOCK_EVT_MODE_SHUTDOWN:
 		omap_32k_timer_stop();
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 6c4dc0a..2edcecd 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -13,6 +13,7 @@
 #include <linux/linkage.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
+#include <linux/leds.h>
 #include <linux/spi/spi.h>
 
 #include <asm/io.h>
@@ -21,6 +22,7 @@
 #include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
 
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
@@ -100,8 +102,31 @@
 	at32_setup_serial_console(0);
 }
 
+static const struct gpio_led ngw_leds[] = {
+	{ .name = "sys", .gpio = GPIO_PIN_PA(16), .active_low = 1,
+		.default_trigger = "heartbeat",
+	},
+	{ .name = "a", .gpio = GPIO_PIN_PA(19), .active_low = 1, },
+	{ .name = "b", .gpio = GPIO_PIN_PE(19), .active_low = 1, },
+};
+
+static const struct gpio_led_platform_data ngw_led_data = {
+	.num_leds =	ARRAY_SIZE(ngw_leds),
+	.leds =		(void *) ngw_leds,
+};
+
+static struct platform_device ngw_gpio_leds = {
+	.name =		"leds-gpio",
+	.id =		-1,
+	.dev = {
+		.platform_data = (void *) &ngw_led_data,
+	}
+};
+
 static int __init atngw100_init(void)
 {
+	unsigned	i;
+
 	/*
 	 * ATNGW100 uses 16-bit SDRAM interface, so we don't need to
 	 * reserve any pins for it.
@@ -116,6 +141,12 @@
 
 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
 
+	for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
+		at32_select_gpio(ngw_leds[i].gpio,
+				AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+	}
+	platform_device_register(&ngw_gpio_leds);
+
 	return 0;
 }
 postcore_initcall(atngw100_init);
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
index 49493ad..b799a68 100644
--- a/arch/avr32/configs/atngw100_defconfig
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -712,7 +712,21 @@
 #
 # LED devices
 #
-# CONFIG_NEW_LEDS is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
 
 #
 # LED drivers
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 7a11b90..abb582b 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -18,6 +18,10 @@
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config CLOCKSOURCE_WATCHDOG
 	bool
 	default y
@@ -544,6 +548,7 @@
 config HIGHMEM64G
 	bool "64GB"
 	depends on !M386 && !M486
+	select X86_PAE
 	help
 	  Select this if you have a 32-bit processor and more than 4
 	  gigabytes of physical RAM.
@@ -573,12 +578,12 @@
 	config VMSPLIT_3G
 		bool "3G/1G user/kernel split"
 	config VMSPLIT_3G_OPT
-		depends on !HIGHMEM
+		depends on !X86_PAE
 		bool "3G/1G user/kernel split (for full 1G low memory)"
 	config VMSPLIT_2G
 		bool "2G/2G user/kernel split"
 	config VMSPLIT_2G_OPT
-		depends on !HIGHMEM
+		depends on !X86_PAE
 		bool "2G/2G user/kernel split (for full 2G low memory)"
 	config VMSPLIT_1G
 		bool "1G/3G user/kernel split"
@@ -598,10 +603,15 @@
 	default y
 
 config X86_PAE
-	bool
-	depends on HIGHMEM64G
-	default y
+	bool "PAE (Physical Address Extension) Support"
+	default n
+	depends on !HIGHMEM4G
 	select RESOURCES_64BIT
+	help
+	  PAE is required for NX support, and furthermore enables
+	  larger swapspace support for non-overcommit purposes. It
+	  has the cost of more pagetable lookup overhead, and also
+	  consumes more pagetable space per process.
 
 # Common NUMA Features
 config NUMA
@@ -817,6 +827,7 @@
 
 config PHYSICAL_START
 	hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+	default "0x1000000" if X86_NUMAQ
 	default "0x100000"
 	help
 	  This gives the physical address where the kernel is loaded.
diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c
index b0e21c3..2d77ee7 100644
--- a/arch/i386/boot/compressed/relocs.c
+++ b/arch/i386/boot/compressed/relocs.c
@@ -31,6 +31,7 @@
 		"__kernel_rt_sigreturn",
 		"__kernel_sigreturn",
 		"SYSENTER_RETURN",
+		"VDSO_NOTE_MASK",
 		"xen_irq_disable_direct_reloc",
 		"xen_save_fl_direct_reloc",
 };
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 0ac62cd..54ee176 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:44 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
 #
 CONFIG_X86_32=y
 CONFIG_GENERIC_TIME=y
@@ -37,19 +37,18 @@
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=18
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
+CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -73,16 +72,13 @@
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -90,14 +86,11 @@
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 CONFIG_LBD=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -201,6 +194,7 @@
 # CONFIG_EDD is not set
 # CONFIG_DELL_RBU is not set
 # CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
 # CONFIG_NOHIGHMEM is not set
 CONFIG_HIGHMEM4G=y
 # CONFIG_HIGHMEM64G is not set
@@ -217,7 +211,9 @@
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
 CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_HIGHPTE is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
@@ -244,7 +240,6 @@
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -284,7 +279,7 @@
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -325,7 +320,7 @@
 CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
-CONFIG_HT_IRQ=y
+# CONFIG_HT_IRQ is not set
 CONFIG_ISA_DMA_API=y
 # CONFIG_ISA is not set
 # CONFIG_MCA is not set
@@ -381,7 +376,7 @@
 CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
@@ -400,27 +395,15 @@
 # CONFIG_INET6_TUNNEL is not set
 CONFIG_INET6_XFRM_MODE_TRANSPORT=y
 CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_BEET is not set
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
 CONFIG_IPV6_SIT=y
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -457,6 +440,7 @@
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -471,21 +455,9 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -493,10 +465,7 @@
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -514,17 +483,14 @@
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_IBM_ASM is not set
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -596,6 +562,7 @@
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 # CONFIG_SCSI_PROC_FS is not set
@@ -606,8 +573,9 @@
 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_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
 # CONFIG_CHR_DEV_SCH is not set
 
 #
@@ -667,6 +635,7 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_STEX is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_QLA_FC is not set
 # CONFIG_SCSI_QLA_ISCSI is not set
@@ -675,14 +644,73 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_ACPI=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_SVW=y
+CONFIG_ATA_PIIX=y
+# CONFIG_SATA_MV is not set
+CONFIG_SATA_NV=y
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+CONFIG_SATA_VIA=y
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -723,42 +751,27 @@
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
 CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
 # 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_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -809,7 +822,6 @@
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 CONFIG_SKY2=y
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 CONFIG_BNX2=y
@@ -823,10 +835,6 @@
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -855,15 +863,7 @@
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -871,6 +871,7 @@
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -936,6 +937,7 @@
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_PNP=y
 CONFIG_SERIAL_8250_NR_UARTS=4
@@ -951,10 +953,6 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
@@ -988,11 +986,7 @@
 CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
-CONFIG_HANGCHECK_TIMER=y
-
-#
-# TPM devices
-#
+# CONFIG_HANGCHECK_TIMER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
@@ -1003,11 +997,8 @@
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 
 #
@@ -1041,7 +1032,7 @@
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=128
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 
 #
@@ -1058,15 +1049,11 @@
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
@@ -1077,10 +1064,7 @@
 # CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1094,6 +1078,7 @@
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1103,7 +1088,6 @@
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1111,6 +1095,7 @@
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1201,15 +1186,7 @@
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
 # CONFIG_EDAC is not set
 
 #
@@ -1229,11 +1206,13 @@
 #
 # DMA Devices
 #
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
 
 #
-# Virtualization
+# Userspace I/O
 #
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -1271,6 +1250,7 @@
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
 
 #
 # CD-ROM/DVD Filesystems
@@ -1298,7 +1278,7 @@
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1348,7 +1328,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1404,10 +1383,7 @@
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
-
-#
-# Instrumentation Support
-#
+CONFIG_INSTRUMENTATION=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
@@ -1417,7 +1393,7 @@
 #
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 # CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_MUST_CHECK is not set
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_UNUSED_SYMBOLS=y
 # CONFIG_DEBUG_FS is not set
@@ -1425,15 +1401,17 @@
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_SLUB_DEBUG_ON 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
@@ -1443,7 +1421,6 @@
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FRAME_POINTER is not set
-# CONFIG_UNWIND_INFO is not set
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
@@ -1462,10 +1439,6 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1476,6 +1449,7 @@
 # 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_PLIST=y
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 06da59f..dbe5e87 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -40,6 +40,7 @@
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
+obj-$(CONFIG_MGEODE_LX)		+= geode.o
 
 obj-$(CONFIG_VMI)		+= vmi.o vmiclock.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index a574cd2..cacdd88 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -618,6 +618,8 @@
 #ifdef CONFIG_HPET_TIMER
 #include <asm/hpet.h>
 
+static struct __initdata resource *hpet_res;
+
 static int __init acpi_parse_hpet(struct acpi_table_header *table)
 {
 	struct acpi_table_hpet *hpet_tbl;
@@ -638,8 +640,42 @@
 	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
 	       hpet_tbl->id, hpet_address);
 
+	/*
+	 * Allocate and initialize the HPET firmware resource for adding into
+	 * the resource tree during the lateinit timeframe.
+	 */
+#define HPET_RESOURCE_NAME_SIZE 9
+	hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
+
+	if (!hpet_res)
+		return 0;
+
+	memset(hpet_res, 0, sizeof(*hpet_res));
+	hpet_res->name = (void *)&hpet_res[1];
+	hpet_res->flags = IORESOURCE_MEM;
+	snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
+		 hpet_tbl->sequence);
+
+	hpet_res->start = hpet_address;
+	hpet_res->end = hpet_address + (1 * 1024) - 1;
+
 	return 0;
 }
+
+/*
+ * hpet_insert_resource inserts the HPET resources used into the resource
+ * tree.
+ */
+static __init int hpet_insert_resource(void)
+{
+	if (!hpet_res)
+		return 1;
+
+	return insert_resource(&iomem_resource, hpet_res);
+}
+
+late_initcall(hpet_insert_resource);
+
 #else
 #define	acpi_parse_hpet	NULL
 #endif
@@ -950,14 +986,6 @@
 	 },
 	{
 	 .callback = force_acpi_ht,
-	 .ident = "DELL GX240",
-	 .matches = {
-		     DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
-		     DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
-		     },
-	 },
-	{
-	 .callback = force_acpi_ht,
 	 .ident = "HP VISUALIZE NT Workstation",
 	 .matches = {
 		     DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index d8cda14..c3750c2 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -2,12 +2,17 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/kprobes.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
+#include <asm/pgtable.h>
+#include <asm/mce.h>
+#include <asm/nmi.h>
 
-static int noreplace_smp     = 0;
-static int smp_alt_once      = 0;
-static int debug_alternative = 0;
+#ifdef CONFIG_HOTPLUG_CPU
+static int smp_alt_once;
 
 static int __init bootonly(char *str)
 {
@@ -15,6 +20,11 @@
 	return 1;
 }
 __setup("smp-alt-boot", bootonly);
+#else
+#define smp_alt_once 1
+#endif
+
+static int debug_alternative;
 
 static int __init debug_alt(char *str)
 {
@@ -23,6 +33,8 @@
 }
 __setup("debug-alternative", debug_alt);
 
+static int noreplace_smp;
+
 static int __init setup_noreplace_smp(char *str)
 {
 	noreplace_smp = 1;
@@ -144,7 +156,7 @@
 		unsigned int noplen = len;
 		if (noplen > ASM_NOP_MAX)
 			noplen = ASM_NOP_MAX;
-		memcpy(insns, noptable[noplen], noplen);
+		text_poke(insns, noptable[noplen], noplen);
 		insns += noplen;
 		len -= noplen;
 	}
@@ -196,7 +208,7 @@
 			continue;
 		if (*ptr > text_end)
 			continue;
-		**ptr = 0xf0; /* lock prefix */
+		text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock prefix */
 	};
 }
 
@@ -354,10 +366,6 @@
 		/* Pad the rest with nops */
 		nop_out(p->instr + used, p->len - used);
 	}
-
-	/* Sync to be conservative, in case we patched following
-	 * instructions */
-	sync_core();
 }
 extern struct paravirt_patch_site __start_parainstructions[],
 	__stop_parainstructions[];
@@ -367,6 +375,14 @@
 {
 	unsigned long flags;
 
+	/* The patching is not fully atomic, so try to avoid local interruptions
+	   that might execute the to be patched code.
+	   Other CPUs are not running. */
+	stop_nmi();
+#ifdef CONFIG_MCE
+	stop_mce();
+#endif
+
 	local_irq_save(flags);
 	apply_alternatives(__alt_instructions, __alt_instructions_end);
 
@@ -376,8 +392,6 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	if (num_possible_cpus() < 2)
 		smp_alt_once = 1;
-#else
-	smp_alt_once = 1;
 #endif
 
 #ifdef CONFIG_SMP
@@ -401,4 +415,37 @@
 #endif
  	apply_paravirt(__parainstructions, __parainstructions_end);
 	local_irq_restore(flags);
+
+	restart_nmi();
+#ifdef CONFIG_MCE
+	restart_mce();
+#endif
+}
+
+/*
+ * Warning:
+ * When you use this code to patch more than one byte of an instruction
+ * you need to make sure that other CPUs cannot execute this code in parallel.
+ * Also no thread must be currently preempted in the middle of these instructions.
+ * And on the local CPU you need to be protected again NMI or MCE handlers
+ * seeing an inconsistent instruction while you patch.
+ */
+void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+{
+        u8 *addr = oaddr;
+	if (!pte_write(*lookup_address((unsigned long)addr))) {
+		struct page *p[2] = { virt_to_page(addr), virt_to_page(addr+PAGE_SIZE) };
+		addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
+		if (!addr)
+			return;
+		addr += ((unsigned long)oaddr) % PAGE_SIZE;
+	}
+	memcpy(addr, opcode, len);
+	sync_core();
+	/* Not strictly needed, but can speed CPU recovery up. Ignore cross cacheline
+	   case. */
+	if (cpu_has_clflush)
+		asm("clflush (%0) " :: "r" (oaddr) : "memory");
+	if (addr != oaddr)
+		vunmap(addr);
 }
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 67824f3..bfc6cb7 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -263,6 +263,9 @@
 		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
 		apic_write_around(APIC_LVTT, v);
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
+		break;
 	}
 
 	local_irq_restore(flags);
@@ -315,7 +318,7 @@
 
 #define LAPIC_CAL_LOOPS		(HZ/10)
 
-static __initdata volatile int lapic_cal_loops = -1;
+static __initdata int lapic_cal_loops = -1;
 static __initdata long lapic_cal_t1, lapic_cal_t2;
 static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2;
 static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
@@ -485,7 +488,7 @@
 		/* Let the interrupts run */
 		local_irq_enable();
 
-		while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
+		while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
 			cpu_relax();
 
 		local_irq_disable();
@@ -521,6 +524,9 @@
 		 */
 		if (nmi_watchdog != NMI_IO_APIC)
 			lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+		else
+			printk(KERN_WARNING "APIC timer registered as dummy,"
+			       " due to nmi_watchdog=1!\n");
 	}
 
 	/* Setup the lapic or request the broadcast */
diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
index 0b6a855..778396c 100644
--- a/arch/i386/kernel/cpu/Makefile
+++ b/arch/i386/kernel/cpu/Makefile
@@ -9,7 +9,6 @@
 obj-y	+=	centaur.o
 obj-y	+=	transmeta.o
 obj-y	+=	intel.o intel_cacheinfo.o addon_cpuid_features.o
-obj-y	+=	rise.o
 obj-y	+=	nexgen.o
 obj-y	+=	umc.o
 
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 6f47eee..c7ba455 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -231,6 +231,9 @@
 
 	switch (c->x86) {
 	case 15:
+	/* Use K8 tuning for Fam10h and Fam11h */
+	case 0x10:
+	case 0x11:
 		set_bit(X86_FEATURE_K8, c->x86_capability);
 		break;
 	case 6:
@@ -272,8 +275,12 @@
 	}
 #endif
 
-	if (cpuid_eax(0x80000000) >= 0x80000006)
-		num_cache_leaves = 3;
+	if (cpuid_eax(0x80000000) >= 0x80000006) {
+		if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
+			num_cache_leaves = 4;
+		else
+			num_cache_leaves = 3;
+	}
 
 	if (amd_apic_timer_broken())
 		set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index e5419a9..d506201 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -606,7 +606,6 @@
 extern int amd_init_cpu(void);
 extern int centaur_init_cpu(void);
 extern int transmeta_init_cpu(void);
-extern int rise_init_cpu(void);
 extern int nexgen_init_cpu(void);
 extern int umc_init_cpu(void);
 
@@ -618,7 +617,6 @@
 	amd_init_cpu();
 	centaur_init_cpu();
 	transmeta_init_cpu();
-	rise_init_cpu();
 	nexgen_init_cpu();
 	umc_init_cpu();
 	early_cpu_detect();
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 18c8b67..6f846be 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -665,8 +665,8 @@
 	data->max_freq = perf->states[0].core_frequency * 1000;
 	/* table init */
 	for (i=0; i<perf->state_count; i++) {
-		if (i>0 && perf->states[i].core_frequency ==
-		    perf->states[i-1].core_frequency)
+		if (i>0 && perf->states[i].core_frequency >=
+		    data->freq_table[valid_states-1].frequency / 1000)
 			continue;
 
 		data->freq_table[valid_states].index = i;
diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
index 1941445..461dabc 100644
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
@@ -79,7 +79,7 @@
 #include <linux/smp.h>
 #include <linux/cpufreq.h>
 #include <linux/pci.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
 #include <asm/errno.h>
 
 /* PCI config registers, all at F0 */
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index e88d2fb..122d2d7 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -4,7 +4,7 @@
 #include <linux/pci.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
 #include <asm/timer.h>
 #include <asm/pci-direct.h>
 #include <asm/tsc.h>
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index e5be819..d5a456d 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -4,7 +4,7 @@
  *      Changes:
  *      Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
  *		Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
- *	Andi Kleen		: CPUID4 emulation on AMD.
+ *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
  */
 
 #include <linux/init.h>
@@ -135,7 +135,7 @@
 
 /* AMD doesn't have CPUID4. Emulate it here to report the same
    information to the user.  This makes some assumptions about the machine:
-   No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
+   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
 
    In theory the TLBs could be reported as fake type (they are in "dummy").
    Maybe later */
@@ -159,13 +159,26 @@
 	unsigned val;
 };
 
+union l3_cache {
+	struct {
+		unsigned line_size : 8;
+		unsigned lines_per_tag : 4;
+		unsigned assoc : 4;
+		unsigned res : 2;
+		unsigned size_encoded : 14;
+	};
+	unsigned val;
+};
+
 static const unsigned short assocs[] = {
 	[1] = 1, [2] = 2, [4] = 4, [6] = 8,
-	[8] = 16,
+	[8] = 16, [0xa] = 32, [0xb] = 48,
+	[0xc] = 64,
 	[0xf] = 0xffff // ??
-	};
-static const unsigned char levels[] = { 1, 1, 2 };
-static const unsigned char types[] = { 1, 2, 3 };
+};
+
+static const unsigned char levels[] = { 1, 1, 2, 3 };
+static const unsigned char types[] = { 1, 2, 3, 3 };
 
 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		       union _cpuid4_leaf_ebx *ebx,
@@ -175,37 +188,58 @@
 	unsigned line_size, lines_per_tag, assoc, size_in_kb;
 	union l1_cache l1i, l1d;
 	union l2_cache l2;
+	union l3_cache l3;
+	union l1_cache *l1 = &l1d;
 
 	eax->full = 0;
 	ebx->full = 0;
 	ecx->full = 0;
 
 	cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
-	cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
+	cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
 
-	if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
-		return;
-
-	eax->split.is_self_initializing = 1;
-	eax->split.type = types[leaf];
-	eax->split.level = levels[leaf];
-	eax->split.num_threads_sharing = 0;
-	eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
-
-	if (leaf <= 1) {
-		union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
+	switch (leaf) {
+	case 1:
+		l1 = &l1i;
+	case 0:
+		if (!l1->val)
+			return;
 		assoc = l1->assoc;
 		line_size = l1->line_size;
 		lines_per_tag = l1->lines_per_tag;
 		size_in_kb = l1->size_in_kb;
-	} else {
+		break;
+	case 2:
+		if (!l2.val)
+			return;
 		assoc = l2.assoc;
 		line_size = l2.line_size;
 		lines_per_tag = l2.lines_per_tag;
 		/* cpu_data has errata corrections for K7 applied */
 		size_in_kb = current_cpu_data.x86_cache_size;
+		break;
+	case 3:
+		if (!l3.val)
+			return;
+		assoc = l3.assoc;
+		line_size = l3.line_size;
+		lines_per_tag = l3.lines_per_tag;
+		size_in_kb = l3.size_encoded * 512;
+		break;
+	default:
+		return;
 	}
 
+	eax->split.is_self_initializing = 1;
+	eax->split.type = types[leaf];
+	eax->split.level = levels[leaf];
+	if (leaf == 3)
+		eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
+	else
+		eax->split.num_threads_sharing = 0;
+	eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+
+
 	if (assoc == 0xf)
 		eax->split.is_fully_associative = 1;
 	ebx->split.coherency_line_size = line_size - 1;
@@ -239,8 +273,7 @@
 	return 0;
 }
 
-/* will only be called once; __init is safe here */
-static int __init find_num_cache_leaves(void)
+static int __cpuinit find_num_cache_leaves(void)
 {
 	unsigned int		eax, ebx, ecx, edx;
 	union _cpuid4_leaf_eax	cache_eax;
@@ -710,7 +743,7 @@
 	return retval;
 }
 
-static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
+static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
 {
 	unsigned int cpu = sys_dev->id;
 	unsigned long i;
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index 56cd485..34c781e 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -60,6 +60,20 @@
 	}
 }
 
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+	old_cr4 = read_cr4();
+	clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+	if (old_cr4 & X86_CR4_MCE)
+		set_in_cr4(X86_CR4_MCE);
+}
+
 static int __init mcheck_disable(char *str)
 {
 	mce_disabled = 1;
diff --git a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/i386/kernel/cpu/mcheck/non-fatal.c
index 6b5d351..bf39409 100644
--- a/arch/i386/kernel/cpu/mcheck/non-fatal.c
+++ b/arch/i386/kernel/cpu/mcheck/non-fatal.c
@@ -57,7 +57,7 @@
 static void mce_work_fn(struct work_struct *work)
 { 
 	on_each_cpu(mce_checkregs, NULL, 1, 1);
-	schedule_delayed_work(&mce_work, MCE_RATE);
+	schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
 } 
 
 static int __init init_nonfatal_mce_checker(void)
@@ -82,7 +82,7 @@
 	/*
 	 * Check for non-fatal errors every MCE_RATE s
 	 */
-	schedule_delayed_work(&mce_work, MCE_RATE);
+	schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
 	printk(KERN_INFO "Machine check exception polling timer started.\n");
 	return 0;
 }
diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
index 1001f1e..2287d48 100644
--- a/arch/i386/kernel/cpu/mtrr/cyrix.c
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c
@@ -3,6 +3,7 @@
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 #include <asm/io.h>
+#include <asm/processor-cyrix.h>
 #include "mtrr.h"
 
 int arr3_protected;
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index f6e4694..56f64e3 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -79,7 +79,7 @@
 }
 
 /*  Grab all of the MTRR state for this CPU into *state  */
-void get_mtrr_state(void)
+void __init get_mtrr_state(void)
 {
 	unsigned int i;
 	struct mtrr_var_range *vrs;
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 75dc6d5..c48b6fe 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -643,7 +643,7 @@
  * initialized (i.e. before smp_init()).
  * 
  */
-__init void mtrr_bp_init(void)
+void __init mtrr_bp_init(void)
 {
 	init_ifs();
 
diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
index 7b39a2f..c9014ca 100644
--- a/arch/i386/kernel/cpu/mtrr/state.c
+++ b/arch/i386/kernel/cpu/mtrr/state.c
@@ -3,6 +3,7 @@
 #include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
+#include <asm-i386/processor-cyrix.h>
 #include "mtrr.h"
 
 
diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/i386/kernel/cpu/perfctr-watchdog.c
index 4d26d51..4be488e 100644
--- a/arch/i386/kernel/cpu/perfctr-watchdog.c
+++ b/arch/i386/kernel/cpu/perfctr-watchdog.c
@@ -325,7 +325,7 @@
 	.stop = single_msr_stop_watchdog,
 	.perfctr = MSR_K7_PERFCTR0,
 	.evntsel = MSR_K7_EVNTSEL0,
-	.checkbit = 1ULL<<63,
+	.checkbit = 1ULL<<47,
 };
 
 /* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
@@ -346,7 +346,9 @@
 	perfctr_msr = MSR_P6_PERFCTR0;
 	evntsel_msr = MSR_P6_EVNTSEL0;
 
-	wrmsrl(perfctr_msr, 0UL);
+	/* KVM doesn't implement this MSR */
+	if (wrmsr_safe(perfctr_msr, 0, 0) < 0)
+		return 0;
 
 	evntsel = P6_EVNTSEL_INT
 		| P6_EVNTSEL_OS
@@ -599,8 +601,8 @@
 	.setup = setup_intel_arch_watchdog,
 	.rearm = p6_rearm,
 	.stop = single_msr_stop_watchdog,
-	.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
-	.evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
+	.perfctr = MSR_ARCH_PERFMON_PERFCTR1,
+	.evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
 };
 
 static void probe_nmi_watchdog(void)
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
deleted file mode 100644
index 50076f2..0000000
--- a/arch/i386/kernel/cpu/rise.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-
-#include "cpu.h"
-
-static void __cpuinit init_rise(struct cpuinfo_x86 *c)
-{
-	printk("CPU: Rise iDragon");
-	if (c->x86_model > 2)
-		printk(" II");
-	printk("\n");
-
-	/* Unhide possibly hidden capability flags
-	   The mp6 iDragon family don't have MSRs.
-	   We switch on extra features with this cpuid weirdness: */
-	__asm__ (
-		"movl $0x6363452a, %%eax\n\t"
-		"movl $0x3231206c, %%ecx\n\t"
-		"movl $0x2a32313a, %%edx\n\t"
-		"cpuid\n\t"
-		"movl $0x63634523, %%eax\n\t"
-		"movl $0x32315f6c, %%ecx\n\t"
-		"movl $0x2333313a, %%edx\n\t"
-		"cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
-	);
-	set_bit(X86_FEATURE_CX8, c->x86_capability);
-}
-
-static struct cpu_dev rise_cpu_dev __cpuinitdata = {
-	.c_vendor	= "Rise",
-	.c_ident	= { "RiseRiseRise" },
-	.c_models = {
-		{ .vendor = X86_VENDOR_RISE, .family = 5, .model_names = 
-		  { 
-			  [0] = "iDragon", 
-			  [2] = "iDragon", 
-			  [8] = "iDragon II", 
-			  [9] = "iDragon II"
-		  }
-		},
-	},
-	.c_init		= init_rise,
-};
-
-int __init rise_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
-	return 0;
-}
-
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index fc822a4..e60cddb 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -10,6 +10,7 @@
 #include <linux/efi.h>
 #include <linux/pfn.h>
 #include <linux/uaccess.h>
+#include <linux/suspend.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -320,6 +321,37 @@
 
 subsys_initcall(request_standard_resources);
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+/**
+ * e820_mark_nosave_regions - Find the ranges of physical addresses that do not
+ * correspond to e820 RAM areas and mark the corresponding pages as nosave for
+ * hibernation.
+ *
+ * This function requires the e820 map to be sorted and without any
+ * overlapping entries and assumes the first e820 area to be RAM.
+ */
+void __init e820_mark_nosave_regions(void)
+{
+	int i;
+	unsigned long pfn;
+
+	pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size);
+	for (i = 1; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i];
+
+		if (pfn < PFN_UP(ei->addr))
+			register_nosave_region(pfn, PFN_UP(ei->addr));
+
+		pfn = PFN_DOWN(ei->addr + ei->size);
+		if (ei->type != E820_RAM)
+			register_nosave_region(PFN_UP(ei->addr), pfn);
+
+		if (pfn >= max_low_pfn)
+			break;
+	}
+}
+#endif
+
 void __init add_memory_region(unsigned long long start,
 			      unsigned long long size, int type)
 {
diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode.c
new file mode 100644
index 0000000..41e8aec
--- /dev/null
+++ b/arch/i386/kernel/geode.c
@@ -0,0 +1,155 @@
+/*
+ * AMD Geode southbridge support code
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <asm/msr.h>
+#include <asm/geode.h>
+
+static struct {
+	char *name;
+	u32 msr;
+	int size;
+	u32 base;
+} lbars[] = {
+	{ "geode-pms",   MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 },
+	{ "geode-acpi",  MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 },
+	{ "geode-gpio",  MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 },
+	{ "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 }
+};
+
+static void __init init_lbars(void)
+{
+	u32 lo, hi;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lbars); i++) {
+		rdmsr(lbars[i].msr, lo, hi);
+		if (hi & 0x01)
+			lbars[i].base = lo & 0x0000ffff;
+
+		if (lbars[i].base == 0)
+			printk(KERN_ERR "geode:  Couldn't initialize '%s'\n",
+					lbars[i].name);
+	}
+}
+
+int geode_get_dev_base(unsigned int dev)
+{
+	BUG_ON(dev >= ARRAY_SIZE(lbars));
+	return lbars[dev].base;
+}
+EXPORT_SYMBOL_GPL(geode_get_dev_base);
+
+/* === GPIO API === */
+
+void geode_gpio_set(unsigned int gpio, unsigned int reg)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+	if (!base)
+		return;
+
+	if (gpio < 16)
+		outl(1 << gpio, base + reg);
+	else
+		outl(1 << (gpio - 16), base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set);
+
+void geode_gpio_clear(unsigned int gpio, unsigned int reg)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+	if (!base)
+		return;
+
+	if (gpio < 16)
+		outl(1 << (gpio + 16), base + reg);
+	else
+		outl(1 << gpio, base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_clear);
+
+int geode_gpio_isset(unsigned int gpio, unsigned int reg)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+	if (!base)
+		return 0;
+
+	if (gpio < 16)
+		return (inl(base + reg) & (1 << gpio)) ? 1 : 0;
+	else
+		return (inl(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(geode_gpio_isset);
+
+void geode_gpio_set_irq(unsigned int group, unsigned int irq)
+{
+	u32 lo, hi;
+
+	if (group > 7 || irq > 15)
+		return;
+
+	rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+
+	lo &= ~(0xF << (group * 4));
+	lo |= (irq & 0xF) << (group * 4);
+
+	wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set_irq);
+
+void geode_gpio_setup_event(unsigned int gpio, int pair, int pme)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+	u32 offset, shift, val;
+
+	if (gpio >= 24)
+		offset = GPIO_MAP_W;
+	else if (gpio >= 16)
+		offset = GPIO_MAP_Z;
+	else if (gpio >= 8)
+		offset = GPIO_MAP_Y;
+	else
+		offset = GPIO_MAP_X;
+
+	shift = (gpio % 8) * 4;
+
+	val = inl(base + offset);
+
+	/* Clear whatever was there before */
+	val &= ~(0xF << shift);
+
+	/* And set the new value */
+
+	val |= ((pair & 7) << shift);
+
+	/* Set the PME bit if this is a PME event */
+
+	if (pme)
+		val |= (1 << (shift + 3));
+
+	outl(val, base + offset);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
+
+static int __init geode_southbridge_init(void)
+{
+	if (!is_geode())
+		return -ENODEV;
+
+	init_lbars();
+	return 0;
+}
+
+postcore_initcall(geode_southbridge_init);
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 17d7345..533d493 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -5,6 +5,7 @@
 #include <linux/init.h>
 #include <linux/sysdev.h>
 #include <linux/pm.h>
+#include <linux/delay.h>
 
 #include <asm/hpet.h>
 #include <asm/io.h>
@@ -187,6 +188,10 @@
 		cfg &= ~HPET_TN_ENABLE;
 		hpet_writel(cfg, HPET_T0_CFG);
 		break;
+
+	case CLOCK_EVT_MODE_RESUME:
+		hpet_enable_int();
+		break;
 	}
 }
 
@@ -217,6 +222,7 @@
 	.mask		= HPET_MASK,
 	.shift		= HPET_SHIFT,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+	.resume		= hpet_start_counter,
 };
 
 /*
@@ -226,7 +232,8 @@
 {
 	unsigned long id;
 	uint64_t hpet_freq;
-	u64 tmp;
+	u64 tmp, start, now;
+	cycle_t t1;
 
 	if (!is_hpet_capable())
 		return 0;
@@ -273,6 +280,27 @@
 	/* Start the counter */
 	hpet_start_counter();
 
+	/* Verify whether hpet counter works */
+	t1 = read_hpet();
+	rdtscll(start);
+
+	/*
+	 * We don't know the TSC frequency yet, but waiting for
+	 * 200000 TSC cycles is safe:
+	 * 4 GHz == 50us
+	 * 1 GHz == 200us
+	 */
+	do {
+		rep_nop();
+		rdtscll(now);
+	} while ((now - start) < 200000UL);
+
+	if (t1 == read_hpet()) {
+		printk(KERN_WARNING
+		       "HPET counter not counting. HPET disabled\n");
+		goto out_nohpet;
+	}
+
 	/* Initialize and register HPET clocksource
 	 *
 	 * hpet period is in femto seconds per cycle
@@ -291,7 +319,6 @@
 
 	clocksource_register(&clocksource_hpet);
 
-
 	if (id & HPET_ID_LEGSUP) {
 		hpet_enable_int();
 		hpet_reserve_platform_timers(id);
@@ -299,7 +326,7 @@
 		 * Start hpet with the boot cpu mask and make it
 		 * global after the IO_APIC has been initialized.
 		 */
-		hpet_clockevent.cpumask =cpumask_of_cpu(0);
+		hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
 		clockevents_register_device(&hpet_clockevent);
 		global_clock_event = &hpet_clockevent;
 		return 1;
@@ -524,68 +551,3 @@
 	return IRQ_HANDLED;
 }
 #endif
-
-
-/*
- * Suspend/resume part
- */
-
-#ifdef CONFIG_PM
-
-static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
-{
-	unsigned long cfg = hpet_readl(HPET_CFG);
-
-	cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
-	hpet_writel(cfg, HPET_CFG);
-
-	return 0;
-}
-
-static int hpet_resume(struct sys_device *sys_device)
-{
-	unsigned int id;
-
-	hpet_start_counter();
-
-	id = hpet_readl(HPET_ID);
-
-	if (id & HPET_ID_LEGSUP)
-		hpet_enable_int();
-
-	return 0;
-}
-
-static struct sysdev_class hpet_class = {
-	set_kset_name("hpet"),
-	.suspend	= hpet_suspend,
-	.resume		= hpet_resume,
-};
-
-static struct sys_device hpet_device = {
-	.id		= 0,
-	.cls		= &hpet_class,
-};
-
-
-static __init int hpet_register_sysfs(void)
-{
-	int err;
-
-	if (!is_hpet_capable())
-		return 0;
-
-	err = sysdev_class_register(&hpet_class);
-
-	if (!err) {
-		err = sysdev_register(&hpet_device);
-		if (err)
-			sysdev_class_unregister(&hpet_class);
-	}
-
-	return err;
-}
-
-device_initcall(hpet_register_sysfs);
-
-#endif
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index f8a3c40..6d839f2 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -3,18 +3,17 @@
  *
  */
 #include <linux/clockchips.h>
-#include <linux/spinlock.h>
-#include <linux/jiffies.h>
-#include <linux/sysdev.h>
-#include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
 
 #include <asm/smp.h>
 #include <asm/delay.h>
 #include <asm/i8253.h>
 #include <asm/io.h>
-
-#include "io_ports.h"
+#include <asm/timer.h>
 
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
@@ -41,26 +40,27 @@
 	case CLOCK_EVT_MODE_PERIODIC:
 		/* binary, mode 2, LSB/MSB, ch 0 */
 		outb_p(0x34, PIT_MODE);
-		udelay(10);
 		outb_p(LATCH & 0xff , PIT_CH0);	/* LSB */
-		udelay(10);
 		outb(LATCH >> 8 , PIT_CH0);	/* MSB */
 		break;
 
-	/*
-	 * Avoid unnecessary state transitions, as it confuses
-	 * Geode / Cyrix based boxen.
-	 */
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		if (evt->mode == CLOCK_EVT_MODE_UNUSED)
-			break;
 	case CLOCK_EVT_MODE_UNUSED:
-		if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
-			break;
+		if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+		    evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+			outb_p(0x30, PIT_MODE);
+			outb_p(0, PIT_CH0);
+			outb_p(0, PIT_CH0);
+		}
+		break;
+
 	case CLOCK_EVT_MODE_ONESHOT:
 		/* One shot setup */
 		outb_p(0x38, PIT_MODE);
-		udelay(10);
+		break;
+
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
 		break;
 	}
 	spin_unlock_irqrestore(&i8253_lock, flags);
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 21db8f5..893df82 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -353,14 +353,6 @@
 # include <linux/slab.h>		/* kmalloc() */
 # include <linux/timer.h>	/* time_after() */
  
-#ifdef CONFIG_BALANCED_IRQ_DEBUG
-#  define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
-#  define Dprintk(x...) do { TDprintk(x); } while (0)
-# else
-#  define TDprintk(x...) 
-#  define Dprintk(x...) 
-# endif
-
 #define IRQBALANCE_CHECK_ARCH -999
 #define MAX_BALANCED_IRQ_INTERVAL	(5*HZ)
 #define MIN_BALANCED_IRQ_INTERVAL	(HZ/2)
@@ -443,7 +435,7 @@
 static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
 {
 	int i, j;
-	Dprintk("Rotating IRQs among CPUs.\n");
+
 	for_each_online_cpu(i) {
 		for (j = 0; j < NR_IRQS; j++) {
 			if (!irq_desc[j].action)
@@ -560,19 +552,11 @@
 	max_loaded = tmp_loaded;	/* processor */
 	imbalance = (max_cpu_irq - min_cpu_irq) / 2;
 	
-	Dprintk("max_loaded cpu = %d\n", max_loaded);
-	Dprintk("min_loaded cpu = %d\n", min_loaded);
-	Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq);
-	Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq);
-	Dprintk("load imbalance = %lu\n", imbalance);
-
 	/* if imbalance is less than approx 10% of max load, then
 	 * observe diminishing returns action. - quit
 	 */
-	if (imbalance < (max_cpu_irq >> 3)) {
-		Dprintk("Imbalance too trivial\n");
+	if (imbalance < (max_cpu_irq >> 3))
 		goto not_worth_the_effort;
-	}
 
 tryanotherirq:
 	/* if we select an IRQ to move that can't go where we want, then
@@ -629,9 +613,6 @@
 	cpus_and(tmp, target_cpu_mask, allowed_mask);
 
 	if (!cpus_empty(tmp)) {
-
-		Dprintk("irq = %d moved to cpu = %d\n",
-				selected_irq, min_loaded);
 		/* mark for change destination */
 		set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
 
@@ -651,7 +632,6 @@
 	 */
 	balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
 		balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);	
-	Dprintk("IRQ worth rotating not found\n");
 	return;
 }
 
@@ -1902,7 +1882,7 @@
  *	- if this function detects that timer IRQs are defunct, then we fall
  *	  back to ISA timer IRQs
  */
-int __init timer_irq_works(void)
+static int __init timer_irq_works(void)
 {
 	unsigned long t1 = jiffies;
 
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index ba44d40..dd2b97f 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -149,15 +149,11 @@
 
 #ifdef CONFIG_4KSTACKS
 
-/*
- * These should really be __section__(".bss.page_aligned") as well, but
- * gcc's 3.0 and earlier don't handle that correctly.
- */
 static char softirq_stack[NR_CPUS * THREAD_SIZE]
-		__attribute__((__aligned__(THREAD_SIZE)));
+		__attribute__((__section__(".bss.page_aligned")));
 
 static char hardirq_stack[NR_CPUS * THREAD_SIZE]
-		__attribute__((__aligned__(THREAD_SIZE)));
+		__attribute__((__section__(".bss.page_aligned")));
 
 /*
  * allocate per-cpu stacks for hardirq and for softirq processing
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index dde828a..448a50b 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -35,6 +35,7 @@
 #include <asm/cacheflush.h>
 #include <asm/desc.h>
 #include <asm/uaccess.h>
+#include <asm/alternative.h>
 
 void jprobe_return_end(void);
 
@@ -169,16 +170,12 @@
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-	*p->addr = BREAKPOINT_INSTRUCTION;
-	flush_icache_range((unsigned long) p->addr,
-			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-	*p->addr = p->opcode;
-	flush_icache_range((unsigned long) p->addr,
-			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	text_poke(p->addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 03b7f55..99beac7 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -353,7 +353,7 @@
 	 * Take the local apic timer and PIT/HPET into account. We don't
 	 * know which one is active, when we have highres/dyntick on
 	 */
-	sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_irqs(0);
+	sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
 
 	/* if the none of the timers isn't firing, this cpu isn't doing much */
 	if (!touched && last_irq_sums[cpu] == sum) {
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index 53f07a8..ea962c0 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -124,20 +124,28 @@
 	return len;
 }
 
+struct branch {
+	unsigned char opcode;
+	u32 delta;
+} __attribute__((packed));
+
 unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
 			     void *site, u16 site_clobbers,
 			     unsigned len)
 {
 	unsigned char *call = site;
 	unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
+	struct branch b;
 
 	if (tgt_clobbers & ~site_clobbers)
 		return len;	/* target would clobber too much for this site */
 	if (len < 5)
 		return len;	/* call too long for patch site */
 
-	*call++ = 0xe8;		/* call */
-	*(unsigned long *)call = delta;
+	b.opcode = 0xe8; /* call */
+	b.delta = delta;
+	BUILD_BUG_ON(sizeof(b) != 5);
+	text_poke(call, (unsigned char *)&b, 5);
 
 	return 5;
 }
@@ -146,12 +154,14 @@
 {
 	unsigned char *jmp = site;
 	unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);
+	struct branch b;
 
 	if (len < 5)
 		return len;	/* call too long for patch site */
 
-	*jmp++ = 0xe9;		/* jmp */
-	*(unsigned long *)jmp = delta;
+	b.opcode = 0xe9;	/* jmp */
+	b.delta = delta;
+	text_poke(jmp, (unsigned char *)&b, 5);
 
 	return 5;
 }
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 6c49acb..8466471 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -300,6 +300,7 @@
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+	unsigned long d0, d1, d2, d3, d6, d7;
 
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
@@ -324,6 +325,17 @@
 	cr3 = read_cr3();
 	cr4 = read_cr4_safe();
 	printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
+
+	get_debugreg(d0, 0);
+	get_debugreg(d1, 1);
+	get_debugreg(d2, 2);
+	get_debugreg(d3, 3);
+	printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
+			d0, d1, d2, d3);
+	get_debugreg(d6, 6);
+	get_debugreg(d7, 7);
+	printk("DR6: %08lx DR7: %08lx\n", d6, d7);
+
 	show_trace(NULL, regs, &regs->esp);
 }
 
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 5513f8d..0d79624 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -113,6 +113,15 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
 		},
 	},
+	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+		.callback = set_bios_reboot,
+		.ident = "Dell OptiPlex 745",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
+			DMI_MATCH(DMI_BOARD_NAME, "0WF810"),
+		},
+	},
 	{	/* Handle problems with rebooting on Dell 2400's */
 		.callback = set_bios_reboot,
 		.ident = "Dell PowerEdge 2400",
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 74871d0..d474cd6 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -273,18 +273,18 @@
 		printk(KERN_WARNING "Warning only %ldMB will be used.\n",
 					MAXMEM>>20);
 		if (max_pfn > MAX_NONPAE_PFN)
-			printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+			printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
 		else
 			printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
 		max_pfn = MAXMEM_PFN;
 #else /* !CONFIG_HIGHMEM */
-#ifndef CONFIG_X86_PAE
+#ifndef CONFIG_HIGHMEM64G
 		if (max_pfn > MAX_NONPAE_PFN) {
 			max_pfn = MAX_NONPAE_PFN;
 			printk(KERN_WARNING "Warning only 4GB will be used.\n");
-			printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+			printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
 		}
-#endif /* !CONFIG_X86_PAE */
+#endif /* !CONFIG_HIGHMEM64G */
 #endif /* !CONFIG_HIGHMEM */
 	} else {
 		if (highmem_pages == -1)
@@ -466,7 +466,7 @@
  *
  * This should all compile down to nothing when NUMA is off.
  */
-void __init remapped_pgdat_init(void)
+static void __init remapped_pgdat_init(void)
 {
 	int nid;
 
@@ -640,6 +640,7 @@
 #endif
 
 	e820_register_memory();
+	e820_mark_nosave_regions();
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index d574e38..f5dd856 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -199,6 +199,13 @@
 	return eax;
 
 badframe:
+	if (show_unhandled_signals && printk_ratelimit())
+		printk("%s%s[%d] bad frame in sigreturn frame:%p eip:%lx"
+		       " esp:%lx oeax:%lx\n",
+		    current->pid > 1 ? KERN_INFO : KERN_EMERG,
+		    current->comm, current->pid, frame, regs->eip,
+		    regs->esp, regs->orig_eax);
+
 	force_sig(SIGSEGV, current);
 	return 0;
 }	
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 5910d3f..e4f61d1 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -308,7 +308,7 @@
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
-void set_cpu_sibling_map(int cpu)
+void __cpuinit set_cpu_sibling_map(int cpu)
 {
 	int i;
 	struct cpuinfo_x86 *c = cpu_data;
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index ff4ee6f..6deb159 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -336,7 +336,9 @@
 
 int in_gate_area(struct task_struct *task, unsigned long addr)
 {
-	return 0;
+	const struct vm_area_struct *vma = get_gate_vma(task);
+
+	return vma && addr >= vma->vm_start && addr < vma->vm_end;
 }
 
 int in_gate_area_no_task(unsigned long addr)
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index a665df6..19a6c67 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -207,55 +207,9 @@
 	return retval;
 }
 
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-int no_sync_cmos_clock;
-
-static void sync_cmos_clock(unsigned long dummy)
+int update_persistent_clock(struct timespec now)
 {
-	struct timeval now, next;
-	int fail = 1;
-
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 * This code is run on a timer.  If the clock is set, that timer
-	 * may not expire at the correct time.  Thus, we adjust...
-	 */
-	if (!ntp_synced())
-		/*
-		 * Not synced, exit, do not restart a timer (if one is
-		 * running, let it run out).
-		 */
-		return;
-
-	do_gettimeofday(&now);
-	if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
-	    now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
-		fail = set_rtc_mmss(now.tv_sec);
-
-	next.tv_usec = USEC_AFTER - now.tv_usec;
-	if (next.tv_usec <= 0)
-		next.tv_usec += USEC_PER_SEC;
-
-	if (!fail)
-		next.tv_sec = 659;
-	else
-		next.tv_sec = 0;
-
-	if (next.tv_usec >= USEC_PER_SEC) {
-		next.tv_sec++;
-		next.tv_usec -= USEC_PER_SEC;
-	}
-	mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
-{
-	if (!no_sync_cmos_clock)
-		mod_timer(&sync_cmos_timer, jiffies + 1);
+	return set_rtc_mmss(now.tv_sec);
 }
 
 extern void (*late_time_init)(void);
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 3e7753c..cfffe3d 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -152,7 +152,7 @@
 	if (!stack) {
 		unsigned long dummy;
 		stack = &dummy;
-		if (task && task != current)
+		if (task != current)
 			stack = (unsigned long *)task->thread.esp;
 	}
 
@@ -211,6 +211,7 @@
 {
 	printk("%s [<%08lx>] ", (char *)data, addr);
 	print_symbol("%s\n", addr);
+	touch_nmi_watchdog();
 }
 
 static struct stacktrace_ops print_trace_ops = {
@@ -617,6 +618,13 @@
 
 	current->thread.error_code = error_code;
 	current->thread.trap_no = 13;
+	if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
+	    printk_ratelimit())
+		printk(KERN_INFO
+		    "%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
+		    current->comm, current->pid,
+		    regs->eip, regs->esp, error_code);
+
 	force_sig(SIGSEGV, current);
 	return;
 
@@ -767,6 +775,8 @@
 	reassert_nmi();
 }
 
+static int ignore_nmis;
+
 fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
 {
 	int cpu;
@@ -777,11 +787,24 @@
 
 	++nmi_count(cpu);
 
-	default_do_nmi(regs);
+	if (!ignore_nmis)
+		default_do_nmi(regs);
 
 	nmi_exit();
 }
 
+void stop_nmi(void)
+{
+	acpi_nmi_disable();
+	ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+	ignore_nmis--;
+	acpi_nmi_enable();
+}
+
 #ifdef CONFIG_KPROBES
 fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock.c
index f9b845f..b1b5ab0 100644
--- a/arch/i386/kernel/vmiclock.c
+++ b/arch/i386/kernel/vmiclock.c
@@ -32,6 +32,7 @@
 #include <asm/apicdef.h>
 #include <asm/apic.h>
 #include <asm/timer.h>
+#include <asm/i8253.h>
 
 #include <irq_vectors.h>
 #include "io_ports.h"
@@ -142,6 +143,7 @@
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	case CLOCK_EVT_MODE_PERIODIC:
 		cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S
index 271f16a..07c0daf 100644
--- a/arch/i386/kernel/vsyscall-note.S
+++ b/arch/i386/kernel/vsyscall-note.S
@@ -14,7 +14,6 @@
 ELFNOTE_END
 
 #ifdef CONFIG_XEN
-
 /*
  * Add a special note telling glibc's dynamic linker a fake hardware
  * flavor that it will use to choose the search path for libraries in the
@@ -28,15 +27,19 @@
  * It should contain:
  *	hwcap 1 nosegneg
  * to match the mapping of bit to name that we give here.
+ *
+ * At runtime, the fake hardware feature will be considered to be present
+ * if its bit is set in the mask word.  So, we start with the mask 0, and
+ * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen.
  */
 
-/* Bit used for the pseudo-hwcap for non-negative segments.  We use
-   bit 1 to avoid bugs in some versions of glibc when bit 0 is
-   used; the choice is otherwise arbitrary. */
-#define VDSO_NOTE_NONEGSEG_BIT	1
+#include "../xen/vdso.h"	/* Defines VDSO_NOTE_NONEGSEG_BIT.  */
 
+	.globl VDSO_NOTE_MASK
 ELFNOTE_START(GNU, 2, "a")
-	.long 1, 1<<VDSO_NOTE_NONEGSEG_BIT		/* ncaps, mask */
+	.long 1			/* ncaps */
+VDSO_NOTE_MASK:
+	.long 0			/* mask */
 	.byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg"	/* bit, name */
 ELFNOTE_END
 #endif
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 22d8ac5..4d105fd 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -4,7 +4,7 @@
 
 
 lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \
-	bitops.o semaphore.o
+	bitops.o semaphore.o string.o
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 
diff --git a/arch/i386/lib/string.c b/arch/i386/lib/string.c
new file mode 100644
index 0000000..2c773fe
--- /dev/null
+++ b/arch/i386/lib/string.c
@@ -0,0 +1,257 @@
+/*
+ * Most of the string-functions are rather heavily hand-optimized,
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * AK: On P4 and K7 using non string instruction implementations might be faster
+ * for large memory blocks. But most of them are unlikely to be used on large
+ * strings.
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+
+#ifdef __HAVE_ARCH_STRCPY
+char *strcpy(char * dest,const char *src)
+{
+	int d0, d1, d2;
+	asm volatile( "1:\tlodsb\n\t"
+		"stosb\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b"
+		: "=&S" (d0), "=&D" (d1), "=&a" (d2)
+		:"0" (src),"1" (dest) : "memory");
+	return dest;
+}
+EXPORT_SYMBOL(strcpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCPY
+char *strncpy(char * dest,const char *src,size_t count)
+{
+	int d0, d1, d2, d3;
+	asm volatile( "1:\tdecl %2\n\t"
+		"js 2f\n\t"
+		"lodsb\n\t"
+		"stosb\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b\n\t"
+		"rep\n\t"
+		"stosb\n"
+		"2:"
+		: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+		:"0" (src),"1" (dest),"2" (count) : "memory");
+	return dest;
+}
+EXPORT_SYMBOL(strncpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRCAT
+char *strcat(char * dest,const char * src)
+{
+	int d0, d1, d2, d3;
+	asm volatile( "repne\n\t"
+		"scasb\n\t"
+		"decl %1\n"
+		"1:\tlodsb\n\t"
+		"stosb\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b"
+		: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+		: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu): "memory");
+	return dest;
+}
+EXPORT_SYMBOL(strcat);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCAT
+char *strncat(char * dest,const char * src,size_t count)
+{
+	int d0, d1, d2, d3;
+	asm volatile( "repne\n\t"
+		"scasb\n\t"
+		"decl %1\n\t"
+		"movl %8,%3\n"
+		"1:\tdecl %3\n\t"
+		"js 2f\n\t"
+		"lodsb\n\t"
+		"stosb\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b\n"
+		"2:\txorl %2,%2\n\t"
+		"stosb"
+		: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+		: "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
+		: "memory");
+	return dest;
+}
+EXPORT_SYMBOL(strncat);
+#endif
+
+#ifdef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+	int d0, d1;
+	int res;
+	asm volatile( "1:\tlodsb\n\t"
+		"scasb\n\t"
+		"jne 2f\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b\n\t"
+		"xorl %%eax,%%eax\n\t"
+		"jmp 3f\n"
+		"2:\tsbbl %%eax,%%eax\n\t"
+		"orb $1,%%al\n"
+		"3:"
+		:"=a" (res), "=&S" (d0), "=&D" (d1)
+		:"1" (cs),"2" (ct)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+	int res;
+	int d0, d1, d2;
+	asm volatile( "1:\tdecl %3\n\t"
+		"js 2f\n\t"
+		"lodsb\n\t"
+		"scasb\n\t"
+		"jne 3f\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b\n"
+		"2:\txorl %%eax,%%eax\n\t"
+		"jmp 4f\n"
+		"3:\tsbbl %%eax,%%eax\n\t"
+		"orb $1,%%al\n"
+		"4:"
+		:"=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+		:"1" (cs),"2" (ct),"3" (count)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strncmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRCHR
+char *strchr(const char * s, int c)
+{
+	int d0;
+	char * res;
+	asm volatile( "movb %%al,%%ah\n"
+		"1:\tlodsb\n\t"
+		"cmpb %%ah,%%al\n\t"
+		"je 2f\n\t"
+		"testb %%al,%%al\n\t"
+		"jne 1b\n\t"
+		"movl $1,%1\n"
+		"2:\tmovl %1,%0\n\t"
+		"decl %0"
+		:"=a" (res), "=&S" (d0)
+		:"1" (s),"0" (c)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRRCHR
+char *strrchr(const char * s, int c)
+{
+	int d0, d1;
+	char * res;
+	asm volatile( "movb %%al,%%ah\n"
+		"1:\tlodsb\n\t"
+		"cmpb %%ah,%%al\n\t"
+		"jne 2f\n\t"
+		"leal -1(%%esi),%0\n"
+		"2:\ttestb %%al,%%al\n\t"
+		"jne 1b"
+		:"=g" (res), "=&S" (d0), "=&a" (d1)
+		:"0" (0),"1" (s),"2" (c)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+	int d0;
+	int res;
+	asm volatile( "repne\n\t"
+		"scasb\n\t"
+		"notl %0\n\t"
+		"decl %0"
+		:"=c" (res), "=&D" (d0)
+		:"1" (s),"a" (0), "0" (0xffffffffu)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifdef __HAVE_ARCH_MEMCHR
+void *memchr(const void *cs,int c,size_t count)
+{
+	int d0;
+	void *res;
+	if (!count)
+		return NULL;
+	asm volatile( "repne\n\t"
+		"scasb\n\t"
+		"je 1f\n\t"
+		"movl $1,%0\n"
+		"1:\tdecl %0"
+		:"=D" (res), "=&c" (d0)
+		:"a" (c),"0" (cs),"1" (count)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(memchr);
+#endif
+
+#ifdef __HAVE_ARCH_MEMSCAN
+void *memscan(void * addr, int c, size_t size)
+{
+	if (!size)
+		return addr;
+	asm volatile("repnz; scasb\n\t"
+	    "jnz 1f\n\t"
+	    "dec %%edi\n"
+	    "1:"
+	    : "=D" (addr), "=c" (size)
+	    : "0" (addr), "1" (size), "a" (c)
+	    : "memory");
+	return addr;
+}
+EXPORT_SYMBOL(memscan);
+#endif
+
+#ifdef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char *s, size_t count)
+{
+	int d0;
+	int res;
+	asm volatile( "movl %2,%0\n\t"
+		"jmp 2f\n"
+		"1:\tcmpb $0,(%0)\n\t"
+		"je 3f\n\t"
+		"incl %0\n"
+		"2:\tdecl %1\n\t"
+		"cmpl $-1,%1\n\t"
+		"jne 1b\n"
+		"3:\tsubl %2,%0"
+		:"=a" (res), "=&d" (d0)
+		:"c" (s),"1" (count)
+		:"memory");
+	return res;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index e92a101..01ffdd4 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -283,6 +283,8 @@
 	return 0;
 }
 
+int show_unhandled_signals = 1;
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -469,6 +471,14 @@
 		if (is_prefetch(regs, address, error_code))
 			return;
 
+		if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+		    printk_ratelimit()) {
+			printk("%s%s[%d]: segfault at %08lx eip %08lx "
+			    "esp %08lx error %lx\n",
+			    tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
+			    tsk->comm, tsk->pid, address, regs->eip,
+			    regs->esp, error_code);
+		}
 		tsk->thread.cr2 = address;
 		/* Kernel addresses are always protection faults */
 		tsk->thread.error_code = error_code | (address >= TASK_SIZE);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 6e72f22..c3b9905 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -471,6 +471,10 @@
 	flush_tlb_all();
 }
 
+int nx_enabled = 0;
+
+#ifdef CONFIG_X86_PAE
+
 static int disable_nx __initdata = 0;
 u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
@@ -500,9 +504,6 @@
 }
 early_param("noexec", noexec_setup);
 
-int nx_enabled = 0;
-#ifdef CONFIG_X86_PAE
-
 static void __init set_nx(void)
 {
 	unsigned int v[4], l, h;
@@ -799,17 +800,9 @@
 	unsigned long start = PFN_ALIGN(_text);
 	unsigned long size = PFN_ALIGN(_etext) - start;
 
-#ifndef CONFIG_KPROBES
-#ifdef CONFIG_HOTPLUG_CPU
-	/* It must still be possible to apply SMP alternatives. */
-	if (num_possible_cpus() <= 1)
-#endif
-	{
-		change_page_attr(virt_to_page(start),
-		                 size >> PAGE_SHIFT, PAGE_KERNEL_RX);
-		printk("Write protecting the kernel text: %luk\n", size >> 10);
-	}
-#endif
+	change_page_attr(virt_to_page(start),
+	                 size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+	printk("Write protecting the kernel text: %luk\n", size >> 10);
 	start += size;
 	size = (unsigned long)__end_rodata - start;
 	change_page_attr(virt_to_page(start),
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index fff08ae..0b27831 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -196,7 +196,7 @@
 	/* Reset the direct mapping. Can block */
 	if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
 		change_page_attr(virt_to_page(__va(p->phys_addr)),
-				 p->size >> PAGE_SHIFT,
+				 get_vm_area_size(p) >> PAGE_SHIFT,
 				 PAGE_KERNEL);
 		global_flush_tlb();
 	} 
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 37992ff..8927222 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -82,7 +82,7 @@
 	struct page *p;
 
 	/* High level code is not ready for clflush yet */
-	if (0 && cpu_has_clflush) {
+	if (cpu_has_clflush) {
 		list_for_each_entry (p, lh, lru)
 			cache_flush_page(p);
 	} else if (boot_cpu_data.x86_model >= 4)
@@ -136,6 +136,12 @@
 			    ref_prot));
 }
 
+static inline void save_page(struct page *kpte_page)
+{
+	if (!test_and_set_bit(PG_arch_1, &kpte_page->flags))
+		list_add(&kpte_page->lru, &df_list);
+}
+
 static int
 __change_page_attr(struct page *page, pgprot_t prot)
 { 
@@ -150,6 +156,9 @@
 	if (!kpte)
 		return -EINVAL;
 	kpte_page = virt_to_page(kpte);
+	BUG_ON(PageLRU(kpte_page));
+	BUG_ON(PageCompound(kpte_page));
+
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
 		if (!pte_huge(*kpte)) {
 			set_pte_atomic(kpte, mk_pte(page, prot)); 
@@ -179,11 +188,11 @@
 	 * time (not via split_large_page) and in turn we must not
 	 * replace it with a largepage.
 	 */
+
+	save_page(kpte_page);
 	if (!PageReserved(kpte_page)) {
 		if (cpu_has_pse && (page_private(kpte_page) == 0)) {
-			ClearPagePrivate(kpte_page);
 			paravirt_release_pt(page_to_pfn(kpte_page));
-			list_add(&kpte_page->lru, &df_list);
 			revert_page(kpte_page, address);
 		}
 	}
@@ -236,6 +245,11 @@
 	spin_unlock_irq(&cpa_lock);
 	flush_map(&l);
 	list_for_each_entry_safe(pg, next, &l, lru) {
+		list_del(&pg->lru);
+		clear_bit(PG_arch_1, &pg->flags);
+		if (PageReserved(pg) || !cpu_has_pse || page_private(pg) != 0)
+			continue;
+		ClearPagePrivate(pg);
 		__free_page(pg);
 	}
 }
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index 8d7c086..01437c4 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -235,7 +235,7 @@
 
 #if (PTRS_PER_PMD == 1)
 /* Non-PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
 {
 	unsigned long flags;
 
@@ -257,7 +257,7 @@
 }
 #else  /* PTRS_PER_PMD > 1 */
 /* PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
 {
 	/* PAE, kernel PMD may be shared */
 
@@ -276,7 +276,7 @@
 }
 #endif	/* PTRS_PER_PMD */
 
-void pgd_dtor(void *pgd)
+static void pgd_dtor(void *pgd)
 {
 	unsigned long flags; /* can be called from interrupt context */
 
diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
index b33aea8..bc8a44b 100644
--- a/arch/i386/pci/acpi.c
+++ b/arch/i386/pci/acpi.c
@@ -8,20 +8,42 @@
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
 {
 	struct pci_bus *bus;
+	struct pci_sysdata *sd;
+	int pxm;
 
-	if (domain != 0) {
-		printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+	/* Allocate per-root-bus (not per bus) arch-specific data.
+	 * TODO: leak; this memory is never freed.
+	 * It's arguable whether it's worth the trouble to care.
+	 */
+	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd) {
+		printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
 		return NULL;
 	}
 
-	bus = pcibios_scan_root(busnum);
+	if (domain != 0) {
+		printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+		kfree(sd);
+		return NULL;
+	}
+
+	sd->node = -1;
+
+	pxm = acpi_get_pxm(device->handle);
+#ifdef CONFIG_ACPI_NUMA
+	if (pxm >= 0)
+		sd->node = pxm_to_node(pxm);
+#endif
+
+	bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+	if (!bus)
+		kfree(sd);
+
 #ifdef CONFIG_ACPI_NUMA
 	if (bus != NULL) {
-		int pxm = acpi_get_pxm(device->handle);
 		if (pxm >= 0) {
-			bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
-			printk("bus %d -> pxm %d -> node %ld\n",
-				busnum, pxm, (long)(bus->sysdata));
+			printk("bus %d -> pxm %d -> node %d\n",
+				busnum, pxm, sd->node);
 		}
 	}
 #endif
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 3f78d4d..85503dee 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -293,6 +293,7 @@
 struct pci_bus * __devinit pcibios_scan_root(int busnum)
 {
 	struct pci_bus *bus = NULL;
+	struct pci_sysdata *sd;
 
 	dmi_check_system(pciprobe_dmi_table);
 
@@ -303,9 +304,19 @@
 		}
 	}
 
+	/* Allocate per-root-bus (not per bus) arch-specific data.
+	 * TODO: leak; this memory is never freed.
+	 * It's arguable whether it's worth the trouble to care.
+	 */
+	sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd) {
+		printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+		return NULL;
+	}
+
 	printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
 
-	return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+	return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
 }
 
 extern u8 pci_cache_line_size;
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index c7cabee..4df637e 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -24,6 +24,9 @@
 
 DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
 
+/* Indicate if the mmcfg resources have been placed into the resource table. */
+static int __initdata pci_mmcfg_resources_inserted;
+
 /* K8 systems have some devices (typically in the builtin northbridge)
    that are only accessible using type1
    Normally this can be expressed in the MCFG by not listing them
@@ -170,7 +173,7 @@
 	return name != NULL;
 }
 
-static void __init pci_mmcfg_insert_resources(void)
+static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
 {
 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
 	int i;
@@ -194,10 +197,13 @@
 			 cfg->pci_segment);
 		res->start = cfg->address;
 		res->end = res->start + (num_buses << 20) - 1;
-		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		res->flags = IORESOURCE_MEM | resource_flags;
 		insert_resource(&iomem_resource, res);
 		names += PCI_MMCFG_RESOURCE_NAME_LEN;
 	}
+
+	/* Mark that the resources have been inserted. */
+	pci_mmcfg_resources_inserted = 1;
 }
 
 static void __init pci_mmcfg_reject_broken(int type)
@@ -267,7 +273,43 @@
 		if (type == 1)
 			unreachable_devices();
 		if (known_bridge)
-			pci_mmcfg_insert_resources();
+			pci_mmcfg_insert_resources(IORESOURCE_BUSY);
 		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+	} else {
+		/*
+		 * Signal not to attempt to insert mmcfg resources because
+		 * the architecture mmcfg setup could not initialize.
+		 */
+		pci_mmcfg_resources_inserted = 1;
 	}
 }
+
+static int __init pci_mmcfg_late_insert_resources(void)
+{
+	/*
+	 * If resources are already inserted or we are not using MMCONFIG,
+	 * don't insert the resources.
+	 */
+	if ((pci_mmcfg_resources_inserted == 1) ||
+	    (pci_probe & PCI_PROBE_MMCONF) == 0 ||
+	    (pci_mmcfg_config_num == 0) ||
+	    (pci_mmcfg_config == NULL) ||
+	    (pci_mmcfg_config[0].address == 0))
+		return 1;
+
+	/*
+	 * Attempt to insert the mmcfg resources but not with the busy flag
+	 * marked so it won't cause request errors when __request_region is
+	 * called.
+	 */
+	pci_mmcfg_insert_resources(0);
+
+	return 0;
+}
+
+/*
+ * Perform MMCONFIG resource insertion after PCI initialization to allow for
+ * misprogrammed MCFG tables that state larger sizes but actually conflict
+ * with other system resources.
+ */
+late_initcall(pci_mmcfg_late_insert_resources);
diff --git a/arch/i386/xen/events.c b/arch/i386/xen/events.c
index 8904acc..da1b173 100644
--- a/arch/i386/xen/events.c
+++ b/arch/i386/xen/events.c
@@ -31,6 +31,7 @@
 #include <asm/irq.h>
 #include <asm/sync_bitops.h>
 #include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
 
 #include <xen/events.h>
 #include <xen/interface/xen.h>
diff --git a/arch/i386/xen/setup.c b/arch/i386/xen/setup.c
index 2fe6eac..f84e772 100644
--- a/arch/i386/xen/setup.c
+++ b/arch/i386/xen/setup.c
@@ -19,6 +19,7 @@
 #include <xen/features.h>
 
 #include "xen-ops.h"
+#include "vdso.h"
 
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
@@ -55,6 +56,18 @@
 	}
 }
 
+/*
+ * Set the bit indicating "nosegneg" library variants should be used.
+ */
+static void fiddle_vdso(void)
+{
+	extern u32 VDSO_NOTE_MASK; /* See ../kernel/vsyscall-note.S.  */
+	extern char vsyscall_int80_start;
+	u32 *mask = (u32 *) ((unsigned long) &VDSO_NOTE_MASK - VDSO_PRELINK +
+			     &vsyscall_int80_start);
+	*mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
+}
+
 void __init xen_arch_setup(void)
 {
 	struct physdev_set_iopl set_iopl;
@@ -93,4 +106,6 @@
 #endif
 
 	paravirt_disable_iospace();
+
+	fiddle_vdso();
 }
diff --git a/arch/i386/xen/time.c b/arch/i386/xen/time.c
index 51fdabf..dfd6db6 100644
--- a/arch/i386/xen/time.c
+++ b/arch/i386/xen/time.c
@@ -412,6 +412,7 @@
 		break;
 
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 
 	case CLOCK_EVT_MODE_UNUSED:
@@ -474,6 +475,8 @@
 		    HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
 			BUG();
 		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
diff --git a/arch/i386/xen/vdso.h b/arch/i386/xen/vdso.h
new file mode 100644
index 0000000..861fedf
--- /dev/null
+++ b/arch/i386/xen/vdso.h
@@ -0,0 +1,4 @@
+/* Bit used for the pseudo-hwcap for non-negative segments.  We use
+   bit 1 to avoid bugs in some versions of glibc when bit 0 is
+   used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT	1
diff --git a/arch/i386/xen/xen-head.S b/arch/i386/xen/xen-head.S
index 2998d55..bc71f3b 100644
--- a/arch/i386/xen/xen-head.S
+++ b/arch/i386/xen/xen-head.S
@@ -7,6 +7,7 @@
 #include <asm/boot.h>
 #include <xen/interface/elfnote.h>
 
+	.section .init.text
 ENTRY(startup_xen)
 	movl %esi,xen_start_info
 	cld
@@ -19,6 +20,7 @@
 	.skip 0x1000
 .popsection
 
+	.section .text
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
 	ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION,  .asciz "2.6")
 	ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION,    .asciz "xen-3.0")
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 616c96e..36c7b96 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -62,7 +62,11 @@
 	bool
 	default y
 
-config TIME_INTERPOLATION
+config GENERIC_TIME
+	bool
+	default y
+
+config GENERIC_TIME_VSYSCALL
 	bool
 	default y
 
diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig
index 90e9c2e..9eb48c0 100644
--- a/arch/ia64/configs/bigsur_defconfig
+++ b/arch/ia64/configs/bigsur_defconfig
@@ -85,7 +85,7 @@
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig
index 0d29aa2..3a9ed95 100644
--- a/arch/ia64/configs/gensparse_defconfig
+++ b/arch/ia64/configs/gensparse_defconfig
@@ -86,7 +86,7 @@
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig
index d9146c3..c420d9f 100644
--- a/arch/ia64/configs/sim_defconfig
+++ b/arch/ia64/configs/sim_defconfig
@@ -86,7 +86,7 @@
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 64e951d..4c9ffc4 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -93,7 +93,7 @@
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index a144693..3dbb398 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:07:09 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:54:47 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=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_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -145,6 +144,9 @@
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -152,11 +154,11 @@
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
+# CONFIG_IA32_SUPPORT is not set
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+# CONFIG_IA64_MC_ERR_INJECT is not set
 # CONFIG_IA64_ESI is not set
 CONFIG_KEXEC=y
 # CONFIG_CRASH_DUMP is not set
@@ -166,6 +168,7 @@
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -175,7 +178,6 @@
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -205,13 +207,11 @@
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -232,7 +232,6 @@
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -270,20 +269,8 @@
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -309,7 +296,17 @@
 # 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
@@ -324,25 +321,9 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -350,10 +331,7 @@
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -370,16 +348,11 @@
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -396,6 +369,7 @@
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -404,12 +378,12 @@
 # CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -438,7 +412,6 @@
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -446,6 +419,7 @@
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -468,6 +442,7 @@
 # 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
@@ -514,15 +489,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -539,6 +506,7 @@
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 # CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -553,46 +521,25 @@
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -623,10 +570,7 @@
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -639,36 +583,36 @@
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# 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_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -678,18 +622,9 @@
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -697,6 +632,7 @@
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -722,9 +658,17 @@
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -790,19 +734,10 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -821,15 +756,8 @@
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -837,21 +765,17 @@
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -863,17 +787,20 @@
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -887,16 +814,18 @@
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -907,8 +836,10 @@
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -918,7 +849,6 @@
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -926,6 +856,7 @@
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -955,41 +886,10 @@
 # CONFIG_USB_LIBUSUAL is not set
 
 #
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
-#
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK 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_MII is not set
-# CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
 #
@@ -1033,10 +933,6 @@
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1051,17 +947,9 @@
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
 # Real Time Clock
 #
 # CONFIG_RTC_CLASS is not set
@@ -1080,12 +968,9 @@
 #
 
 #
-# Auxiliary Display support
+# Userspace I/O
 #
-
-#
-# Virtualization
-#
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1200,7 +1085,8 @@
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1214,7 +1100,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1236,6 +1121,7 @@
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1292,11 +1178,14 @@
 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_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1319,8 +1208,8 @@
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 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
@@ -1343,17 +1232,12 @@
 # CONFIG_DISABLE_VHPT is not set
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
 # CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1373,6 +1257,7 @@
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1390,7 +1275,4 @@
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index 1c7955c..4a060fc 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -96,7 +96,7 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 90bd960..03172dc 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:01:03 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:55:32 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=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_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -147,6 +146,9 @@
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -164,7 +166,7 @@
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-# CONFIG_MC_ERR_INJECT is not set
+# CONFIG_IA64_MC_ERR_INJECT is not set
 CONFIG_SGI_SN=y
 # CONFIG_IA64_ESI is not set
 
@@ -180,6 +182,7 @@
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -189,7 +192,6 @@
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -220,13 +222,11 @@
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -248,7 +248,6 @@
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -286,20 +285,8 @@
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -325,7 +312,17 @@
 # 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
@@ -340,25 +337,9 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -366,10 +347,7 @@
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -386,16 +364,11 @@
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_SGI_IOC4=y
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -412,6 +385,7 @@
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -420,12 +394,12 @@
 # CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -455,7 +429,6 @@
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -463,6 +436,7 @@
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -485,6 +459,7 @@
 # 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
@@ -492,7 +467,7 @@
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
 # CONFIG_SCSI_SAS_LIBSAS is not set
 
 #
@@ -531,15 +506,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -557,6 +524,8 @@
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 # CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -564,53 +533,32 @@
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 CONFIG_FUSION_FC=m
-# CONFIG_FUSION_SAS is not set
+CONFIG_FUSION_SAS=y
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -641,10 +589,7 @@
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -657,36 +602,36 @@
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# 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_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -696,18 +641,9 @@
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -715,6 +651,7 @@
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -740,9 +677,17 @@
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -814,19 +759,10 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -848,15 +784,8 @@
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
 CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -864,21 +793,17 @@
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -890,17 +815,20 @@
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -1014,9 +942,10 @@
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
 
 #
-# SoC audio support
+# System on Chip audio support
 #
 # CONFIG_SND_SOC is not set
 
@@ -1025,16 +954,24 @@
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=m
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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=y
@@ -1045,8 +982,10 @@
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1056,7 +995,6 @@
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1064,6 +1002,7 @@
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1093,47 +1032,10 @@
 # CONFIG_USB_LIBUSUAL is not set
 
 #
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
-#
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK 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_MII is not set
-# CONFIG_USB_USBNET is not set
 CONFIG_USB_MON=y
 
 #
@@ -1177,10 +1079,6 @@
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1195,10 +1093,6 @@
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 CONFIG_INFINIBAND=m
 # CONFIG_INFINIBAND_USER_MAD is not set
 # CONFIG_INFINIBAND_USER_ACCESS is not set
@@ -1206,6 +1100,7 @@
 CONFIG_INFINIBAND_MTHCA=m
 CONFIG_INFINIBAND_MTHCA_DEBUG=y
 # CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_MLX4_INFINIBAND is not set
 CONFIG_INFINIBAND_IPOIB=m
 # CONFIG_INFINIBAND_IPOIB_CM is not set
 CONFIG_INFINIBAND_IPOIB_DEBUG=y
@@ -1214,10 +1109,6 @@
 # CONFIG_INFINIBAND_ISER is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
 # Real Time Clock
 #
 # CONFIG_RTC_CLASS is not set
@@ -1236,12 +1127,9 @@
 #
 
 #
-# Auxiliary Display support
+# Userspace I/O
 #
-
-#
-# Virtualization
-#
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1357,7 +1245,8 @@
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1371,7 +1260,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1393,6 +1281,7 @@
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1449,11 +1338,14 @@
 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_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1483,8 +1375,8 @@
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 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
@@ -1514,10 +1406,6 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1537,6 +1425,7 @@
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1554,7 +1443,4 @@
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
index e1189ba..1cfab32 100644
--- a/arch/ia64/ia32/binfmt_elf32.c
+++ b/arch/ia64/ia32/binfmt_elf32.c
@@ -226,7 +226,7 @@
 }
 
 static unsigned long
-elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type, unsigned long unused)
+elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
 {
 	unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK;
 
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 2236fab..0aebc6f 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
 #define ASM_OFFSETS_C 1
 
 #include <linux/sched.h>
+#include <linux/clocksource.h>
 
 #include <asm-ia64/processor.h>
 #include <asm-ia64/ptrace.h>
@@ -15,6 +16,7 @@
 #include <asm-ia64/mca.h>
 
 #include "../kernel/sigframe.h"
+#include "../kernel/fsyscall_gtod_data.h"
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -256,17 +258,24 @@
 	BLANK();
 
 	/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
-	DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
-	DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
-	DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift));
-	DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc));
-	DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset));
-	DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle));
-	DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter));
-	DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter));
-	DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask));
-	DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU);
-	DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
-	DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
-	DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
+	DEFINE(IA64_GTOD_LOCK_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, lock));
+	DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, wall_time));
+	DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, monotonic_time));
+	DEFINE(IA64_CLKSRC_MASK_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, clk_mask));
+	DEFINE(IA64_CLKSRC_MULT_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, clk_mult));
+	DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, clk_shift));
+	DEFINE(IA64_CLKSRC_MMIO_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
+	DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
+		offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
+	DEFINE(IA64_ITC_JITTER_OFFSET,
+		offsetof (struct itc_jitter_data_t, itc_jitter));
+	DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
+		offsetof (struct itc_jitter_data_t, itc_lastcycle));
 }
diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c
index e00b215..2fd96d90 100644
--- a/arch/ia64/kernel/cyclone.c
+++ b/arch/ia64/kernel/cyclone.c
@@ -3,6 +3,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 #include <asm/io.h>
 
 /* IBM Summit (EXA) Cyclone counter code*/
@@ -18,13 +19,21 @@
 	use_cyclone = 1;
 }
 
+static void __iomem *cyclone_mc;
 
-struct time_interpolator cyclone_interpolator = {
-	.source =	TIME_SOURCE_MMIO64,
-	.shift =	16,
-	.frequency =	CYCLONE_TIMER_FREQ,
-	.drift =	-100,
-	.mask =		(1LL << 40) - 1
+static cycle_t read_cyclone(void)
+{
+	return (cycle_t)readq((void __iomem *)cyclone_mc);
+}
+
+static struct clocksource clocksource_cyclone = {
+        .name           = "cyclone",
+        .rating         = 300,
+        .read           = read_cyclone,
+        .mask           = (1LL << 40) - 1,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 int __init init_cyclone_clock(void)
@@ -44,13 +53,15 @@
 	offset = (CYCLONE_CBAR_ADDR);
 	reg = (u64*)ioremap_nocache(offset, sizeof(u64));
 	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+				" register.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
 	base = readq(reg);
 	if(!base){
-		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+				" value.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
@@ -60,7 +71,8 @@
 	offset = (base + CYCLONE_PMCC_OFFSET);
 	reg = (u64*)ioremap_nocache(offset, sizeof(u64));
 	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
+				" register.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
@@ -71,7 +83,8 @@
 	offset = (base + CYCLONE_MPCS_OFFSET);
 	reg = (u64*)ioremap_nocache(offset, sizeof(u64));
 	if(!reg){
-		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
+				" register.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
@@ -82,7 +95,8 @@
 	offset = (base + CYCLONE_MPMC_OFFSET);
 	cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
 	if(!cyclone_timer){
-		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
+				" register.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
@@ -93,7 +107,8 @@
 		int stall = 100;
 		while(stall--) barrier();
 		if(readl(cyclone_timer) == old){
-			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			printk(KERN_ERR "Summit chipset: Counter not counting!"
+					" DISABLED\n");
 			iounmap(cyclone_timer);
 			cyclone_timer = 0;
 			use_cyclone = 0;
@@ -101,8 +116,11 @@
 		}
 	}
 	/* initialize last tick */
-	cyclone_interpolator.addr = cyclone_timer;
-	register_time_interpolator(&cyclone_interpolator);
+	cyclone_mc = cyclone_timer;
+	clocksource_cyclone.fsys_mmio = cyclone_timer;
+	clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+						clocksource_cyclone.shift);
+	clocksource_register(&clocksource_cyclone);
 
 	return 0;
 }
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 95f5175..c36f43c 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1581,7 +1581,7 @@
 	data8 sys_sync_file_range		// 1300
 	data8 sys_tee
 	data8 sys_vmsplice
-	data8 sys_ni_syscall			// reserved for move_pages
+	data8 sys_fallocate
 	data8 sys_getcpu
 	data8 sys_epoll_pwait			// 1305
 	data8 sys_utimensat
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 3f926c2..4484197 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -147,12 +147,11 @@
 	FSYS_RETURN
 END(fsys_set_tid_address)
 
-/*
- * Ensure that the time interpolator structure is compatible with the asm code
- */
-#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \
-	|| IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4
-#error fsys_gettimeofday incompatible with changes to struct time_interpolator
+#if IA64_GTOD_LOCK_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
+#endif
+#if IA64_ITC_JITTER_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct itc_jitter_data_t
 #endif
 #define CLOCK_REALTIME 0
 #define CLOCK_MONOTONIC 1
@@ -179,126 +178,124 @@
 	// r11 = preserved: saved ar.pfs
 	// r12 = preserved: memory stack
 	// r13 = preserved: thread pointer
-	// r14 = address of mask / mask
+	// r14 = address of mask / mask value
 	// r15 = preserved: system call number
 	// r16 = preserved: current task pointer
-	// r17 = wall to monotonic use
-	// r18 = time_interpolator->offset
-	// r19 = address of wall_to_monotonic
-	// r20 = pointer to struct time_interpolator / pointer to time_interpolator->address
-	// r21 = shift factor
-	// r22 = address of time interpolator->last_counter
-	// r23 = address of time_interpolator->last_cycle
-	// r24 = adress of time_interpolator->offset
-	// r25 = last_cycle value
-	// r26 = last_counter value
-	// r27 = pointer to xtime
+	// r17 = (not used)
+	// r18 = (not used)
+	// r19 = address of itc_lastcycle
+	// r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
+	// r21 = address of mmio_ptr
+	// r22 = address of wall_time or monotonic_time
+	// r23 = address of shift / value
+	// r24 = address mult factor / cycle_last value
+	// r25 = itc_lastcycle value
+	// r26 = address clocksource cycle_last
+	// r27 = (not used)
 	// r28 = sequence number at the beginning of critcal section
-	// r29 = address of seqlock
+	// r29 = address of itc_jitter
 	// r30 = time processing flags / memory address
 	// r31 = pointer to result
 	// Predicates
 	// p6,p7 short term use
 	// p8 = timesource ar.itc
 	// p9 = timesource mmio64
-	// p10 = timesource mmio32
+	// p10 = timesource mmio32 - not used
 	// p11 = timesource not to be handled by asm code
-	// p12 = memory time source ( = p9 | p10)
-	// p13 = do cmpxchg with time_interpolator_last_cycle
+	// p12 = memory time source ( = p9 | p10) - not used
+	// p13 = do cmpxchg with itc_lastcycle
 	// p14 = Divide by 1000
 	// p15 = Add monotonic
 	//
-	// Note that instructions are optimized for McKinley. McKinley can process two
-	// bundles simultaneously and therefore we continuously try to feed the CPU
-	// two bundles and then a stop.
-	tnat.nz p6,p0 = r31	// branch deferred since it does not fit into bundle structure
+	// Note that instructions are optimized for McKinley. McKinley can
+	// process two bundles simultaneously and therefore we continuously
+	// try to feed the CPU two bundles and then a stop.
+	//
+	// Additional note that code has changed a lot. Optimization is TBD.
+	// Comments begin with "?" are maybe outdated.
+	tnat.nz p6,p0 = r31	// ? branch deferred to fit later bundle
 	mov pr = r30,0xc000	// Set predicates according to function
 	add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
-	movl r20 = time_interpolator
+	movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
 	;;
-	ld8 r20 = [r20]		// get pointer to time_interpolator structure
-	movl r29 = xtime_lock
+	movl r29 = itc_jitter_data	// itc_jitter
+	add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20	// wall_time
 	ld4 r2 = [r2]		// process work pending flags
-	movl r27 = xtime
-	;;	// only one bundle here
-	ld8 r21 = [r20]		// first quad with control information
-	and r2 = TIF_ALLWORK_MASK,r2
-(p6)    br.cond.spnt.few .fail_einval	// deferred branch
 	;;
-	add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20
-	extr r3 = r21,32,32	// time_interpolator->nsec_per_cyc
-	extr r8 = r21,0,16	// time_interpolator->source
+(p15)	add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20	// monotonic_time
+	add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
+	add r19 = IA64_ITC_LASTCYCLE_OFFSET,r29
+	and r2 = TIF_ALLWORK_MASK,r2
+(p6)    br.cond.spnt.few .fail_einval	// ? deferred branch
+	;;
+	add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
 	cmp.ne p6, p0 = 0, r2	// Fallback if work is scheduled
 (p6)    br.cond.spnt.many fsys_fallback_syscall
 	;;
-	cmp.eq p8,p12 = 0,r8	// Check for cpu timer
-	cmp.eq p9,p0 = 1,r8	// MMIO64 ?
-	extr r2 = r21,24,8	// time_interpolator->jitter
-	cmp.eq p10,p0 = 2,r8	// MMIO32 ?
-	cmp.ltu p11,p0 = 2,r8	// function or other clock
-(p11)	br.cond.spnt.many fsys_fallback_syscall
-	;;
-	setf.sig f7 = r3	// Setup for scaling of counter
-(p15)	movl r19 = wall_to_monotonic
-(p12)	ld8 r30 = [r10]
-	cmp.ne p13,p0 = r2,r0	// need jitter compensation?
-	extr r21 = r21,16,8	// shift factor
-	;;
+	// Begin critical section
 .time_redo:
-	.pred.rel.mutex p8,p9,p10
-	ld4.acq r28 = [r29]	// xtime_lock.sequence. Must come first for locking purposes
+	ld4.acq r28 = [r20]	// gtod_lock.sequence, Must take first
 	;;
-	and r28 = ~1,r28	// Make sequence even to force retry if odd
+	and r28 = ~1,r28	// And make sequence even to force retry if odd
 	;;
+	ld8 r30 = [r21]		// clocksource->mmio_ptr
+	add r24 = IA64_CLKSRC_MULT_OFFSET,r20
+	ld4 r2 = [r29]		// itc_jitter value
+	add r23 = IA64_CLKSRC_SHIFT_OFFSET,r20
+	add r14 = IA64_CLKSRC_MASK_OFFSET,r20
+	;;
+	ld4 r3 = [r24]		// clocksource mult value
+	ld8 r14 = [r14]         // clocksource mask value
+	cmp.eq p8,p9 = 0,r30	// use cpu timer if no mmio_ptr
+	;;
+	setf.sig f7 = r3	// Setup for mult scaling of counter
+(p8)	cmp.ne p13,p0 = r2,r0	// need itc_jitter compensation, set p13
+	ld4 r23 = [r23]		// clocksource shift value
+	ld8 r24 = [r26]		// get clksrc_cycle_last value
+(p9)	cmp.eq p13,p0 = 0,r30	// if mmio_ptr, clear p13 jitter control
+	;;
+	.pred.rel.mutex p8,p9
 (p8)	mov r2 = ar.itc		// CPU_TIMER. 36 clocks latency!!!
-	add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
-(p9)	ld8 r2 = [r30]		// readq(ti->address). Could also have latency issues..
-(p10)	ld4 r2 = [r30]		// readw(ti->address)
-(p13)	add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20
-	;;			// could be removed by moving the last add upward
-	ld8 r26 = [r22]		// time_interpolator->last_counter
-(p13)	ld8 r25 = [r23]		// time interpolator->last_cycle
-	add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20
-(p15)	ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET
- 	ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
-	add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20
+(p9)	ld8 r2 = [r30]		// MMIO_TIMER. Could also have latency issues..
+(p13)	ld8 r25 = [r19]		// get itc_lastcycle value
+	;;		// ? could be removed by moving the last add upward
+	ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET	// tv_sec
 	;;
-	ld8 r18 = [r24]		// time_interpolator->offset
-	ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET	// xtime.tv_nsec
-(p13)	sub r3 = r25,r2	// Diff needed before comparison (thanks davidm)
+	ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET	// tv_nsec
+(p13)	sub r3 = r25,r2		// Diff needed before comparison (thanks davidm)
 	;;
-	ld8 r14 = [r14]		// time_interpolator->mask
-(p13)	cmp.gt.unc p6,p7 = r3,r0	// check if it is less than last. p6,p7 cleared
-	sub r10 = r2,r26	// current_counter - last_counter
+(p13)	cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
+	sub r10 = r2,r24	// current_cycle - last_cycle
 	;;
-(p6)	sub r10 = r25,r26	// time we got was less than last_cycle
+(p6)	sub r10 = r25,r24	// time we got was less than last_cycle
 (p7)	mov ar.ccv = r25	// more than last_cycle. Prep for cmpxchg
 	;;
+(p7)	cmpxchg8.rel r3 = [r19],r2,ar.ccv
+	;;
+(p7)	cmp.ne p7,p0 = r25,r3	// if cmpxchg not successful
+	;;
+(p7)	sub r10 = r3,r24	// then use new last_cycle instead
+	;;
 	and r10 = r10,r14	// Apply mask
 	;;
 	setf.sig f8 = r10
 	nop.i 123
 	;;
-(p7)	cmpxchg8.rel r3 = [r23],r2,ar.ccv
-EX(.fail_efault, probe.w.fault r31, 3)	// This takes 5 cycles and we have spare time
+	// fault check takes 5 cycles and we have spare time
+EX(.fail_efault, probe.w.fault r31, 3)
 	xmpy.l f8 = f8,f7	// nsec_per_cyc*(counter-last_counter)
-(p15)	add r9 = r9,r17		// Add wall to monotonic.secs to result secs
 	;;
-(p15)	ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
-(p7)	cmp.ne p7,p0 = r25,r3	// if cmpxchg not successful redo
-	// simulate tbit.nz.or p7,p0 = r28,0
+	// ? simulate tbit.nz.or p7,p0 = r28,0
 	getf.sig r2 = f8
 	mf
-	add r8 = r8,r18		// Add time interpolator offset
 	;;
-	ld4 r10 = [r29]		// xtime_lock.sequence
-(p15)	add r8 = r8, r17	// Add monotonic.nsecs to nsecs
-	shr.u r2 = r2,r21
-	;;		// overloaded 3 bundles!
-	// End critical section.
+	ld4 r10 = [r20]		// gtod_lock.sequence
+	shr.u r2 = r2,r23	// shift by factor
+	;;		// ? overloaded 3 bundles!
 	add r8 = r8,r2		// Add xtime.nsecs
-	cmp4.ne.or p7,p0 = r28,r10
-(p7)	br.cond.dpnt.few .time_redo	// sequence number changed ?
+	cmp4.ne p7,p0 = r28,r10
+(p7)	br.cond.dpnt.few .time_redo	// sequence number changed, redo
+	// End critical section.
 	// Now r8=tv->tv_nsec and r9=tv->tv_sec
 	mov r10 = r0
 	movl r2 = 1000000000
@@ -308,19 +305,19 @@
 .time_normalize:
 	mov r21 = r8
 	cmp.ge p6,p0 = r8,r2
-(p14)	shr.u r20 = r8, 3		// We can repeat this if necessary just wasting some time
+(p14)	shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
 	;;
 (p14)	setf.sig f8 = r20
 (p6)	sub r8 = r8,r2
-(p6)	add r9 = 1,r9			// two nops before the branch.
-(p14)	setf.sig f7 = r3		// Chances for repeats are 1 in 10000 for gettod
+(p6)	add r9 = 1,r9		// two nops before the branch.
+(p14)	setf.sig f7 = r3	// Chances for repeats are 1 in 10000 for gettod
 (p6)	br.cond.dpnt.few .time_normalize
 	;;
 	// Divided by 8 though shift. Now divide by 125
 	// The compiler was able to do that with a multiply
 	// and a shift and we do the same
-EX(.fail_efault, probe.w.fault r23, 3)		// This also costs 5 cycles
-(p14)	xmpy.hu f8 = f8, f7			// xmpy has 5 cycles latency so use it...
+EX(.fail_efault, probe.w.fault r23, 3)	// This also costs 5 cycles
+(p14)	xmpy.hu f8 = f8, f7		// xmpy has 5 cycles latency so use it
 	;;
 	mov r8 = r0
 (p14)	getf.sig r2 = f8
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
new file mode 100644
index 0000000..490dab5
--- /dev/null
+++ b/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -0,0 +1,23 @@
+/*
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *        Contributed by Peter Keilty <peter.keilty@hp.com>
+ *
+ * fsyscall gettimeofday data
+ */
+
+struct fsyscall_gtod_data_t {
+	seqlock_t	lock;
+	struct timespec	wall_time;
+	struct timespec monotonic_time;
+	cycle_t		clk_mask;
+	u32		clk_mult;
+	u32		clk_shift;
+	void		*clk_fsys_mmio;
+	cycle_t		clk_cycle_last;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
+struct itc_jitter_data_t {
+	int		itc_jitter;
+	cycle_t		itc_lastcycle;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 37f4652..91e6dc1 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -118,15 +118,25 @@
  * vector.
  */
 
-struct iosapic_rte_info {
-	struct list_head rte_list;	/* node in list of RTEs sharing the
-					 * same vector */
+#define NO_REF_RTE	0
+
+static struct iosapic {
 	char __iomem	*addr;		/* base address of IOSAPIC */
-	unsigned int	gsi_base;	/* first GSI assigned to this
-					 * IOSAPIC */
+	unsigned int	gsi_base;	/* GSI base */
+	unsigned short	num_rte;	/* # of RTEs on this IOSAPIC */
+	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
+#ifdef CONFIG_NUMA
+	unsigned short	node;		/* numa node association via pxm */
+#endif
+	spinlock_t	lock;		/* lock for indirect reg access */
+} iosapic_lists[NR_IOSAPICS];
+
+struct iosapic_rte_info {
+	struct list_head rte_list;	/* RTEs sharing the same vector */
 	char		rte_index;	/* IOSAPIC RTE index */
 	int		refcnt;		/* reference counter */
 	unsigned int	flags;		/* flags */
+	struct iosapic	*iosapic;
 } ____cacheline_aligned;
 
 static struct iosapic_intr_info {
@@ -140,24 +150,23 @@
 	unsigned char 	polarity: 1;	/* interrupt polarity
 					 * (see iosapic.h) */
 	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
-
-static struct iosapic {
-	char __iomem	*addr;		/* base address of IOSAPIC */
-	unsigned int 	gsi_base;	/* first GSI assigned to this
-					 * IOSAPIC */
-	unsigned short 	num_rte;	/* # of RTEs on this IOSAPIC */
-	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
-#ifdef CONFIG_NUMA
-	unsigned short	node;		/* numa node association via pxm */
-#endif
-} iosapic_lists[NR_IOSAPICS];
+} iosapic_intr_info[NR_IRQS];
 
 static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */
 
 static int iosapic_kmalloc_ok;
 static LIST_HEAD(free_rte_list);
 
+static inline void
+iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&iosapic->lock, flags);
+	__iosapic_write(iosapic->addr, reg, val);
+	spin_unlock_irqrestore(&iosapic->lock, flags);
+}
+
 /*
  * Find an IOSAPIC associated with a GSI
  */
@@ -175,17 +184,18 @@
 	return -1;
 }
 
-static inline int
-_gsi_to_vector (unsigned int gsi)
+static inline int __gsi_to_irq(unsigned int gsi)
 {
+	int irq;
 	struct iosapic_intr_info *info;
 	struct iosapic_rte_info *rte;
 
-	for (info = iosapic_intr_info; info <
-		     iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		info = &iosapic_intr_info[irq];
 		list_for_each_entry(rte, &info->rtes, rte_list)
-			if (rte->gsi_base + rte->rte_index == gsi)
-				return info - iosapic_intr_info;
+			if (rte->iosapic->gsi_base + rte->rte_index == gsi)
+				return irq;
+	}
 	return -1;
 }
 
@@ -196,7 +206,10 @@
 inline int
 gsi_to_vector (unsigned int gsi)
 {
-	return _gsi_to_vector(gsi);
+	int irq = __gsi_to_irq(gsi);
+	if (check_irq_used(irq) < 0)
+		return -1;
+	return irq_to_vector(irq);
 }
 
 int
@@ -204,66 +217,48 @@
 {
 	unsigned long flags;
 	int irq;
-	/*
-	 * XXX fix me: this assumes an identity mapping between IA-64 vector
-	 * and Linux irq numbers...
-	 */
-	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		irq = _gsi_to_vector(gsi);
-	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
 
+	spin_lock_irqsave(&iosapic_lock, flags);
+	irq = __gsi_to_irq(gsi);
+	spin_unlock_irqrestore(&iosapic_lock, flags);
 	return irq;
 }
 
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
-						  unsigned int vec)
+static struct iosapic_rte_info *find_rte(unsigned int irq, unsigned int gsi)
 {
 	struct iosapic_rte_info *rte;
 
-	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-		if (rte->gsi_base + rte->rte_index == gsi)
+	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+		if (rte->iosapic->gsi_base + rte->rte_index == gsi)
 			return rte;
 	return NULL;
 }
 
 static void
-set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
 {
 	unsigned long pol, trigger, dmode;
 	u32 low32, high32;
-	char __iomem *addr;
 	int rte_index;
 	char redir;
 	struct iosapic_rte_info *rte;
+	ia64_vector vector = irq_to_vector(irq);
 
 	DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
 
-	rte = gsi_vector_to_rte(gsi, vector);
+	rte = find_rte(irq, gsi);
 	if (!rte)
 		return;		/* not an IOSAPIC interrupt */
 
 	rte_index = rte->rte_index;
-	addr	= rte->addr;
-	pol     = iosapic_intr_info[vector].polarity;
-	trigger = iosapic_intr_info[vector].trigger;
-	dmode   = iosapic_intr_info[vector].dmode;
+	pol     = iosapic_intr_info[irq].polarity;
+	trigger = iosapic_intr_info[irq].trigger;
+	dmode   = iosapic_intr_info[irq].dmode;
 
 	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
 
 #ifdef CONFIG_SMP
-	{
-		unsigned int irq;
-
-		for (irq = 0; irq < NR_IRQS; ++irq)
-			if (irq_to_vector(irq) == vector) {
-				set_irq_affinity_info(irq,
-						      (int)(dest & 0xffff),
-						      redir);
-				break;
-			}
-	}
+	set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
 #endif
 
 	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
@@ -275,10 +270,10 @@
 	/* dest contains both id and eid */
 	high32 = (dest << IOSAPIC_DEST_SHIFT);
 
-	iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
-	iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-	iosapic_intr_info[vector].low32 = low32;
-	iosapic_intr_info[vector].dest = dest;
+	iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+	iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
+	iosapic_intr_info[irq].low32 = low32;
+	iosapic_intr_info[irq].dest = dest;
 }
 
 static void
@@ -294,15 +289,18 @@
 {
 	struct iosapic_intr_info *info;
 	struct iosapic_rte_info *rte;
-	u8 vec = 0;
-	for (info = iosapic_intr_info; info <
-			iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
+	ia64_vector vec;
+	int irq;
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		info = &iosapic_intr_info[irq];
+		vec = irq_to_vector(irq);
 		list_for_each_entry(rte, &info->rtes,
 				rte_list) {
-			iosapic_write(rte->addr,
+			iosapic_write(rte->iosapic,
 					IOSAPIC_RTE_LOW(rte->rte_index),
 					IOSAPIC_MASK|vec);
-			iosapic_eoi(rte->addr, vec);
+			iosapic_eoi(rte->iosapic->addr, vec);
 		}
 	}
 }
@@ -311,54 +309,36 @@
 static void
 mask_irq (unsigned int irq)
 {
-	unsigned long flags;
-	char __iomem *addr;
 	u32 low32;
 	int rte_index;
-	ia64_vector vec = irq_to_vector(irq);
 	struct iosapic_rte_info *rte;
 
-	if (list_empty(&iosapic_intr_info[vec].rtes))
+	if (list_empty(&iosapic_intr_info[irq].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
-	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		/* set only the mask bit */
-		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-				    rte_list) {
-			addr = rte->addr;
-			rte_index = rte->rte_index;
-			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-		}
+	/* set only the mask bit */
+	low32 = iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+		rte_index = rte->rte_index;
+		iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 static void
 unmask_irq (unsigned int irq)
 {
-	unsigned long flags;
-	char __iomem *addr;
 	u32 low32;
 	int rte_index;
-	ia64_vector vec = irq_to_vector(irq);
 	struct iosapic_rte_info *rte;
 
-	if (list_empty(&iosapic_intr_info[vec].rtes))
+	if (list_empty(&iosapic_intr_info[irq].rtes))
 		return;			/* not an IOSAPIC interrupt! */
 
-	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-				    rte_list) {
-			addr = rte->addr;
-			rte_index = rte->rte_index;
-			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-		}
+	low32 = iosapic_intr_info[irq].low32 &= ~IOSAPIC_MASK;
+	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+		rte_index = rte->rte_index;
+		iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 
@@ -366,23 +346,24 @@
 iosapic_set_affinity (unsigned int irq, cpumask_t mask)
 {
 #ifdef CONFIG_SMP
-	unsigned long flags;
 	u32 high32, low32;
 	int dest, rte_index;
-	char __iomem *addr;
 	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
-	ia64_vector vec;
 	struct iosapic_rte_info *rte;
+	struct iosapic *iosapic;
 
 	irq &= (~IA64_IRQ_REDIRECTED);
-	vec = irq_to_vector(irq);
 
+	cpus_and(mask, mask, cpu_online_map);
 	if (cpus_empty(mask))
 		return;
 
+	if (reassign_irq_vector(irq, first_cpu(mask)))
+		return;
+
 	dest = cpu_physical_id(first_cpu(mask));
 
-	if (list_empty(&iosapic_intr_info[vec].rtes))
+	if (list_empty(&iosapic_intr_info[irq].rtes))
 		return;			/* not an IOSAPIC interrupt */
 
 	set_irq_affinity_info(irq, dest, redir);
@@ -390,31 +371,24 @@
 	/* dest contains both id and eid */
 	high32 = dest << IOSAPIC_DEST_SHIFT;
 
-	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		low32 = iosapic_intr_info[vec].low32 &
-			~(7 << IOSAPIC_DELIVERY_SHIFT);
+	low32 = iosapic_intr_info[irq].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+	if (redir)
+		/* change delivery mode to lowest priority */
+		low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+	else
+		/* change delivery mode to fixed */
+		low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+	low32 &= IOSAPIC_VECTOR_MASK;
+	low32 |= irq_to_vector(irq);
 
-		if (redir)
-		        /* change delivery mode to lowest priority */
-			low32 |= (IOSAPIC_LOWEST_PRIORITY <<
-				  IOSAPIC_DELIVERY_SHIFT);
-		else
-		        /* change delivery mode to fixed */
-			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
-		iosapic_intr_info[vec].low32 = low32;
-		iosapic_intr_info[vec].dest = dest;
-		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-				    rte_list) {
-			addr = rte->addr;
-			rte_index = rte->rte_index;
-			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
-				      high32);
-			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-		}
+	iosapic_intr_info[irq].low32 = low32;
+	iosapic_intr_info[irq].dest = dest;
+	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+		iosapic = rte->iosapic;
+		rte_index = rte->rte_index;
+		iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+		iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
 	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
 #endif
 }
 
@@ -434,10 +408,20 @@
 {
 	ia64_vector vec = irq_to_vector(irq);
 	struct iosapic_rte_info *rte;
+	int do_unmask_irq = 0;
 
-	move_native_irq(irq);
-	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-		iosapic_eoi(rte->addr, vec);
+	if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+		do_unmask_irq = 1;
+		mask_irq(irq);
+	}
+
+	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+		iosapic_eoi(rte->iosapic->addr, vec);
+
+	if (unlikely(do_unmask_irq)) {
+		move_masked_irq(irq);
+		unmask_irq(irq);
+	}
 }
 
 #define iosapic_shutdown_level_irq	mask_irq
@@ -519,13 +503,12 @@
 	 *	unsigned int reserved2 : 8;
 	 * }
 	 */
-	return iosapic_read(addr, IOSAPIC_VERSION);
+	return __iosapic_read(addr, IOSAPIC_VERSION);
 }
 
-static int iosapic_find_sharable_vector (unsigned long trigger,
-					 unsigned long pol)
+static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol)
 {
-	int i, vector = -1, min_count = -1;
+	int i, irq = -ENOSPC, min_count = -1;
 	struct iosapic_intr_info *info;
 
 	/*
@@ -533,21 +516,21 @@
 	 * supported yet
 	 */
 	if (trigger == IOSAPIC_EDGE)
-		return -1;
+		return -EINVAL;
 
-	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+	for (i = 0; i <= NR_IRQS; i++) {
 		info = &iosapic_intr_info[i];
 		if (info->trigger == trigger && info->polarity == pol &&
-		    (info->dmode == IOSAPIC_FIXED || info->dmode ==
-		     IOSAPIC_LOWEST_PRIORITY)) {
+		    (info->dmode == IOSAPIC_FIXED ||
+		     info->dmode == IOSAPIC_LOWEST_PRIORITY) &&
+		    can_request_irq(i, IRQF_SHARED)) {
 			if (min_count == -1 || info->count < min_count) {
-				vector = i;
+				irq = i;
 				min_count = info->count;
 			}
 		}
 	}
-
-	return vector;
+	return irq;
 }
 
 /*
@@ -555,25 +538,25 @@
  *  assign a new vector for the other and make the vector available
  */
 static void __init
-iosapic_reassign_vector (int vector)
+iosapic_reassign_vector (int irq)
 {
-	int new_vector;
+	int new_irq;
 
-	if (!list_empty(&iosapic_intr_info[vector].rtes)) {
-		new_vector = assign_irq_vector(AUTO_ASSIGN);
-		if (new_vector < 0)
+	if (!list_empty(&iosapic_intr_info[irq].rtes)) {
+		new_irq = create_irq();
+		if (new_irq < 0)
 			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
 		printk(KERN_INFO "Reassigning vector %d to %d\n",
-		       vector, new_vector);
-		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
+		       irq_to_vector(irq), irq_to_vector(new_irq));
+		memcpy(&iosapic_intr_info[new_irq], &iosapic_intr_info[irq],
 		       sizeof(struct iosapic_intr_info));
-		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
-		list_move(iosapic_intr_info[vector].rtes.next,
-			  &iosapic_intr_info[new_vector].rtes);
-		memset(&iosapic_intr_info[vector], 0,
+		INIT_LIST_HEAD(&iosapic_intr_info[new_irq].rtes);
+		list_move(iosapic_intr_info[irq].rtes.next,
+			  &iosapic_intr_info[new_irq].rtes);
+		memset(&iosapic_intr_info[irq], 0,
 		       sizeof(struct iosapic_intr_info));
-		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
-		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+		iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
+		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
 	}
 }
 
@@ -610,29 +593,18 @@
 	return rte;
 }
 
-static void iosapic_free_rte (struct iosapic_rte_info *rte)
+static inline int irq_is_shared (int irq)
 {
-	if (rte->flags & RTE_PREALLOCATED)
-		list_add_tail(&rte->rte_list, &free_rte_list);
-	else
-		kfree(rte);
-}
-
-static inline int vector_is_shared (int vector)
-{
-	return (iosapic_intr_info[vector].count > 1);
+	return (iosapic_intr_info[irq].count > 1);
 }
 
 static int
-register_intr (unsigned int gsi, int vector, unsigned char delivery,
+register_intr (unsigned int gsi, int irq, unsigned char delivery,
 	       unsigned long polarity, unsigned long trigger)
 {
 	irq_desc_t *idesc;
 	struct hw_interrupt_type *irq_type;
-	int rte_index;
 	int index;
-	unsigned long gsi_base;
-	void __iomem *iosapic_address;
 	struct iosapic_rte_info *rte;
 
 	index = find_iosapic(gsi);
@@ -642,10 +614,7 @@
 		return -ENODEV;
 	}
 
-	iosapic_address = iosapic_lists[index].addr;
-	gsi_base = iosapic_lists[index].gsi_base;
-
-	rte = gsi_vector_to_rte(gsi, vector);
+	rte = find_rte(irq, gsi);
 	if (!rte) {
 		rte = iosapic_alloc_rte();
 		if (!rte) {
@@ -654,40 +623,42 @@
 			return -ENOMEM;
 		}
 
-		rte_index = gsi - gsi_base;
-		rte->rte_index	= rte_index;
-		rte->addr	= iosapic_address;
-		rte->gsi_base	= gsi_base;
+		rte->iosapic	= &iosapic_lists[index];
+		rte->rte_index	= gsi - rte->iosapic->gsi_base;
 		rte->refcnt++;
-		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
-		iosapic_intr_info[vector].count++;
+		list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes);
+		iosapic_intr_info[irq].count++;
 		iosapic_lists[index].rtes_inuse++;
 	}
-	else if (vector_is_shared(vector)) {
-		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
-		if (info->trigger != trigger || info->polarity != polarity) {
+	else if (rte->refcnt == NO_REF_RTE) {
+		struct iosapic_intr_info *info = &iosapic_intr_info[irq];
+		if (info->count > 0 &&
+		    (info->trigger != trigger || info->polarity != polarity)){
 			printk (KERN_WARNING
 				"%s: cannot override the interrupt\n",
 				__FUNCTION__);
 			return -EINVAL;
 		}
+		rte->refcnt++;
+		iosapic_intr_info[irq].count++;
+		iosapic_lists[index].rtes_inuse++;
 	}
 
-	iosapic_intr_info[vector].polarity = polarity;
-	iosapic_intr_info[vector].dmode    = delivery;
-	iosapic_intr_info[vector].trigger  = trigger;
+	iosapic_intr_info[irq].polarity = polarity;
+	iosapic_intr_info[irq].dmode    = delivery;
+	iosapic_intr_info[irq].trigger  = trigger;
 
 	if (trigger == IOSAPIC_EDGE)
 		irq_type = &irq_type_iosapic_edge;
 	else
 		irq_type = &irq_type_iosapic_level;
 
-	idesc = irq_desc + vector;
+	idesc = irq_desc + irq;
 	if (idesc->chip != irq_type) {
 		if (idesc->chip != &no_irq_type)
 			printk(KERN_WARNING
 			       "%s: changing vector %d from %s to %s\n",
-			       __FUNCTION__, vector,
+			       __FUNCTION__, irq_to_vector(irq),
 			       idesc->chip->name, irq_type->name);
 		idesc->chip = irq_type;
 	}
@@ -695,18 +666,19 @@
 }
 
 static unsigned int
-get_target_cpu (unsigned int gsi, int vector)
+get_target_cpu (unsigned int gsi, int irq)
 {
 #ifdef CONFIG_SMP
 	static int cpu = -1;
 	extern int cpe_vector;
+	cpumask_t domain = irq_to_domain(irq);
 
 	/*
 	 * In case of vector shared by multiple RTEs, all RTEs that
 	 * share the vector need to use the same destination CPU.
 	 */
-	if (!list_empty(&iosapic_intr_info[vector].rtes))
-		return iosapic_intr_info[vector].dest;
+	if (!list_empty(&iosapic_intr_info[irq].rtes))
+		return iosapic_intr_info[irq].dest;
 
 	/*
 	 * If the platform supports redirection via XTP, let it
@@ -723,7 +695,7 @@
 		return cpu_physical_id(smp_processor_id());
 
 #ifdef CONFIG_ACPI
-	if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR)
+	if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)
 		return get_cpei_target_cpu();
 #endif
 
@@ -738,7 +710,7 @@
 			goto skip_numa_setup;
 
 		cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
-
+		cpus_and(cpu_mask, cpu_mask, domain);
 		for_each_cpu_mask(numa_cpu, cpu_mask) {
 			if (!cpu_online(numa_cpu))
 				cpu_clear(numa_cpu, cpu_mask);
@@ -749,8 +721,8 @@
 		if (!num_cpus)
 			goto skip_numa_setup;
 
-		/* Use vector assignment to distribute across cpus in node */
-		cpu_index = vector % num_cpus;
+		/* Use irq assignment to distribute across cpus in node */
+		cpu_index = irq % num_cpus;
 
 		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
 			numa_cpu = next_cpu(numa_cpu, cpu_mask);
@@ -768,7 +740,7 @@
 	do {
 		if (++cpu >= NR_CPUS)
 			cpu = 0;
-	} while (!cpu_online(cpu));
+	} while (!cpu_online(cpu) || !cpu_isset(cpu, domain));
 
 	return cpu_physical_id(cpu);
 #else  /* CONFIG_SMP */
@@ -785,84 +757,72 @@
 iosapic_register_intr (unsigned int gsi,
 		       unsigned long polarity, unsigned long trigger)
 {
-	int vector, mask = 1, err;
+	int irq, mask = 1, err;
 	unsigned int dest;
 	unsigned long flags;
 	struct iosapic_rte_info *rte;
 	u32 low32;
-again:
+
 	/*
 	 * If this GSI has already been registered (i.e., it's a
 	 * shared interrupt, or we lost a race to register it),
 	 * don't touch the RTE.
 	 */
 	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		vector = gsi_to_vector(gsi);
-		if (vector > 0) {
-			rte = gsi_vector_to_rte(gsi, vector);
+	irq = __gsi_to_irq(gsi);
+	if (irq > 0) {
+		rte = find_rte(irq, gsi);
+		if(iosapic_intr_info[irq].count == 0) {
+			assign_irq_vector(irq);
+			dynamic_irq_init(irq);
+		} else if (rte->refcnt != NO_REF_RTE) {
 			rte->refcnt++;
-			spin_unlock_irqrestore(&iosapic_lock, flags);
-			return vector;
+			goto unlock_iosapic_lock;
 		}
-	}
-	spin_unlock_irqrestore(&iosapic_lock, flags);
+	} else
+		irq = create_irq();
 
 	/* If vector is running out, we try to find a sharable vector */
-	vector = assign_irq_vector(AUTO_ASSIGN);
-	if (vector < 0) {
-		vector = iosapic_find_sharable_vector(trigger, polarity);
-  		if (vector < 0)
-			return -ENOSPC;
+	if (irq < 0) {
+		irq = iosapic_find_sharable_irq(trigger, polarity);
+		if (irq < 0)
+			goto unlock_iosapic_lock;
 	}
 
-	spin_lock_irqsave(&irq_desc[vector].lock, flags);
-	spin_lock(&iosapic_lock);
-	{
-		if (gsi_to_vector(gsi) > 0) {
-			if (list_empty(&iosapic_intr_info[vector].rtes))
-				free_irq_vector(vector);
-			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_desc[vector].lock,
-					       flags);
-			goto again;
-		}
-
-		dest = get_target_cpu(gsi, vector);
-		err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-			      polarity, trigger);
-		if (err < 0) {
-			spin_unlock(&iosapic_lock);
-			spin_unlock_irqrestore(&irq_desc[vector].lock,
-					       flags);
-			return err;
-		}
-
-		/*
-		 * If the vector is shared and already unmasked for
-		 * other interrupt sources, don't mask it.
-		 */
-		low32 = iosapic_intr_info[vector].low32;
-		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
-			mask = 0;
-		set_rte(gsi, vector, dest, mask);
+	spin_lock(&irq_desc[irq].lock);
+	dest = get_target_cpu(gsi, irq);
+	err = register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY,
+			    polarity, trigger);
+	if (err < 0) {
+		irq = err;
+		goto unlock_all;
 	}
-	spin_unlock(&iosapic_lock);
-	spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
+
+	/*
+	 * If the vector is shared and already unmasked for other
+	 * interrupt sources, don't mask it.
+	 */
+	low32 = iosapic_intr_info[irq].low32;
+	if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK))
+		mask = 0;
+	set_rte(gsi, irq, dest, mask);
 
 	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
 	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       cpu_logical_id(dest), dest, vector);
-
-	return vector;
+	       cpu_logical_id(dest), dest, irq_to_vector(irq));
+ unlock_all:
+	spin_unlock(&irq_desc[irq].lock);
+ unlock_iosapic_lock:
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+	return irq;
 }
 
 void
 iosapic_unregister_intr (unsigned int gsi)
 {
 	unsigned long flags;
-	int irq, vector, index;
+	int irq, index;
 	irq_desc_t *idesc;
 	u32 low32;
 	unsigned long trigger, polarity;
@@ -881,78 +841,56 @@
 		WARN_ON(1);
 		return;
 	}
-	vector = irq_to_vector(irq);
+
+	spin_lock_irqsave(&iosapic_lock, flags);
+	if ((rte = find_rte(irq, gsi)) == NULL) {
+		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+		       gsi);
+		WARN_ON(1);
+		goto out;
+	}
+
+	if (--rte->refcnt > 0)
+		goto out;
 
 	idesc = irq_desc + irq;
-	spin_lock_irqsave(&idesc->lock, flags);
-	spin_lock(&iosapic_lock);
-	{
-		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
-			printk(KERN_ERR
-			       "iosapic_unregister_intr(%u) unbalanced\n",
-			       gsi);
-			WARN_ON(1);
-			goto out;
-		}
+	rte->refcnt = NO_REF_RTE;
 
-		if (--rte->refcnt > 0)
-			goto out;
+	/* Mask the interrupt */
+	low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
+	iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
 
-		/* Mask the interrupt */
-		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
-		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
-			      low32);
+	iosapic_intr_info[irq].count--;
+	index = find_iosapic(gsi);
+	iosapic_lists[index].rtes_inuse--;
+	WARN_ON(iosapic_lists[index].rtes_inuse < 0);
 
-		/* Remove the rte entry from the list */
-		list_del(&rte->rte_list);
-		iosapic_intr_info[vector].count--;
-		iosapic_free_rte(rte);
-		index = find_iosapic(gsi);
-		iosapic_lists[index].rtes_inuse--;
-		WARN_ON(iosapic_lists[index].rtes_inuse < 0);
+	trigger  = iosapic_intr_info[irq].trigger;
+	polarity = iosapic_intr_info[irq].polarity;
+	dest     = iosapic_intr_info[irq].dest;
+	printk(KERN_INFO
+	       "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+	       cpu_logical_id(dest), dest, irq_to_vector(irq));
 
-		trigger	 = iosapic_intr_info[vector].trigger;
-		polarity = iosapic_intr_info[vector].polarity;
-		dest     = iosapic_intr_info[vector].dest;
-		printk(KERN_INFO
-		       "GSI %u (%s, %s) -> CPU %d (0x%04x)"
-		       " vector %d unregistered\n",
-		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
-		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-		       cpu_logical_id(dest), dest, vector);
-
-		if (list_empty(&iosapic_intr_info[vector].rtes)) {
-			/* Sanity check */
-			BUG_ON(iosapic_intr_info[vector].count);
-
-			/* Clear the interrupt controller descriptor */
-			idesc->chip = &no_irq_type;
-
+	if (iosapic_intr_info[irq].count == 0) {
 #ifdef CONFIG_SMP
-			/* Clear affinity */
-			cpus_setall(idesc->affinity);
+		/* Clear affinity */
+		cpus_setall(idesc->affinity);
 #endif
+		/* Clear the interrupt information */
+		iosapic_intr_info[irq].dest = 0;
+		iosapic_intr_info[irq].dmode = 0;
+		iosapic_intr_info[irq].polarity = 0;
+		iosapic_intr_info[irq].trigger = 0;
+		iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
 
-			/* Clear the interrupt information */
-			memset(&iosapic_intr_info[vector], 0,
-			       sizeof(struct iosapic_intr_info));
-			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
-			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
-
-			if (idesc->action) {
-				printk(KERN_ERR
-				       "interrupt handlers still exist on"
-				       "IRQ %u\n", irq);
-				WARN_ON(1);
-			}
-
-			/* Free the interrupt vector */
-			free_irq_vector(vector);
-		}
+		/* Destroy and reserve IRQ */
+		destroy_and_reserve_irq(irq);
 	}
  out:
-	spin_unlock(&iosapic_lock);
-	spin_unlock_irqrestore(&idesc->lock, flags);
+	spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 /*
@@ -965,27 +903,30 @@
 {
 	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
 	unsigned char delivery;
-	int vector, mask = 0;
+	int irq, vector, mask = 0;
 	unsigned int dest = ((id << 8) | eid) & 0xffff;
 
 	switch (int_type) {
 	      case ACPI_INTERRUPT_PMI:
-		vector = iosapic_vector;
+		irq = vector = iosapic_vector;
+		bind_irq_vector(irq, vector, CPU_MASK_ALL);
 		/*
 		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
 		 * we need to make sure the vector is available
 		 */
-		iosapic_reassign_vector(vector);
+		iosapic_reassign_vector(irq);
 		delivery = IOSAPIC_PMI;
 		break;
 	      case ACPI_INTERRUPT_INIT:
-		vector = assign_irq_vector(AUTO_ASSIGN);
-		if (vector < 0)
+		irq = create_irq();
+		if (irq < 0)
 			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+		vector = irq_to_vector(irq);
 		delivery = IOSAPIC_INIT;
 		break;
 	      case ACPI_INTERRUPT_CPEI:
-		vector = IA64_CPE_VECTOR;
+		irq = vector = IA64_CPE_VECTOR;
+		BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
 		delivery = IOSAPIC_LOWEST_PRIORITY;
 		mask = 1;
 		break;
@@ -995,7 +936,7 @@
 		return -1;
 	}
 
-	register_intr(gsi, vector, delivery, polarity, trigger);
+	register_intr(gsi, irq, delivery, polarity, trigger);
 
 	printk(KERN_INFO
 	       "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
@@ -1005,7 +946,7 @@
 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
 	       cpu_logical_id(dest), dest, vector);
 
-	set_rte(gsi, vector, dest, mask);
+	set_rte(gsi, irq, dest, mask);
 	return vector;
 }
 
@@ -1017,30 +958,32 @@
 			  unsigned long polarity,
 			  unsigned long trigger)
 {
-	int vector;
+	int vector, irq;
 	unsigned int dest = cpu_physical_id(smp_processor_id());
 
-	vector = isa_irq_to_vector(isa_irq);
-
-	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+	irq = vector = isa_irq_to_vector(isa_irq);
+	BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
+	register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
 	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
 	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
 	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
 	    cpu_logical_id(dest), dest, vector);
 
-	set_rte(gsi, vector, dest, 1);
+	set_rte(gsi, irq, dest, 1);
 }
 
 void __init
 iosapic_system_init (int system_pcat_compat)
 {
-	int vector;
+	int irq;
 
-	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
-		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+	for (irq = 0; irq < NR_IRQS; ++irq) {
+		iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
 		/* mark as unused */
-		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
+
+		iosapic_intr_info[irq].count = 0;
 	}
 
 	pcat_compat = system_pcat_compat;
@@ -1108,31 +1051,35 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		addr = ioremap(phys_addr, 0);
-		ver = iosapic_version(addr);
-
-		if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
-			iounmap(addr);
-			spin_unlock_irqrestore(&iosapic_lock, flags);
-			return err;
-		}
-
-		/*
-		 * The MAX_REDIR register holds the highest input pin
-		 * number (starting from 0).
-		 * We add 1 so that we can use it for number of pins (= RTEs)
-		 */
-		num_rte = ((ver >> 16) & 0xff) + 1;
-
-		index = iosapic_alloc();
-		iosapic_lists[index].addr = addr;
-		iosapic_lists[index].gsi_base = gsi_base;
-		iosapic_lists[index].num_rte = num_rte;
-#ifdef CONFIG_NUMA
-		iosapic_lists[index].node = MAX_NUMNODES;
-#endif
+	index = find_iosapic(gsi_base);
+	if (index >= 0) {
+		spin_unlock_irqrestore(&iosapic_lock, flags);
+		return -EBUSY;
 	}
+
+	addr = ioremap(phys_addr, 0);
+	ver = iosapic_version(addr);
+	if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+		iounmap(addr);
+		spin_unlock_irqrestore(&iosapic_lock, flags);
+		return err;
+	}
+
+	/*
+	 * The MAX_REDIR register holds the highest input pin number
+	 * (starting from 0).  We add 1 so that we can use it for
+	 * number of pins (= RTEs)
+	 */
+	num_rte = ((ver >> 16) & 0xff) + 1;
+
+	index = iosapic_alloc();
+	iosapic_lists[index].addr = addr;
+	iosapic_lists[index].gsi_base = gsi_base;
+	iosapic_lists[index].num_rte = num_rte;
+#ifdef CONFIG_NUMA
+	iosapic_lists[index].node = MAX_NUMNODES;
+#endif
+	spin_lock_init(&iosapic_lists[index].lock);
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 
 	if ((gsi_base == 0) && pcat_compat) {
@@ -1157,25 +1104,22 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&iosapic_lock, flags);
-	{
-		index = find_iosapic(gsi_base);
-		if (index < 0) {
-			printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
-			       __FUNCTION__, gsi_base);
-			goto out;
-		}
-
-		if (iosapic_lists[index].rtes_inuse) {
-			err = -EBUSY;
-			printk(KERN_WARNING
-			       "%s: IOSAPIC for GSI base %u is busy\n",
-			       __FUNCTION__, gsi_base);
-			goto out;
-		}
-
-		iounmap(iosapic_lists[index].addr);
-		iosapic_free(index);
+	index = find_iosapic(gsi_base);
+	if (index < 0) {
+		printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+		       __FUNCTION__, gsi_base);
+		goto out;
 	}
+
+	if (iosapic_lists[index].rtes_inuse) {
+		err = -EBUSY;
+		printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+		       __FUNCTION__, gsi_base);
+		goto out;
+	}
+
+	iounmap(iosapic_lists[index].addr);
+	iosapic_free(index);
  out:
 	spin_unlock_irqrestore(&iosapic_lock, flags);
 	return err;
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 407b458..cc3ee4e 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -35,7 +35,7 @@
 #ifdef CONFIG_IA64_GENERIC
 unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
 {
-	return (unsigned int) vec;
+	return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index bc47049..91797c1 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -46,6 +46,12 @@
 
 #define IRQ_DEBUG	0
 
+#define IRQ_VECTOR_UNASSIGNED	(0)
+
+#define IRQ_UNUSED		(0)
+#define IRQ_USED		(1)
+#define IRQ_RSVD		(2)
+
 /* These can be overridden in platform_irq_init */
 int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
 int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -54,6 +60,8 @@
 void __iomem *ipi_base_addr = ((void __iomem *)
 			       (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
 
+static cpumask_t vector_allocation_domain(int cpu);
+
 /*
  * Legacy IRQ to IA-64 vector translation table.
  */
@@ -64,46 +72,269 @@
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
+DEFINE_SPINLOCK(vector_lock);
+
+struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+	[0 ... NR_IRQS - 1] = {
+		.vector = IRQ_VECTOR_UNASSIGNED,
+		.domain = CPU_MASK_NONE
+	}
+};
+
+DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = {
+	[0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR
+};
+
+static cpumask_t vector_table[IA64_MAX_DEVICE_VECTORS] = {
+	[0 ... IA64_MAX_DEVICE_VECTORS - 1] = CPU_MASK_NONE
+};
+
+static int irq_status[NR_IRQS] = {
+	[0 ... NR_IRQS -1] = IRQ_UNUSED
+};
+
+int check_irq_used(int irq)
+{
+	if (irq_status[irq] == IRQ_USED)
+		return 1;
+
+	return -1;
+}
+
+static void reserve_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	irq_status[irq] = IRQ_RSVD;
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+static inline int find_unassigned_irq(void)
+{
+	int irq;
+
+	for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
+		if (irq_status[irq] == IRQ_UNUSED)
+			return irq;
+	return -ENOSPC;
+}
+
+static inline int find_unassigned_vector(cpumask_t domain)
+{
+	cpumask_t mask;
+	int pos;
+
+	cpus_and(mask, domain, cpu_online_map);
+	if (cpus_empty(mask))
+		return -EINVAL;
+
+	for (pos = 0; pos < IA64_NUM_DEVICE_VECTORS; pos++) {
+		cpus_and(mask, domain, vector_table[pos]);
+		if (!cpus_empty(mask))
+			continue;
+		return IA64_FIRST_DEVICE_VECTOR + pos;
+	}
+	return -ENOSPC;
+}
+
+static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+	cpumask_t mask;
+	int cpu, pos;
+	struct irq_cfg *cfg = &irq_cfg[irq];
+
+	cpus_and(mask, domain, cpu_online_map);
+	if (cpus_empty(mask))
+		return -EINVAL;
+	if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
+		return 0;
+	if (cfg->vector != IRQ_VECTOR_UNASSIGNED)
+		return -EBUSY;
+	for_each_cpu_mask(cpu, mask)
+		per_cpu(vector_irq, cpu)[vector] = irq;
+	cfg->vector = vector;
+	cfg->domain = domain;
+	irq_status[irq] = IRQ_USED;
+	pos = vector - IA64_FIRST_DEVICE_VECTOR;
+	cpus_or(vector_table[pos], vector_table[pos], domain);
+	return 0;
+}
+
+int bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	ret = __bind_irq_vector(irq, vector, domain);
+	spin_unlock_irqrestore(&vector_lock, flags);
+	return ret;
+}
+
+static void __clear_irq_vector(int irq)
+{
+	int vector, cpu, pos;
+	cpumask_t mask;
+	cpumask_t domain;
+	struct irq_cfg *cfg = &irq_cfg[irq];
+
+	BUG_ON((unsigned)irq >= NR_IRQS);
+	BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
+	vector = cfg->vector;
+	domain = cfg->domain;
+	cpus_and(mask, cfg->domain, cpu_online_map);
+	for_each_cpu_mask(cpu, mask)
+		per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+	cfg->vector = IRQ_VECTOR_UNASSIGNED;
+	cfg->domain = CPU_MASK_NONE;
+	irq_status[irq] = IRQ_UNUSED;
+	pos = vector - IA64_FIRST_DEVICE_VECTOR;
+	cpus_andnot(vector_table[pos], vector_table[pos], domain);
+}
+
+static void clear_irq_vector(int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	__clear_irq_vector(irq);
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
 
 int
 assign_irq_vector (int irq)
 {
-	int pos, vector;
- again:
-	pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
-	vector = IA64_FIRST_DEVICE_VECTOR + pos;
-	if (vector > IA64_LAST_DEVICE_VECTOR)
-		return -ENOSPC;
-	if (test_and_set_bit(pos, ia64_vector_mask))
-		goto again;
+	unsigned long flags;
+	int vector, cpu;
+	cpumask_t domain;
+
+	vector = -ENOSPC;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	if (irq < 0) {
+		goto out;
+	}
+	for_each_online_cpu(cpu) {
+		domain = vector_allocation_domain(cpu);
+		vector = find_unassigned_vector(domain);
+		if (vector >= 0)
+			break;
+	}
+	if (vector < 0)
+		goto out;
+	BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+	spin_unlock_irqrestore(&vector_lock, flags);
 	return vector;
 }
 
 void
 free_irq_vector (int vector)
 {
-	int pos;
-
-	if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
+	if (vector < IA64_FIRST_DEVICE_VECTOR ||
+	    vector > IA64_LAST_DEVICE_VECTOR)
 		return;
-
-	pos = vector - IA64_FIRST_DEVICE_VECTOR;
-	if (!test_and_clear_bit(pos, ia64_vector_mask))
-		printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
+	clear_irq_vector(vector);
 }
 
 int
 reserve_irq_vector (int vector)
 {
-	int pos;
-
 	if (vector < IA64_FIRST_DEVICE_VECTOR ||
 	    vector > IA64_LAST_DEVICE_VECTOR)
 		return -EINVAL;
+	return !!bind_irq_vector(vector, vector, CPU_MASK_ALL);
+}
 
-	pos = vector - IA64_FIRST_DEVICE_VECTOR;
-	return test_and_set_bit(pos, ia64_vector_mask);
+/*
+ * Initialize vector_irq on a new cpu. This function must be called
+ * with vector_lock held.
+ */
+void __setup_vector_irq(int cpu)
+{
+	int irq, vector;
+
+	/* Clear vector_irq */
+	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
+		per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+	/* Mark the inuse vectors */
+	for (irq = 0; irq < NR_IRQS; ++irq) {
+		if (!cpu_isset(cpu, irq_cfg[irq].domain))
+			continue;
+		vector = irq_to_vector(irq);
+		per_cpu(vector_irq, cpu)[vector] = irq;
+	}
+}
+
+#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+static enum vector_domain_type {
+	VECTOR_DOMAIN_NONE,
+	VECTOR_DOMAIN_PERCPU
+} vector_domain_type = VECTOR_DOMAIN_NONE;
+
+static cpumask_t vector_allocation_domain(int cpu)
+{
+	if (vector_domain_type == VECTOR_DOMAIN_PERCPU)
+		return cpumask_of_cpu(cpu);
+	return CPU_MASK_ALL;
+}
+
+static int __init parse_vector_domain(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+	if (!strcmp(arg, "percpu")) {
+		vector_domain_type = VECTOR_DOMAIN_PERCPU;
+		no_int_routing = 1;
+	}
+	return 1;
+}
+early_param("vector", parse_vector_domain);
+#else
+static cpumask_t vector_allocation_domain(int cpu)
+{
+	return CPU_MASK_ALL;
+}
+#endif
+
+
+void destroy_and_reserve_irq(unsigned int irq)
+{
+	dynamic_irq_cleanup(irq);
+
+	clear_irq_vector(irq);
+	reserve_irq(irq);
+}
+
+static int __reassign_irq_vector(int irq, int cpu)
+{
+	struct irq_cfg *cfg = &irq_cfg[irq];
+	int vector;
+	cpumask_t domain;
+
+	if (cfg->vector == IRQ_VECTOR_UNASSIGNED || !cpu_online(cpu))
+		return -EINVAL;
+	if (cpu_isset(cpu, cfg->domain))
+		return 0;
+	domain = vector_allocation_domain(cpu);
+	vector = find_unassigned_vector(domain);
+	if (vector < 0)
+		return -ENOSPC;
+	__clear_irq_vector(irq);
+	BUG_ON(__bind_irq_vector(irq, vector, domain));
+	return 0;
+}
+
+int reassign_irq_vector(int irq, int cpu)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	ret = __reassign_irq_vector(irq, cpu);
+	spin_unlock_irqrestore(&vector_lock, flags);
+	return ret;
 }
 
 /*
@@ -111,18 +342,35 @@
  */
 int create_irq(void)
 {
-	int vector = assign_irq_vector(AUTO_ASSIGN);
+	unsigned long flags;
+	int irq, vector, cpu;
+	cpumask_t domain;
 
-	if (vector >= 0)
-		dynamic_irq_init(vector);
-
-	return vector;
+	irq = vector = -ENOSPC;
+	spin_lock_irqsave(&vector_lock, flags);
+	for_each_online_cpu(cpu) {
+		domain = vector_allocation_domain(cpu);
+		vector = find_unassigned_vector(domain);
+		if (vector >= 0)
+			break;
+	}
+	if (vector < 0)
+		goto out;
+	irq = find_unassigned_irq();
+	if (irq < 0)
+		goto out;
+	BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+	spin_unlock_irqrestore(&vector_lock, flags);
+	if (irq >= 0)
+		dynamic_irq_init(irq);
+	return irq;
 }
 
 void destroy_irq(unsigned int irq)
 {
 	dynamic_irq_cleanup(irq);
-	free_irq_vector(irq);
+	clear_irq_vector(irq);
 }
 
 #ifdef CONFIG_SMP
@@ -301,14 +549,13 @@
 	irq_desc_t *desc;
 	unsigned int irq;
 
-	for (irq = 0; irq < NR_IRQS; ++irq)
-		if (irq_to_vector(irq) == vec) {
-			desc = irq_desc + irq;
-			desc->status |= IRQ_PER_CPU;
-			desc->chip = &irq_type_ia64_lsapic;
-			if (action)
-				setup_irq(irq, action);
-		}
+	irq = vec;
+	BUG_ON(bind_irq_vector(irq, vec, CPU_MASK_ALL));
+	desc = irq_desc + irq;
+	desc->status |= IRQ_PER_CPU;
+	desc->chip = &irq_type_ia64_lsapic;
+	if (action)
+		setup_irq(irq, action);
 }
 
 void __init
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index c81080d..2fdbd5c 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -13,6 +13,7 @@
 
 #define MSI_DATA_VECTOR_SHIFT		0
 #define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+#define MSI_DATA_VECTOR_MASK		0xffffff00
 
 #define MSI_DATA_DELIVERY_SHIFT		8
 #define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
@@ -50,17 +51,29 @@
 static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 {
 	struct msi_msg msg;
-	u32 addr;
+	u32 addr, data;
+	int cpu = first_cpu(cpu_mask);
+
+	if (!cpu_online(cpu))
+		return;
+
+	if (reassign_irq_vector(irq, cpu))
+		return;
 
 	read_msi_msg(irq, &msg);
 
 	addr = msg.address_lo;
 	addr &= MSI_ADDR_DESTID_MASK;
-	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu));
 	msg.address_lo = addr;
 
+	data = msg.data;
+	data &= MSI_DATA_VECTOR_MASK;
+	data |= MSI_DATA_VECTOR(irq_to_vector(irq));
+	msg.data = data;
+
 	write_msi_msg(irq, &msg);
-	irq_desc[irq].affinity = cpu_mask;
+	irq_desc[irq].affinity = cpumask_of_cpu(cpu);
 }
 #endif /* CONFIG_SMP */
 
@@ -69,13 +82,15 @@
 	struct msi_msg	msg;
 	unsigned long	dest_phys_id;
 	int	irq, vector;
+	cpumask_t mask;
 
 	irq = create_irq();
 	if (irq < 0)
 		return irq;
 
 	set_irq_msi(irq, desc);
-	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+	cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+	dest_phys_id = cpu_physical_id(first_cpu(mask));
 	vector = irq_to_vector(irq);
 
 	msg.address_hi = 0;
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 3c9d8e6..9f5c90b 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -395,9 +395,13 @@
 	fix_b0_for_bsp();
 
 	lock_ipi_calllock();
+	spin_lock(&vector_lock);
+	/* Setup the per cpu irq handling data structures */
+	__setup_vector_irq(cpuid);
 	cpu_set(cpuid, cpu_online_map);
 	unlock_ipi_calllock();
 	per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+	spin_unlock(&vector_lock);
 
 	smp_setup_percpu_timer();
 
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 3486fe7..627785c 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/efi.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 
 #include <asm/machvec.h>
 #include <asm/delay.h>
@@ -28,6 +29,16 @@
 #include <asm/sections.h>
 #include <asm/system.h>
 
+#include "fsyscall_gtod_data.h"
+
+static cycle_t itc_get_cycles(void);
+
+struct fsyscall_gtod_data_t fsyscall_gtod_data = {
+	.lock = SEQLOCK_UNLOCKED,
+};
+
+struct itc_jitter_data_t itc_jitter_data;
+
 volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
 
 #ifdef CONFIG_IA64_DEBUG_IRQ
@@ -37,11 +48,16 @@
 
 #endif
 
-static struct time_interpolator itc_interpolator = {
-	.shift = 16,
-	.mask = 0xffffffffffffffffLL,
-	.source = TIME_SOURCE_CPU
+static struct clocksource clocksource_itc = {
+        .name           = "itc",
+        .rating         = 350,
+        .read           = itc_get_cycles,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
+static struct clocksource *itc_clocksource;
 
 static irqreturn_t
 timer_interrupt (int irq, void *dev_id)
@@ -210,8 +226,6 @@
 					+ itc_freq/2)/itc_freq;
 
 	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
-		itc_interpolator.frequency = local_cpu_data->itc_freq;
-		itc_interpolator.drift = itc_drift;
 #ifdef CONFIG_SMP
 		/* On IA64 in an SMP configuration ITCs are never accurately synchronized.
 		 * Jitter compensation requires a cmpxchg which may limit
@@ -223,15 +237,50 @@
 		 * even going backward) if the ITC offsets between the individual CPUs
 		 * are too large.
 		 */
-		if (!nojitter) itc_interpolator.jitter = 1;
+		if (!nojitter)
+			itc_jitter_data.itc_jitter = 1;
 #endif
-		register_time_interpolator(&itc_interpolator);
 	}
 
 	/* Setup the CPU local timer tick */
 	ia64_cpu_local_tick();
+
+	if (!itc_clocksource) {
+		/* Sort out mult/shift values: */
+		clocksource_itc.mult =
+			clocksource_hz2mult(local_cpu_data->itc_freq,
+						clocksource_itc.shift);
+		clocksource_register(&clocksource_itc);
+		itc_clocksource = &clocksource_itc;
+	}
 }
 
+static cycle_t itc_get_cycles()
+{
+	u64 lcycle, now, ret;
+
+	if (!itc_jitter_data.itc_jitter)
+		return get_cycles();
+
+	lcycle = itc_jitter_data.itc_lastcycle;
+	now = get_cycles();
+	if (lcycle && time_after(lcycle, now))
+		return lcycle;
+
+	/*
+	 * Keep track of the last timer value returned.
+	 * In an SMP environment, you could lose out in contention of
+	 * cmpxchg. If so, your cmpxchg returns new value which the
+	 * winner of contention updated to. Use the new value instead.
+	 */
+	ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
+	if (unlikely(ret != lcycle))
+		return ret;
+
+	return now;
+}
+
+
 static struct irqaction timer_irqaction = {
 	.handler =	timer_interrupt,
 	.flags =	IRQF_DISABLED | IRQF_IRQPOLL,
@@ -307,3 +356,34 @@
 	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
 		ia64_printk_clock = ia64_itc_printk_clock;
 }
+
+void update_vsyscall(struct timespec *wall, struct clocksource *c)
+{
+        unsigned long flags;
+
+        write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
+
+        /* copy fsyscall clock data */
+        fsyscall_gtod_data.clk_mask = c->mask;
+        fsyscall_gtod_data.clk_mult = c->mult;
+        fsyscall_gtod_data.clk_shift = c->shift;
+        fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
+        fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
+
+	/* copy kernel time structures */
+        fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
+        fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
+        fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+							+ wall->tv_sec;
+        fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+							+ wall->tv_nsec;
+
+	/* normalize */
+	while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
+		fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
+		fsyscall_gtod_data.monotonic_time.tv_sec++;
+	}
+
+        write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
+}
+
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
index 56a88b6..19e25d2 100644
--- a/arch/ia64/sn/kernel/sn2/timer.c
+++ b/arch/ia64/sn/kernel/sn2/timer.c
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
+#include <linux/clocksource.h>
 
 #include <asm/hw_irq.h>
 #include <asm/system.h>
@@ -22,11 +23,21 @@
 
 extern unsigned long sn_rtc_cycles_per_second;
 
-static struct time_interpolator sn2_interpolator = {
-	.drift = -1,
-	.shift = 10,
-	.mask = (1LL << 55) - 1,
-	.source = TIME_SOURCE_MMIO64
+static void __iomem *sn2_mc;
+
+static cycle_t read_sn2(void)
+{
+	return (cycle_t)readq(sn2_mc);
+}
+
+static struct clocksource clocksource_sn2 = {
+        .name           = "sn2_rtc",
+        .rating         = 300,
+        .read           = read_sn2,
+        .mask           = (1LL << 55) - 1,
+        .mult           = 0,
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 /*
@@ -47,9 +58,11 @@
 
 void __init sn_timer_init(void)
 {
-	sn2_interpolator.frequency = sn_rtc_cycles_per_second;
-	sn2_interpolator.addr = RTC_COUNTER_ADDR;
-	register_time_interpolator(&sn2_interpolator);
+	sn2_mc = RTC_COUNTER_ADDR;
+	clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
+	clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+							clocksource_sn2.shift);
+	clocksource_register(&clocksource_sn2);
 
 	ia64_udelay = &ia64_sn_udelay;
 }
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index a86e2e9..20a9c08 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -37,6 +37,10 @@
 	bool
 	default y
 
+config GENERIC_IOMAP
+	bool
+	default y
+
 config ARCH_MAY_HAVE_PC_FDC
 	bool
 	depends on Q40 || (BROKEN && SUN3X)
@@ -45,6 +49,9 @@
 config NO_IOPORT
 	def_bool y
 
+config NO_DMA
+	def_bool SUN3
+
 mainmenu "Linux/68k Kernel Configuration"
 
 source "init/Kconfig"
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index cb8e760..78df98f 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -148,8 +148,8 @@
     }
 }
 
-void config_apollo(void) {
-
+void __init config_apollo(void)
+{
 	int i;
 
 	dn_setup_model();
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 13bd41be..5d47f3a 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -37,7 +37,7 @@
 };
 
 
-void dn_init_IRQ(void)
+void __init dn_init_IRQ(void)
 {
 	m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
 	m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 1c29603..2b5f647 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -13,6 +13,7 @@
  * enhanced by Bjoern Brauel and Roman Hodek
  */
 
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -42,6 +43,9 @@
 void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
 /* Hook for mouse inputdev  driver */
 void (*atari_input_mouse_interrupt_hook) (char *);
+EXPORT_SYMBOL(atari_mouse_interrupt_hook);
+EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
+EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
 
 /* variables for IKBD self test: */
 
@@ -429,6 +433,7 @@
 
 	ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_rel_pos);
 
 /* Set absolute mouse position reporting */
 void ikbd_mouse_abs_pos(int xmax, int ymax)
@@ -453,6 +458,7 @@
 
 	ikbd_write(cmd, 3);
 }
+EXPORT_SYMBOL(ikbd_mouse_thresh);
 
 /* Set mouse scale */
 void ikbd_mouse_scale(int x, int y)
@@ -495,6 +501,7 @@
 
 	ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_y0_top);
 
 /* Resume */
 void ikbd_resume(void)
@@ -511,6 +518,7 @@
 
 	ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_disable);
 
 /* Pause output */
 void ikbd_pause(void)
@@ -696,7 +704,6 @@
 	return 0;
 }
 
-
 int atari_kbdrate(struct kbd_repeat *k)
 {
 	if (k->delay > 0) {
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 896ae3d..9433a88 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -97,7 +97,7 @@
  * This function is called during kernel startup to initialize
  * the bvme6000 IRQ handling routines.
  */
-static void bvme6000_init_IRQ(void)
+static void __init bvme6000_init_IRQ(void)
 {
 	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 05741f2..faa6764 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -577,7 +577,7 @@
 #endif
 .endm
 
-.text
+.section ".text.head","ax"
 ENTRY(_stext)
 /*
  * Version numbers of the bootinfo interface
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 215c7bd..7e6d5fb 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -58,6 +58,7 @@
 extern unsigned long availmem;
 
 int m68k_num_memory;
+EXPORT_SYMBOL(m68k_num_memory);
 int m68k_realnum_memory;
 EXPORT_SYMBOL(m68k_realnum_memory);
 unsigned long m68k_memoffset;
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
index 4b5f050..aad0159 100644
--- a/arch/m68k/kernel/sun3-head.S
+++ b/arch/m68k/kernel/sun3-head.S
@@ -29,7 +29,7 @@
 .globl kernel_pg_dir
 .equ    kernel_pg_dir,kernel_pmd_table
 
-	.section .head
+	.section .text.head
 ENTRY(_stext)
 ENTRY(_start)
 
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 4c065f9..7db4159 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -72,7 +72,7 @@
 	return IRQ_HANDLED;
 }
 
-void time_init(void)
+void __init time_init(void)
 {
 	struct rtc_time time;
 
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 40f02b1..c422457 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -11,6 +11,7 @@
   . = 0x1000;
   _text = .;			/* Text and read-only data */
   .text : {
+	*(.text.head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index f06425b..4adffef 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -11,7 +11,7 @@
   . = 0xE002000;
   _text = .;			/* Text and read-only data */
   .text : {
-	*(.head)
+	*(.text.head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 5fd4132..8547dbc 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -49,6 +49,7 @@
 int mac_bisize = sizeof mac_bi_data;
 
 struct mac_hw_present mac_hw_present;
+EXPORT_SYMBOL(mac_hw_present);
 
 /* New m68k bootinfo stuff and videobase */
 
@@ -84,7 +85,7 @@
 
 static void mac_get_model(char *str);
 
-static void mac_sched_init(irq_handler_t vector)
+static void __init mac_sched_init(irq_handler_t vector)
 {
 	via_init_clock(vector);
 }
@@ -769,7 +770,7 @@
 	}
 };
 
-void mac_identify(void)
+void __init mac_identify(void)
 {
 	struct mac_model *m;
 
@@ -846,7 +847,7 @@
 	baboon_init();
 }
 
-void mac_report_hardware(void)
+void __init mac_report_hardware(void)
 {
 	printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 0fc72d8..ecddac4 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -114,6 +114,7 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -224,7 +225,7 @@
 	.disable	= mac_disable_irq,
 };
 
-void mac_init_IRQ(void)
+void __init mac_init_IRQ(void)
 {
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Setting things up...\n");
@@ -391,6 +392,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(mac_irq_pending);
 
 static int num_debug[8];
 
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index f1de19e..f42caa7 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -44,7 +44,7 @@
 EXPORT_SYMBOL(pg_data_table);
 #endif
 
-void m68k_setup_node(int node)
+void __init m68k_setup_node(int node)
 {
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
 	struct mem_info *info = m68k_memory + node;
diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c
index 1af24cb..3dc41158 100644
--- a/arch/m68k/mm/sun3kmap.c
+++ b/arch/m68k/mm/sun3kmap.c
@@ -105,6 +105,7 @@
 	return (void __iomem *)ret;
 
 }
+EXPORT_SYMBOL(sun3_ioremap);
 
 
 void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
@@ -157,3 +158,4 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(sun3_map_test);
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 4a7df9c..92fe507 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -89,7 +89,7 @@
  * the mvme147 IRQ handling routines.
  */
 
-void mvme147_init_IRQ(void)
+void __init mvme147_init_IRQ(void)
 {
 	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index c829ebb..daa7851 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -119,7 +119,7 @@
  * that the base vectors for the VMEChip2 and PCCChip2 are valid.
  */
 
-static void mvme16x_init_IRQ (void)
+static void __init mvme16x_init_IRQ (void)
 {
 	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 2fb25ae..ad3ed1f 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -79,7 +79,7 @@
 
 static int disabled;
 
-void q40_init_IRQ(void)
+void __init q40_init_IRQ(void)
 {
 	m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
 
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index 50df34b..cf93481 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -97,7 +97,7 @@
 	.disable	= sun3_disable_irq,
 };
 
-void sun3_init_IRQ(void)
+void __init sun3_init_IRQ(void)
 {
 	*sun3_intreg = 1;
 
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
index 48f8eb7..a7b7e81 100644
--- a/arch/m68k/sun3x/prom.c
+++ b/arch/m68k/sun3x/prom.c
@@ -92,7 +92,7 @@
 	.index	= -1,
 };
 
-void sun3x_prom_init(void)
+void __init sun3x_prom_init(void)
 {
 	/* Read the vector table */
 
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 80f4e9d..2203f69 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -231,32 +231,33 @@
 /*
  *	Get CPU information for use by the procfs.
  */
-
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-    char *cpu, *mmu, *fpu;
-    u_long clockfreq;
+	char *cpu, *mmu, *fpu;
+	u_long clockfreq;
 
-    cpu = CPU;
-    mmu = "none";
-    fpu = "none";
+	cpu = CPU;
+	mmu = "none";
+	fpu = "none";
 
 #ifdef CONFIG_COLDFIRE
-    clockfreq = (loops_per_jiffy*HZ)*3;
+	clockfreq = (loops_per_jiffy * HZ) * 3;
 #else
-    clockfreq = (loops_per_jiffy*HZ)*16;
+	clockfreq = (loops_per_jiffy * HZ) * 16;
 #endif
 
-    seq_printf(m, "CPU:\t\t%s\n"
-		   "MMU:\t\t%s\n"
-		   "FPU:\t\t%s\n"
-		   "Clocking:\t%lu.%1luMHz\n"
-		   "BogoMips:\t%lu.%02lu\n"
-		   "Calibration:\t%lu loops\n",
-		   cpu, mmu, fpu,
-		   clockfreq/1000000,(clockfreq/100000)%10,
-		   (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
-		   (loops_per_jiffy*HZ));
+	seq_printf(m, "CPU:\t\t%s\n"
+		      "MMU:\t\t%s\n"
+		      "FPU:\t\t%s\n"
+		      "Clocking:\t%lu.%1luMHz\n"
+		      "BogoMips:\t%lu.%02lu\n"
+		      "Calibration:\t%lu loops\n",
+		      cpu, mmu, fpu,
+		      clockfreq / 1000000,
+		      (clockfreq / 100000) % 10,
+		      (loops_per_jiffy * HZ) / 500000,
+		      ((loops_per_jiffy * HZ) / 5000) % 100,
+		      (loops_per_jiffy * HZ));
 
 	return 0;
 }
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5c863bc..1e3aecc 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1190,8 +1190,19 @@
 config SYS_HAS_CPU_SB1
 	bool
 
+#
+# CPU may reorder R->R, R->W, W->R, W->W
+# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+#
 config WEAK_ORDERING
 	bool
+
+#
+# CPU may reorder reads and writes beyond LL/SC
+# CPU may reorder R->LL, R->LL, W->LL, W->LL, R->SC, R->SC, W->SC, W->SC
+#
+config WEAK_REORDERING_BEYOND_LLSC
+	bool
 endmenu
 
 #
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index c6b8b07..06448a9 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -75,6 +75,27 @@
 	local_irq_enable();
 }
 
+/*
+ * The RM7000 variant has to handle erratum 38.  The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+	local_irq_disable();
+	if (!need_resched())
+		__asm__(
+		"	.set	push					\n"
+		"	.set	mips3					\n"
+		"	.set	noat					\n"
+		"	mfc0	$1, $12					\n"
+		"	sync						\n"
+		"	mtc0	$1, $12		# stalls until W stage	\n"
+		"	wait						\n"
+		"	mtc0	$1, $12		# stalls until W stage	\n"
+		"	.set	pop					\n");
+	local_irq_enable();
+}
+
 /* The Au1xxx wait is available only if using 32khz counter or
  * external timer source, but specifically not CP0 Counter. */
 int allow_au1k_wait;
@@ -132,7 +153,6 @@
 	case CPU_R4700:
 	case CPU_R5000:
 	case CPU_NEVADA:
-	case CPU_RM7000:
 	case CPU_4KC:
 	case CPU_4KEC:
 	case CPU_4KSC:
@@ -142,6 +162,10 @@
 		cpu_wait = r4k_wait;
 		break;
 
+	case CPU_RM7000:
+		cpu_wait = rm7k_wait_irqoff;
+		break;
+
 	case CPU_24K:
 	case CPU_34K:
 		cpu_wait = r4k_wait;
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 8f4cf27..bd05f5a 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,7 +25,9 @@
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
+#include <linux/random.h>
 
+#include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
@@ -460,3 +462,15 @@
 out:
 	return pc;
 }
+
+/*
+ * Don't forget that the stack pointer must be aligned on a 8 bytes
+ * boundary for 32-bits ABI and 16 bytes for 64-bits ABI.
+ */
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+		sp -= get_random_int() & ~PAGE_MASK;
+
+	return sp & ALMASK;
+}
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d860b64..853c282 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -92,6 +92,9 @@
 config PPC_OF
 	def_bool y
 
+config OF
+	def_bool y
+
 config PPC_UDBG_16550
 	bool
 	default n
diff --git a/arch/powerpc/boot/ps3-head.S b/arch/powerpc/boot/ps3-head.S
index 1a6d64a..a55c273 100644
--- a/arch/powerpc/boot/ps3-head.S
+++ b/arch/powerpc/boot/ps3-head.S
@@ -20,6 +20,8 @@
 
 #include "ppc_asm.h"
 
+	.machine "ppc64"
+
 	.text
 
 /*
diff --git a/arch/powerpc/boot/ps3-hvcall.S b/arch/powerpc/boot/ps3-hvcall.S
index c8b7df3..585965f 100644
--- a/arch/powerpc/boot/ps3-hvcall.S
+++ b/arch/powerpc/boot/ps3-hvcall.S
@@ -20,6 +20,8 @@
 
 #include "ppc_asm.h"
 
+	.machine "ppc64"
+
 /*
  * The PS3 hypervisor uses a 64 bit "C" language calling convention.
  * The routines here marshal arguments between the 32 bit wrapper
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index 74f83f4..d9ac24e 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1455,7 +1455,8 @@
 # Instrumentation Support
 #
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_OPROFILE_CELL=y
 # CONFIG_KPROBES is not set
 
 #
diff --git a/arch/powerpc/configs/prpmc2800_defconfig b/arch/powerpc/configs/prpmc2800_defconfig
index fb504a7..858f865 100644
--- a/arch/powerpc/configs/prpmc2800_defconfig
+++ b/arch/powerpc/configs/prpmc2800_defconfig
@@ -48,7 +48,7 @@
 # CONFIG_PPC_MM_SLICES is not set
 # CONFIG_SMP is not set
 CONFIG_NOT_COHERENT_CACHE=y
-CONFIG_CONFIG_CHECK_CACHE_COHERENCY=y
+CONFIG_CHECK_CACHE_COHERENCY=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index d3f2080..37658ea 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -219,6 +219,72 @@
 	cpus_in_sr = CPU_MASK_NONE;
 }
 #endif
+#ifdef CONFIG_SPU_BASE
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+struct crash_spu_info {
+	struct spu *spu;
+	u32 saved_spu_runcntl_RW;
+	u32 saved_spu_status_R;
+	u32 saved_spu_npc_RW;
+	u64 saved_mfc_sr1_RW;
+	u64 saved_mfc_dar;
+	u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS	16	/* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+	struct spu *spu;
+	int i;
+	u64 tmp;
+
+	for (i = 0; i < CRASH_NUM_SPUS; i++) {
+		if (!crash_spu_info[i].spu)
+			continue;
+
+		spu = crash_spu_info[i].spu;
+
+		crash_spu_info[i].saved_spu_runcntl_RW =
+			in_be32(&spu->problem->spu_runcntl_RW);
+		crash_spu_info[i].saved_spu_status_R =
+			in_be32(&spu->problem->spu_status_R);
+		crash_spu_info[i].saved_spu_npc_RW =
+			in_be32(&spu->problem->spu_npc_RW);
+
+		crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
+		crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
+		tmp = spu_mfc_sr1_get(spu);
+		crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+		tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+		spu_mfc_sr1_set(spu, tmp);
+
+		__delay(200);
+	}
+}
+
+void crash_register_spus(struct list_head *list)
+{
+	struct spu *spu;
+
+	list_for_each_entry(spu, list, full_list) {
+		if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+			continue;
+
+		crash_spu_info[spu->number].spu = spu;
+	}
+}
+
+#else
+static inline void crash_kexec_stop_spus(void)
+{
+}
+#endif /* CONFIG_SPU_BASE */
 
 void default_machine_crash_shutdown(struct pt_regs *regs)
 {
@@ -254,6 +320,7 @@
 	crash_save_cpu(regs, crashing_cpu);
 	crash_kexec_prepare_cpus(crashing_cpu);
 	cpu_set(crashing_cpu, cpus_in_crash);
+	crash_kexec_stop_spus();
 	if (ppc_md.kexec_cpu_down)
 		ppc_md.kexec_cpu_down(1, 0);
 }
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index a464d67..89b911e 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -1,5 +1,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -8,118 +9,6 @@
 #include <asm/errno.h>
 #include <asm/of_device.h>
 
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @ids: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
-					 const struct device_node *node)
-{
-	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-		int match = 1;
-		if (matches->name[0])
-			match &= node->name
-				&& !strcmp(matches->name, node->name);
-		if (matches->type[0])
-			match &= node->type
-				&& !strcmp(matches->type, node->type);
-		if (matches->compatible[0])
-			match &= of_device_is_compatible(node,
-						      matches->compatible);
-		if (match)
-			return matches;
-		matches++;
-	}
-	return NULL;
-}
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-					const struct of_device *dev)
-{
-	if (!dev->node)
-		return NULL;
-	return of_match_node(matches, dev->node);
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-	struct device *tmp;
-
-	if (!dev)
-		return NULL;
-	tmp = get_device(&dev->dev);
-	if (tmp)
-		return to_of_device(tmp);
-	else
-		return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-	if (dev)
-		put_device(&dev->dev);
-}
-
-static ssize_t dev_show_devspec(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	struct of_device *ofdev;
-
-	ofdev = to_of_device(dev);
-	return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-	struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-	of_node_put(ofdev->node);
-	kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-	int rc;
-
-	BUG_ON(ofdev->node == NULL);
-
-	rc = device_register(&ofdev->dev);
-	if (rc)
-		return rc;
-
-	return device_create_file(&ofdev->dev, &dev_attr_devspec);
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-	device_remove_file(&ofdev->dev, &dev_attr_devspec);
-
-	device_unregister(&ofdev->dev);
-}
-
-
 ssize_t of_device_get_modalias(struct of_device *ofdev,
 				char *str, ssize_t len)
 {
@@ -229,14 +118,5 @@
 
 	return 0;
 }
-
-
-EXPORT_SYMBOL(of_match_node);
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_release_dev);
 EXPORT_SYMBOL(of_device_uevent);
 EXPORT_SYMBOL(of_device_get_modalias);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 8ded4e7..f70e787 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -55,94 +55,14 @@
 
 static atomic_t bus_no_reg_magic;
 
-/*
- *
- * OF platform device type definition & base infrastructure
- *
- */
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_device_id * matches = of_drv->match_table;
-
-	if (!matches)
-		return 0;
-
-	return of_match_device(matches, of_dev) != NULL;
-}
-
-static int of_platform_device_probe(struct device *dev)
-{
-	int error = -ENODEV;
-	struct of_platform_driver *drv;
-	struct of_device *of_dev;
-	const struct of_device_id *match;
-
-	drv = to_of_platform_driver(dev->driver);
-	of_dev = to_of_device(dev);
-
-	if (!drv->probe)
-		return error;
-
-	of_dev_get(of_dev);
-
-	match = of_match_device(drv->match_table, of_dev);
-	if (match)
-		error = drv->probe(of_dev, match);
-	if (error)
-		of_dev_put(of_dev);
-
-	return error;
-}
-
-static int of_platform_device_remove(struct device *dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-	if (dev->driver && drv->remove)
-		drv->remove(of_dev);
-	return 0;
-}
-
-static int of_platform_device_suspend(struct device *dev, pm_message_t state)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->suspend)
-		error = drv->suspend(of_dev, state);
-	return error;
-}
-
-static int of_platform_device_resume(struct device * dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->resume)
-		error = drv->resume(of_dev);
-	return error;
-}
-
 struct bus_type of_platform_bus_type = {
-       .name	= "of_platform",
-       .match	= of_platform_bus_match,
        .uevent	= of_device_uevent,
-       .probe	= of_platform_device_probe,
-       .remove	= of_platform_device_remove,
-       .suspend	= of_platform_device_suspend,
-       .resume	= of_platform_device_resume,
 };
 EXPORT_SYMBOL(of_platform_bus_type);
 
 static int __init of_bus_driver_init(void)
 {
-	return bus_register(&of_platform_bus_type);
+	return of_bus_type_init(&of_platform_bus_type, "of_platform");
 }
 
 postcore_initcall(of_bus_driver_init);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 94b4a02..fe7d125 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -166,7 +166,7 @@
 
 }
 
-char __init *pcibios_setup(char *str)
+char __devinit *pcibios_setup(char *str)
 {
 	return str;
 }
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 37ff99b..a38197b 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -78,12 +78,9 @@
 struct boot_param_header *initial_boot_params;
 #endif
 
-static struct device_node *allnodes = NULL;
+extern struct device_node *allnodes;	/* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
+extern rwlock_t devtree_lock;	/* temporary while merging */
 
 /* export that to outside world */
 struct device_node *of_chosen;
@@ -1056,60 +1053,6 @@
 	DBG(" <- early_init_devtree()\n");
 }
 
-int of_n_addr_cells(struct device_node* np)
-{
-	const int *ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#address-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #address-cells property for the root node, default to 1 */
-	return 1;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node* np)
-{
-	const int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#size-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #size-cells property for the root node, default to 1 */
-	return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int of_device_is_compatible(const struct device_node *device,
-		const char *compat)
-{
-	const char* cp;
-	int cplen, l;
-
-	cp = of_get_property(device, "compatible", &cplen);
-	if (cp == NULL)
-		return 0;
-	while (cplen > 0) {
-		if (strncasecmp(cp, compat, strlen(compat)) == 0)
-			return 1;
-		l = strlen(cp) + 1;
-		cp += l;
-		cplen -= l;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
 
 /**
  * Indicates whether the root node has a given value in its
@@ -1141,119 +1084,6 @@
  *******/
 
 /**
- *	of_find_node_by_name - Find a node by its "name" property
- *	@from:	The node to start searching from or NULL, the node
- *		you pass will not be searched, only the next one
- *		will; typically, you pass what the previous call
- *		returned. of_node_put() will be called on it
- *	@name:	The name string to match against
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name)
-{
-	struct device_node *np;
-
-	read_lock(&devtree_lock);
-	np = from ? from->allnext : allnodes;
-	for (; np != NULL; np = np->allnext)
-		if (np->name != NULL && strcasecmp(np->name, name) == 0
-		    && of_node_get(np))
-			break;
-	of_node_put(from);
-	read_unlock(&devtree_lock);
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-/**
- *	of_find_node_by_type - Find a node by its "device_type" property
- *	@from:	The node to start searching from, or NULL to start searching
- *		the entire device tree. The node you pass will not be
- *		searched, only the next one will; typically, you pass
- *		what the previous call returned. of_node_put() will be
- *		called on from for you.
- *	@type:	The type string to match against
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type)
-{
-	struct device_node *np;
-
-	read_lock(&devtree_lock);
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext)
-		if (np->type != 0 && strcasecmp(np->type, type) == 0
-		    && of_node_get(np))
-			break;
-	of_node_put(from);
-	read_unlock(&devtree_lock);
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-/**
- *	of_find_compatible_node - Find a node based on type and one of the
- *                                tokens in its "compatible" property
- *	@from:		The node to start searching from or NULL, the node
- *			you pass will not be searched, only the next one
- *			will; typically, you pass what the previous call
- *			returned. of_node_put() will be called on it
- *	@type:		The type string to match "device_type" or NULL to ignore
- *	@compatible:	The string to match to one of the tokens in the device
- *			"compatible" list.
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compatible)
-{
-	struct device_node *np;
-
-	read_lock(&devtree_lock);
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-			continue;
-		if (of_device_is_compatible(np, compatible) && of_node_get(np))
-			break;
-	}
-	of_node_put(from);
-	read_unlock(&devtree_lock);
-	return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-/**
- *	of_find_node_by_path - Find a node matching a full OF path
- *	@path:	The full path to match
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_path(const char *path)
-{
-	struct device_node *np = allnodes;
-
-	read_lock(&devtree_lock);
-	for (; np != 0; np = np->allnext) {
-		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
-		    && of_node_get(np))
-			break;
-	}
-	read_unlock(&devtree_lock);
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
-
-/**
  *	of_find_node_by_phandle - Find a node given a phandle
  *	@handle:	phandle of the node to find
  *
@@ -1298,51 +1128,6 @@
 EXPORT_SYMBOL(of_find_all_nodes);
 
 /**
- *	of_get_parent - Get a node's parent if any
- *	@node:	Node to get parent
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_get_parent(const struct device_node *node)
-{
-	struct device_node *np;
-
-	if (!node)
-		return NULL;
-
-	read_lock(&devtree_lock);
-	np = of_node_get(node->parent);
-	read_unlock(&devtree_lock);
-	return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-/**
- *	of_get_next_child - Iterate a node childs
- *	@node:	parent node
- *	@prev:	previous child of the parent node, or NULL to get first
- *
- *	Returns a node pointer with refcount incremented, use
- *	of_node_put() on it when done.
- */
-struct device_node *of_get_next_child(const struct device_node *node,
-	struct device_node *prev)
-{
-	struct device_node *next;
-
-	read_lock(&devtree_lock);
-	next = prev ? prev->sibling : node->child;
-	for (; next != 0; next = next->sibling)
-		if (of_node_get(next))
-			break;
-	of_node_put(prev);
-	read_unlock(&devtree_lock);
-	return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-/**
  *	of_node_get - Increment refcount of a node
  *	@node:	Node to inc refcount, NULL is supported to
  *		simplify writing of callers
@@ -1433,7 +1218,7 @@
  * a reference to the node.  The memory associated with the node
  * is not freed until its refcount goes to zero.
  */
-void of_detach_node(const struct device_node *np)
+void of_detach_node(struct device_node *np)
 {
 	struct device_node *parent;
 
@@ -1543,37 +1328,6 @@
 __initcall(prom_reconfig_setup);
 #endif
 
-struct property *of_find_property(const struct device_node *np,
-				  const char *name,
-				  int *lenp)
-{
-	struct property *pp;
-
-	read_lock(&devtree_lock);
-	for (pp = np->properties; pp != 0; pp = pp->next)
-		if (strcmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			break;
-		}
-	read_unlock(&devtree_lock);
-
-	return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-			 int *lenp)
-{
-	struct property *pp = of_find_property(np,name,lenp);
-	return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 /*
  * Add a property to a node
  */
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index d577b71..087c92f 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -284,7 +284,7 @@
 			int wait)
 {
 	cpumask_t map = CPU_MASK_NONE;
-	int ret = -EBUSY;
+	int ret = 0;
 
 	if (!cpu_online(cpu))
 		return -EINVAL;
@@ -292,6 +292,11 @@
 	cpu_set(cpu, map);
 	if (cpu != get_cpu())
 		ret = smp_call_function_map(func,info,nonatomic,wait,map);
+	else {
+		local_irq_disable();
+		func(info);
+		local_irq_enable();
+	}
 	put_cpu();
 	return ret;
 }
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index e5df167..727a669 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -122,6 +122,7 @@
 static long timezone_offset;
 
 unsigned long ppc_proc_freq;
+EXPORT_SYMBOL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
 
 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 3767211..ab3546c 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -283,7 +283,13 @@
 		/* protection fault */
 		if (error_code & DSISR_PROTFAULT)
 			goto bad_area;
-		if (!(vma->vm_flags & VM_EXEC))
+		/*
+		 * Allow execution from readable areas if the MMU does not
+		 * provide separate controls over reading and executing.
+		 */
+		if (!(vma->vm_flags & VM_EXEC) &&
+		    (cpu_has_feature(CPU_FTR_NOEXECUTE) ||
+		     !(vma->vm_flags & (VM_READ | VM_WRITE))))
 			goto bad_area;
 #else
 		pte_t *ptep;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 2ce9491..bc7b0ce 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -609,7 +609,7 @@
 	mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
 #endif /* CONFIG_PPC_MM_SLICES */
 
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
 	spu_flush_all_slbs(mm);
 #endif
 }
@@ -744,7 +744,7 @@
 			       "to 4kB pages because of "
 			       "non-cacheable mapping\n");
 			psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
 			spu_flush_all_slbs(mm);
 #endif
 		}
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index 06c7e77..eb4b512 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -26,6 +26,8 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
+#include <linux/pagemap.h>
+
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 
diff --git a/arch/powerpc/oprofile/Kconfig b/arch/powerpc/oprofile/Kconfig
index eb2dece..7089e79 100644
--- a/arch/powerpc/oprofile/Kconfig
+++ b/arch/powerpc/oprofile/Kconfig
@@ -15,3 +15,10 @@
 
 	  If unsure, say N.
 
+config OPROFILE_CELL
+	bool "OProfile for Cell Broadband Engine"
+	depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE = y) || (SPU_FS = m && OPROFILE = m)
+	default y
+	help
+	  Profiling of Cell BE SPUs requires special support enabled
+	  by this option.
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 4b5f952..c5f64c3 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -11,7 +11,9 @@
 		timer_int.o )
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
+oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
+		cell/spu_profiler.o cell/vma_map.o \
+		cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h
new file mode 100644
index 0000000..e5704f0
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/pr_util.h
@@ -0,0 +1,97 @@
+ /*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@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.
+ */
+
+#ifndef PR_UTIL_H
+#define PR_UTIL_H
+
+#include <linux/cpumask.h>
+#include <linux/oprofile.h>
+#include <asm/cell-pmu.h>
+#include <asm/spu.h>
+
+#include "../../platforms/cell/cbe_regs.h"
+
+/* Defines used for sync_start */
+#define SKIP_GENERIC_SYNC 0
+#define SYNC_START_ERROR -1
+#define DO_GENERIC_SYNC 1
+
+struct spu_overlay_info {	/* map of sections within an SPU overlay */
+	unsigned int vma;	/* SPU virtual memory address from elf */
+	unsigned int size;	/* size of section from elf */
+	unsigned int offset;	/* offset of section into elf file */
+	unsigned int buf;
+};
+
+struct vma_to_fileoffset_map {	/* map of sections within an SPU program */
+	struct vma_to_fileoffset_map *next;	/* list pointer */
+	unsigned int vma;	/* SPU virtual memory address from elf */
+	unsigned int size;	/* size of section from elf */
+	unsigned int offset;	/* offset of section into elf file */
+	unsigned int guard_ptr;
+	unsigned int guard_val;
+        /*
+	 * The guard pointer is an entry in the _ovly_buf_table,
+	 * computed using ovly.buf as the index into the table.  Since
+	 * ovly.buf values begin at '1' to reference the first (or 0th)
+	 * entry in the _ovly_buf_table, the computation subtracts 1
+	 * from ovly.buf.
+	 * The guard value is stored in the _ovly_buf_table entry and
+	 * is an index (starting at 1) back to the _ovly_table entry
+	 * that is pointing at this _ovly_buf_table entry.  So, for
+	 * example, for an overlay scenario with one overlay segment
+	 * and two overlay sections:
+	 *      - Section 1 points to the first entry of the
+	 *        _ovly_buf_table, which contains a guard value
+	 *        of '1', referencing the first (index=0) entry of
+	 *        _ovly_table.
+	 *      - Section 2 points to the second entry of the
+	 *        _ovly_buf_table, which contains a guard value
+	 *        of '2', referencing the second (index=1) entry of
+	 *        _ovly_table.
+	 */
+
+};
+
+/* The three functions below are for maintaining and accessing
+ * the vma-to-fileoffset map.
+ */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu,
+					     u64 objectid);
+unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map,
+			    unsigned int vma, const struct spu *aSpu,
+			    int *grd_val);
+void vma_map_free(struct vma_to_fileoffset_map *map);
+
+/*
+ * Entry point for SPU profiling.
+ * cycles_reset is the SPU_CYCLES count value specified by the user.
+ */
+int start_spu_profiling(unsigned int cycles_reset);
+
+void stop_spu_profiling(void);
+
+
+/* add the necessary profiling hooks */
+int spu_sync_start(void);
+
+/* remove the hooks */
+int spu_sync_stop(void);
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+		     int num_samples);
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset);
+
+#endif	  /* PR_UTIL_H */
diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c
new file mode 100644
index 0000000..380d7e2
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/spu_profiler.c
@@ -0,0 +1,221 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Authors: Maynard Johnson <maynardj@us.ibm.com>
+ *	    Carl Love <carll@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/hrtimer.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <asm/cell-pmu.h>
+#include "pr_util.h"
+
+#define TRACE_ARRAY_SIZE 1024
+#define SCALE_SHIFT 14
+
+static u32 *samples;
+
+static int spu_prof_running;
+static unsigned int profiling_interval;
+
+#define NUM_SPU_BITS_TRBUF 16
+#define SPUS_PER_TB_ENTRY   4
+#define SPUS_PER_NODE	     8
+
+#define SPU_PC_MASK	     0xFFFF
+
+static DEFINE_SPINLOCK(sample_array_lock);
+unsigned long sample_array_lock_flags;
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset)
+{
+	unsigned long ns_per_cyc;
+
+	if (!freq_khz)
+		freq_khz = ppc_proc_freq/1000;
+
+	/* To calculate a timeout in nanoseconds, the basic
+	 * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency).
+	 * To avoid floating point math, we use the scale math
+	 * technique as described in linux/jiffies.h.  We use
+	 * a scale factor of SCALE_SHIFT, which provides 4 decimal places
+	 * of precision.  This is close enough for the purpose at hand.
+	 *
+	 * The value of the timeout should be small enough that the hw
+	 * trace buffer will not get more then about 1/3 full for the
+	 * maximum user specified (the LFSR value) hw sampling frequency.
+	 * This is to ensure the trace buffer will never fill even if the
+	 * kernel thread scheduling varies under a heavy system load.
+	 */
+
+	ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz;
+	profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT;
+
+}
+
+/*
+ * Extract SPU PC from trace buffer entry
+ */
+static void spu_pc_extract(int cpu, int entry)
+{
+	/* the trace buffer is 128 bits */
+	u64 trace_buffer[2];
+	u64 spu_mask;
+	int spu;
+
+	spu_mask = SPU_PC_MASK;
+
+	/* Each SPU PC is 16 bits; hence, four spus in each of
+	 * the two 64-bit buffer entries that make up the
+	 * 128-bit trace_buffer entry.	Process two 64-bit values
+	 * simultaneously.
+	 * trace[0] SPU PC contents are: 0 1 2 3
+	 * trace[1] SPU PC contents are: 4 5 6 7
+	 */
+
+	cbe_read_trace_buffer(cpu, trace_buffer);
+
+	for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) {
+		/* spu PC trace entry is upper 16 bits of the
+		 * 18 bit SPU program counter
+		 */
+		samples[spu * TRACE_ARRAY_SIZE + entry]
+			= (spu_mask & trace_buffer[0]) << 2;
+		samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry]
+			= (spu_mask & trace_buffer[1]) << 2;
+
+		trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF;
+		trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF;
+	}
+}
+
+static int cell_spu_pc_collection(int cpu)
+{
+	u32 trace_addr;
+	int entry;
+
+	/* process the collected SPU PC for the node */
+
+	entry = 0;
+
+	trace_addr = cbe_read_pm(cpu, trace_address);
+	while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) {
+		/* there is data in the trace buffer to process */
+		spu_pc_extract(cpu, entry);
+
+		entry++;
+
+		if (entry >= TRACE_ARRAY_SIZE)
+			/* spu_samples is full */
+			break;
+
+		trace_addr = cbe_read_pm(cpu, trace_address);
+	}
+
+	return entry;
+}
+
+
+static enum hrtimer_restart profile_spus(struct hrtimer *timer)
+{
+	ktime_t kt;
+	int cpu, node, k, num_samples, spu_num;
+
+	if (!spu_prof_running)
+		goto stop;
+
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		node = cbe_cpu_to_node(cpu);
+
+		/* There should only be one kernel thread at a time processing
+		 * the samples.	 In the very unlikely case that the processing
+		 * is taking a very long time and multiple kernel threads are
+		 * started to process the samples.  Make sure only one kernel
+		 * thread is working on the samples array at a time.  The
+		 * sample array must be loaded and then processed for a given
+		 * cpu.	 The sample array is not per cpu.
+		 */
+		spin_lock_irqsave(&sample_array_lock,
+				  sample_array_lock_flags);
+		num_samples = cell_spu_pc_collection(cpu);
+
+		if (num_samples == 0) {
+			spin_unlock_irqrestore(&sample_array_lock,
+					       sample_array_lock_flags);
+			continue;
+		}
+
+		for (k = 0; k < SPUS_PER_NODE; k++) {
+			spu_num = k + (node * SPUS_PER_NODE);
+			spu_sync_buffer(spu_num,
+					samples + (k * TRACE_ARRAY_SIZE),
+					num_samples);
+		}
+
+		spin_unlock_irqrestore(&sample_array_lock,
+				       sample_array_lock_flags);
+
+	}
+	smp_wmb();	/* insure spu event buffer updates are written */
+			/* don't want events intermingled... */
+
+	kt = ktime_set(0, profiling_interval);
+	if (!spu_prof_running)
+		goto stop;
+	hrtimer_forward(timer, timer->base->get_time(), kt);
+	return HRTIMER_RESTART;
+
+ stop:
+	printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n");
+	return HRTIMER_NORESTART;
+}
+
+static struct hrtimer timer;
+/*
+ * Entry point for SPU profiling.
+ * NOTE:  SPU profiling is done system-wide, not per-CPU.
+ *
+ * cycles_reset is the count value specified by the user when
+ * setting up OProfile to count SPU_CYCLES.
+ */
+int start_spu_profiling(unsigned int cycles_reset)
+{
+	ktime_t kt;
+
+	pr_debug("timer resolution: %lu\n", TICK_NSEC);
+	kt = ktime_set(0, profiling_interval);
+	hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer.expires = kt;
+	timer.function = profile_spus;
+
+	/* Allocate arrays for collecting SPU PC samples */
+	samples = kzalloc(SPUS_PER_NODE *
+			  TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL);
+
+	if (!samples)
+		return -ENOMEM;
+
+	spu_prof_running = 1;
+	hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+void stop_spu_profiling(void)
+{
+	spu_prof_running = 0;
+	hrtimer_cancel(&timer);
+	kfree(samples);
+	pr_debug("SPU_PROF: stop_spu_profiling issued\n");
+}
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
new file mode 100644
index 0000000..1336657
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -0,0 +1,484 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@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.
+ */
+
+/* The purpose of this file is to handle SPU event task switching
+ * and to record SPU context information into the OProfile
+ * event buffer.
+ *
+ * Additionally, the spu_sync_buffer function is provided as a helper
+ * for recoding actual SPU program counter samples to the event buffer.
+ */
+#include <linux/dcookies.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/oprofile.h>
+#include <linux/spinlock.h>
+#include "pr_util.h"
+
+#define RELEASE_ALL 9999
+
+static DEFINE_SPINLOCK(buffer_lock);
+static DEFINE_SPINLOCK(cache_lock);
+static int num_spu_nodes;
+int spu_prof_num_nodes;
+int last_guard_val[MAX_NUMNODES * 8];
+
+/* Container for caching information about an active SPU task. */
+struct cached_info {
+	struct vma_to_fileoffset_map *map;
+	struct spu *the_spu;	/* needed to access pointer to local_store */
+	struct kref cache_ref;
+};
+
+static struct cached_info *spu_info[MAX_NUMNODES * 8];
+
+static void destroy_cached_info(struct kref *kref)
+{
+	struct cached_info *info;
+
+	info = container_of(kref, struct cached_info, cache_ref);
+	vma_map_free(info->map);
+	kfree(info);
+	module_put(THIS_MODULE);
+}
+
+/* Return the cached_info for the passed SPU number.
+ * ATTENTION:  Callers are responsible for obtaining the
+ *	       cache_lock if needed prior to invoking this function.
+ */
+static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num)
+{
+	struct kref *ref;
+	struct cached_info *ret_info;
+
+	if (spu_num >= num_spu_nodes) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: Invalid index %d into spu info cache\n",
+		       __FUNCTION__, __LINE__, spu_num);
+		ret_info = NULL;
+		goto out;
+	}
+	if (!spu_info[spu_num] && the_spu) {
+		ref = spu_get_profile_private_kref(the_spu->ctx);
+		if (ref) {
+			spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref);
+			kref_get(&spu_info[spu_num]->cache_ref);
+		}
+	}
+
+	ret_info = spu_info[spu_num];
+ out:
+	return ret_info;
+}
+
+
+/* Looks for cached info for the passed spu.  If not found, the
+ * cached info is created for the passed spu.
+ * Returns 0 for success; otherwise, -1 for error.
+ */
+static int
+prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
+{
+	unsigned long flags;
+	struct vma_to_fileoffset_map *new_map;
+	int retval = 0;
+	struct cached_info *info;
+
+	/* We won't bother getting cache_lock here since
+	 * don't do anything with the cached_info that's returned.
+	 */
+	info = get_cached_info(spu, spu->number);
+
+	if (info) {
+		pr_debug("Found cached SPU info.\n");
+		goto out;
+	}
+
+	/* Create cached_info and set spu_info[spu->number] to point to it.
+	 * spu->number is a system-wide value, not a per-node value.
+	 */
+	info = kzalloc(sizeof(struct cached_info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: create vma_map failed\n",
+		       __FUNCTION__, __LINE__);
+		retval = -ENOMEM;
+		goto err_alloc;
+	}
+	new_map = create_vma_map(spu, objectId);
+	if (!new_map) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: create vma_map failed\n",
+		       __FUNCTION__, __LINE__);
+		retval = -ENOMEM;
+		goto err_alloc;
+	}
+
+	pr_debug("Created vma_map\n");
+	info->map = new_map;
+	info->the_spu = spu;
+	kref_init(&info->cache_ref);
+	spin_lock_irqsave(&cache_lock, flags);
+	spu_info[spu->number] = info;
+	/* Increment count before passing off ref to SPUFS. */
+	kref_get(&info->cache_ref);
+
+	/* We increment the module refcount here since SPUFS is
+	 * responsible for the final destruction of the cached_info,
+	 * and it must be able to access the destroy_cached_info()
+	 * function defined in the OProfile module.  We decrement
+	 * the module refcount in destroy_cached_info.
+	 */
+	try_module_get(THIS_MODULE);
+	spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
+				destroy_cached_info);
+	spin_unlock_irqrestore(&cache_lock, flags);
+	goto out;
+
+err_alloc:
+	kfree(info);
+out:
+	return retval;
+}
+
+/*
+ * NOTE:  The caller is responsible for locking the
+ *	  cache_lock prior to calling this function.
+ */
+static int release_cached_info(int spu_index)
+{
+	int index, end;
+
+	if (spu_index == RELEASE_ALL) {
+		end = num_spu_nodes;
+		index = 0;
+	} else {
+		if (spu_index >= num_spu_nodes) {
+			printk(KERN_ERR "SPU_PROF: "
+				"%s, line %d: "
+				"Invalid index %d into spu info cache\n",
+				__FUNCTION__, __LINE__, spu_index);
+			goto out;
+		}
+		end = spu_index + 1;
+		index = spu_index;
+	}
+	for (; index < end; index++) {
+		if (spu_info[index]) {
+			kref_put(&spu_info[index]->cache_ref,
+				 destroy_cached_info);
+			spu_info[index] = NULL;
+		}
+	}
+
+out:
+	return 0;
+}
+
+/* The source code for fast_get_dcookie was "borrowed"
+ * from drivers/oprofile/buffer_sync.c.
+ */
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer).
+ */
+static inline unsigned long fast_get_dcookie(struct dentry *dentry,
+					     struct vfsmount *vfsmnt)
+{
+	unsigned long cookie;
+
+	if (dentry->d_cookie)
+		return (unsigned long)dentry;
+	get_dcookie(dentry, vfsmnt, &cookie);
+	return cookie;
+}
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". Also, determine
+ * the offset for the SPU ELF object.  If computed offset is
+ * non-zero, it implies an embedded SPU object; otherwise, it's a
+ * separate SPU binary, in which case we retrieve it's dcookie.
+ * For the embedded case, we must determine if SPU ELF is embedded
+ * in the executable application or another file (i.e., shared lib).
+ * If embedded in a shared lib, we must get the dcookie and return
+ * that to the caller.
+ */
+static unsigned long
+get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
+			    unsigned long *spu_bin_dcookie,
+			    unsigned long spu_ref)
+{
+	unsigned long app_cookie = 0;
+	unsigned int my_offset = 0;
+	struct file *app = NULL;
+	struct vm_area_struct *vma;
+	struct mm_struct *mm = spu->mm;
+
+	if (!mm)
+		goto out;
+
+	down_read(&mm->mmap_sem);
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!vma->vm_file)
+			continue;
+		if (!(vma->vm_flags & VM_EXECUTABLE))
+			continue;
+		app_cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+					  vma->vm_file->f_vfsmnt);
+		pr_debug("got dcookie for %s\n",
+			 vma->vm_file->f_dentry->d_name.name);
+		app = vma->vm_file;
+		break;
+	}
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
+			continue;
+		my_offset = spu_ref - vma->vm_start;
+		if (!vma->vm_file)
+			goto fail_no_image_cookie;
+
+		pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
+			 my_offset, spu_ref,
+			 vma->vm_file->f_dentry->d_name.name);
+		*offsetp = my_offset;
+		break;
+	}
+
+	*spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry,
+						 vma->vm_file->f_vfsmnt);
+	pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+
+	up_read(&mm->mmap_sem);
+
+out:
+	return app_cookie;
+
+fail_no_image_cookie:
+	up_read(&mm->mmap_sem);
+
+	printk(KERN_ERR "SPU_PROF: "
+		"%s, line %d: Cannot find dcookie for SPU binary\n",
+		__FUNCTION__, __LINE__);
+	goto out;
+}
+
+
+
+/* This function finds or creates cached context information for the
+ * passed SPU and records SPU context information into the OProfile
+ * event buffer.
+ */
+static int process_context_switch(struct spu *spu, unsigned long objectId)
+{
+	unsigned long flags;
+	int retval;
+	unsigned int offset = 0;
+	unsigned long spu_cookie = 0, app_dcookie;
+
+	retval = prepare_cached_spu_info(spu, objectId);
+	if (retval)
+		goto out;
+
+	/* Get dcookie first because a mutex_lock is taken in that
+	 * code path, so interrupts must not be disabled.
+	 */
+	app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId);
+	if (!app_dcookie || !spu_cookie) {
+		retval  = -ENOENT;
+		goto out;
+	}
+
+	/* Record context info in event buffer */
+	spin_lock_irqsave(&buffer_lock, flags);
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(SPU_CTX_SWITCH_CODE);
+	add_event_entry(spu->number);
+	add_event_entry(spu->pid);
+	add_event_entry(spu->tgid);
+	add_event_entry(app_dcookie);
+	add_event_entry(spu_cookie);
+	add_event_entry(offset);
+	spin_unlock_irqrestore(&buffer_lock, flags);
+	smp_wmb();	/* insure spu event buffer updates are written */
+			/* don't want entries intermingled... */
+out:
+	return retval;
+}
+
+/*
+ * This function is invoked on either a bind_context or unbind_context.
+ * If called for an unbind_context, the val arg is 0; otherwise,
+ * it is the object-id value for the spu context.
+ * The data arg is of type 'struct spu *'.
+ */
+static int spu_active_notify(struct notifier_block *self, unsigned long val,
+				void *data)
+{
+	int retval;
+	unsigned long flags;
+	struct spu *the_spu = data;
+
+	pr_debug("SPU event notification arrived\n");
+	if (!val) {
+		spin_lock_irqsave(&cache_lock, flags);
+		retval = release_cached_info(the_spu->number);
+		spin_unlock_irqrestore(&cache_lock, flags);
+	} else {
+		retval = process_context_switch(the_spu, val);
+	}
+	return retval;
+}
+
+static struct notifier_block spu_active = {
+	.notifier_call = spu_active_notify,
+};
+
+static int number_of_online_nodes(void)
+{
+        u32 cpu; u32 tmp;
+        int nodes = 0;
+        for_each_online_cpu(cpu) {
+                tmp = cbe_cpu_to_node(cpu) + 1;
+                if (tmp > nodes)
+                        nodes++;
+        }
+        return nodes;
+}
+
+/* The main purpose of this function is to synchronize
+ * OProfile with SPUFS by registering to be notified of
+ * SPU task switches.
+ *
+ * NOTE: When profiling SPUs, we must ensure that only
+ * spu_sync_start is invoked and not the generic sync_start
+ * in drivers/oprofile/oprof.c.	 A return value of
+ * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
+ * accomplish this.
+ */
+int spu_sync_start(void)
+{
+	int k;
+	int ret = SKIP_GENERIC_SYNC;
+	int register_ret;
+	unsigned long flags = 0;
+
+	spu_prof_num_nodes = number_of_online_nodes();
+	num_spu_nodes = spu_prof_num_nodes * 8;
+
+	spin_lock_irqsave(&buffer_lock, flags);
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(SPU_PROFILING_CODE);
+	add_event_entry(num_spu_nodes);
+	spin_unlock_irqrestore(&buffer_lock, flags);
+
+	/* Register for SPU events  */
+	register_ret = spu_switch_event_register(&spu_active);
+	if (register_ret) {
+		ret = SYNC_START_ERROR;
+		goto out;
+	}
+
+	for (k = 0; k < (MAX_NUMNODES * 8); k++)
+		last_guard_val[k] = 0;
+	pr_debug("spu_sync_start -- running.\n");
+out:
+	return ret;
+}
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+		     int num_samples)
+{
+	unsigned long long file_offset;
+	unsigned long flags;
+	int i;
+	struct vma_to_fileoffset_map *map;
+	struct spu *the_spu;
+	unsigned long long spu_num_ll = spu_num;
+	unsigned long long spu_num_shifted = spu_num_ll << 32;
+	struct cached_info *c_info;
+
+	/* We need to obtain the cache_lock here because it's
+	 * possible that after getting the cached_info, the SPU job
+	 * corresponding to this cached_info may end, thus resulting
+	 * in the destruction of the cached_info.
+	 */
+	spin_lock_irqsave(&cache_lock, flags);
+	c_info = get_cached_info(NULL, spu_num);
+	if (!c_info) {
+		/* This legitimately happens when the SPU task ends before all
+		 * samples are recorded.
+		 * No big deal -- so we just drop a few samples.
+		 */
+		pr_debug("SPU_PROF: No cached SPU contex "
+			  "for SPU #%d. Dropping samples.\n", spu_num);
+		goto out;
+	}
+
+	map = c_info->map;
+	the_spu = c_info->the_spu;
+	spin_lock(&buffer_lock);
+	for (i = 0; i < num_samples; i++) {
+		unsigned int sample = *(samples+i);
+		int grd_val = 0;
+		file_offset = 0;
+		if (sample == 0)
+			continue;
+		file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
+
+		/* If overlays are used by this SPU application, the guard
+		 * value is non-zero, indicating which overlay section is in
+		 * use.	 We need to discard samples taken during the time
+		 * period which an overlay occurs (i.e., guard value changes).
+		 */
+		if (grd_val && grd_val != last_guard_val[spu_num]) {
+			last_guard_val[spu_num] = grd_val;
+			/* Drop the rest of the samples. */
+			break;
+		}
+
+		add_event_entry(file_offset | spu_num_shifted);
+	}
+	spin_unlock(&buffer_lock);
+out:
+	spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+
+int spu_sync_stop(void)
+{
+	unsigned long flags = 0;
+	int ret = spu_switch_event_unregister(&spu_active);
+	if (ret) {
+		printk(KERN_ERR "SPU_PROF: "
+			"%s, line %d: spu_switch_event_unregister returned %d\n",
+			__FUNCTION__, __LINE__, ret);
+		goto out;
+	}
+
+	spin_lock_irqsave(&cache_lock, flags);
+	ret = release_cached_info(RELEASE_ALL);
+	spin_unlock_irqrestore(&cache_lock, flags);
+out:
+	pr_debug("spu_sync_stop -- done.\n");
+	return ret;
+}
+
+
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c
new file mode 100644
index 0000000..76ec1d1
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/vma_map.c
@@ -0,0 +1,287 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@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.
+ */
+
+/* The code in this source file is responsible for generating
+ * vma-to-fileOffset maps for both overlay and non-overlay SPU
+ * applications.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include "pr_util.h"
+
+
+void vma_map_free(struct vma_to_fileoffset_map *map)
+{
+	while (map) {
+		struct vma_to_fileoffset_map *next = map->next;
+		kfree(map);
+		map = next;
+	}
+}
+
+unsigned int
+vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
+	       const struct spu *aSpu, int *grd_val)
+{
+	/*
+	 * Default the offset to the physical address + a flag value.
+	 * Addresses of dynamically generated code can't be found in the vma
+	 * map.  For those addresses the flagged value will be sent on to
+	 * the user space tools so they can be reported rather than just
+	 * thrown away.
+	 */
+	u32 offset = 0x10000000 + vma;
+	u32 ovly_grd;
+
+	for (; map; map = map->next) {
+		if (vma < map->vma || vma >= map->vma + map->size)
+			continue;
+
+		if (map->guard_ptr) {
+			ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
+			if (ovly_grd != map->guard_val)
+				continue;
+			*grd_val = ovly_grd;
+		}
+		offset = vma - map->vma + map->offset;
+		break;
+	}
+
+	return offset;
+}
+
+static struct vma_to_fileoffset_map *
+vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
+	    unsigned int size, unsigned int offset, unsigned int guard_ptr,
+	    unsigned int guard_val)
+{
+	struct vma_to_fileoffset_map *new =
+		kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
+	if (!new) {
+		printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
+		       __FUNCTION__, __LINE__);
+		vma_map_free(map);
+		return NULL;
+	}
+
+	new->next = map;
+	new->vma = vma;
+	new->size = size;
+	new->offset = offset;
+	new->guard_ptr = guard_ptr;
+	new->guard_val = guard_val;
+
+	return new;
+}
+
+
+/* Parse SPE ELF header and generate a list of vma_maps.
+ * A pointer to the first vma_map in the generated list
+ * of vma_maps is returned.  */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
+					     unsigned long spu_elf_start)
+{
+	static const unsigned char expected[EI_PAD] = {
+		[EI_MAG0] = ELFMAG0,
+		[EI_MAG1] = ELFMAG1,
+		[EI_MAG2] = ELFMAG2,
+		[EI_MAG3] = ELFMAG3,
+		[EI_CLASS] = ELFCLASS32,
+		[EI_DATA] = ELFDATA2MSB,
+		[EI_VERSION] = EV_CURRENT,
+		[EI_OSABI] = ELFOSABI_NONE
+	};
+
+	int grd_val;
+	struct vma_to_fileoffset_map *map = NULL;
+	struct spu_overlay_info ovly;
+	unsigned int overlay_tbl_offset = -1;
+	unsigned long phdr_start, shdr_start;
+	Elf32_Ehdr ehdr;
+	Elf32_Phdr phdr;
+	Elf32_Shdr shdr, shdr_str;
+	Elf32_Sym sym;
+	int i, j;
+	char name[32];
+
+	unsigned int ovly_table_sym = 0;
+	unsigned int ovly_buf_table_sym = 0;
+	unsigned int ovly_table_end_sym = 0;
+	unsigned int ovly_buf_table_end_sym = 0;
+	unsigned long ovly_table;
+	unsigned int n_ovlys;
+
+	/* Get and validate ELF header.	 */
+
+	if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr)))
+		goto fail;
+
+	if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
+		       __FUNCTION__, __LINE__);
+		goto fail;
+	}
+	if (ehdr.e_machine != EM_SPU) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
+		       __FUNCTION__,  __LINE__);
+		goto fail;
+	}
+	if (ehdr.e_type != ET_EXEC) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: Unexpected e_type parsing SPU ELF\n",
+		       __FUNCTION__, __LINE__);
+		goto fail;
+	}
+	phdr_start = spu_elf_start + ehdr.e_phoff;
+	shdr_start = spu_elf_start + ehdr.e_shoff;
+
+	/* Traverse program headers.  */
+	for (i = 0; i < ehdr.e_phnum; i++) {
+		if (copy_from_user(&phdr,
+				   (void *) (phdr_start + i * sizeof(phdr)),
+				   sizeof(phdr)))
+			goto fail;
+
+		if (phdr.p_type != PT_LOAD)
+			continue;
+		if (phdr.p_flags & (1 << 27))
+			continue;
+
+		map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
+				  phdr.p_offset, 0, 0);
+		if (!map)
+			goto fail;
+	}
+
+	pr_debug("SPU_PROF: Created non-overlay maps\n");
+	/* Traverse section table and search for overlay-related symbols.  */
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		if (copy_from_user(&shdr,
+				   (void *) (shdr_start + i * sizeof(shdr)),
+				   sizeof(shdr)))
+			goto fail;
+
+		if (shdr.sh_type != SHT_SYMTAB)
+			continue;
+		if (shdr.sh_entsize != sizeof (sym))
+			continue;
+
+		if (copy_from_user(&shdr_str,
+				   (void *) (shdr_start + shdr.sh_link *
+					     sizeof(shdr)),
+				   sizeof(shdr)))
+			goto fail;
+
+		if (shdr_str.sh_type != SHT_STRTAB)
+			goto fail;;
+
+		for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
+			if (copy_from_user(&sym, (void *) (spu_elf_start +
+						       shdr.sh_offset + j *
+							   sizeof (sym)),
+					   sizeof (sym)))
+				goto fail;
+
+			if (copy_from_user(name, (void *)
+					   (spu_elf_start + shdr_str.sh_offset +
+					    sym.st_name),
+					   20))
+				goto fail;
+
+			if (memcmp(name, "_ovly_table", 12) == 0)
+				ovly_table_sym = sym.st_value;
+			if (memcmp(name, "_ovly_buf_table", 16) == 0)
+				ovly_buf_table_sym = sym.st_value;
+			if (memcmp(name, "_ovly_table_end", 16) == 0)
+				ovly_table_end_sym = sym.st_value;
+			if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
+				ovly_buf_table_end_sym = sym.st_value;
+		}
+	}
+
+	/* If we don't have overlays, we're done.  */
+	if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
+	    || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
+		pr_debug("SPU_PROF: No overlay table found\n");
+		goto out;
+	} else {
+		pr_debug("SPU_PROF: Overlay table found\n");
+	}
+
+	/* The _ovly_table symbol represents a table with one entry
+	 * per overlay section.	 The _ovly_buf_table symbol represents
+	 * a table with one entry per overlay region.
+	 * The struct spu_overlay_info gives the structure of the _ovly_table
+	 * entries.  The structure of _ovly_table_buf is simply one
+	 * u32 word per entry.
+	 */
+	overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
+					    aSpu, &grd_val);
+	if (overlay_tbl_offset < 0) {
+		printk(KERN_ERR "SPU_PROF: "
+		       "%s, line %d: Error finding SPU overlay table\n",
+		       __FUNCTION__, __LINE__);
+		goto fail;
+	}
+	ovly_table = spu_elf_start + overlay_tbl_offset;
+
+	n_ovlys = (ovly_table_end_sym -
+		   ovly_table_sym) / sizeof (ovly);
+
+	/* Traverse overlay table.  */
+	for (i = 0; i < n_ovlys; i++) {
+		if (copy_from_user(&ovly, (void *)
+				   (ovly_table + i * sizeof (ovly)),
+				   sizeof (ovly)))
+			goto fail;
+
+		/* The ovly.vma/size/offset arguments are analogous to the same
+		 * arguments used above for non-overlay maps.  The final two
+		 * args are referred to as the guard pointer and the guard
+		 * value.
+		 * The guard pointer is an entry in the _ovly_buf_table,
+		 * computed using ovly.buf as the index into the table.	 Since
+		 * ovly.buf values begin at '1' to reference the first (or 0th)
+		 * entry in the _ovly_buf_table, the computation subtracts 1
+		 * from ovly.buf.
+		 * The guard value is stored in the _ovly_buf_table entry and
+		 * is an index (starting at 1) back to the _ovly_table entry
+		 * that is pointing at this _ovly_buf_table entry.  So, for
+		 * example, for an overlay scenario with one overlay segment
+		 * and two overlay sections:
+		 *	- Section 1 points to the first entry of the
+		 *	  _ovly_buf_table, which contains a guard value
+		 *	  of '1', referencing the first (index=0) entry of
+		 *	  _ovly_table.
+		 *	- Section 2 points to the second entry of the
+		 *	  _ovly_buf_table, which contains a guard value
+		 *	  of '2', referencing the second (index=1) entry of
+		 *	  _ovly_table.
+		 */
+		map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
+				  ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
+		if (!map)
+			goto fail;
+	}
+	goto out;
+
+ fail:
+	map = NULL;
+ out:
+	return map;
+}
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 1a7ef7e..a28cce1 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -29,6 +29,8 @@
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
+static int op_per_cpu_rc;
+
 static void op_handle_interrupt(struct pt_regs *regs)
 {
 	model->handle_interrupt(regs, ctr);
@@ -36,25 +38,41 @@
 
 static void op_powerpc_cpu_setup(void *dummy)
 {
-	model->cpu_setup(ctr);
+	int ret;
+
+	ret = model->cpu_setup(ctr);
+
+	if (ret != 0)
+		op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_setup(void)
 {
 	int err;
 
+	op_per_cpu_rc = 0;
+
 	/* Grab the hardware */
 	err = reserve_pmc_hardware(op_handle_interrupt);
 	if (err)
 		return err;
 
 	/* Pre-compute the values to stuff in the hardware registers.  */
-	model->reg_setup(ctr, &sys, model->num_counters);
+	op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
 
-	/* Configure the registers on all cpus.  */
+	if (op_per_cpu_rc)
+		goto out;
+
+	/* Configure the registers on all cpus.	 If an error occurs on one
+	 * of the cpus, op_per_cpu_rc will be set to the error */
 	on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
 
-	return 0;
+out:	if (op_per_cpu_rc) {
+		/* error on setup release the performance counter hardware */
+		release_pmc_hardware();
+	}
+
+	return op_per_cpu_rc;
 }
 
 static void op_powerpc_shutdown(void)
@@ -64,16 +82,29 @@
 
 static void op_powerpc_cpu_start(void *dummy)
 {
-	model->start(ctr);
+	/* If any of the cpus have return an error, set the
+	 * global flag to the error so it can be returned
+	 * to the generic OProfile caller.
+	 */
+	int ret;
+
+	ret = model->start(ctr);
+	if (ret != 0)
+		op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_start(void)
 {
+	op_per_cpu_rc = 0;
+
 	if (model->global_start)
-		model->global_start(ctr);
-	if (model->start)
+		return model->global_start(ctr);
+	if (model->start) {
 		on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
-	return 0;
+		return op_per_cpu_rc;
+	}
+	return -EIO; /* No start function is defined for this
+			power architecture */
 }
 
 static inline void op_powerpc_cpu_stop(void *dummy)
@@ -147,11 +178,13 @@
 
 	switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_CELL_NATIVE
+#ifdef CONFIG_OPROFILE_CELL
 		case PPC_OPROFILE_CELL:
 			if (firmware_has_feature(FW_FEATURE_LPAR))
 				return -ENODEV;
 			model = &op_model_cell;
+			ops->sync_start = model->sync_start;
+			ops->sync_stop = model->sync_stop;
 			break;
 #endif
 		case PPC_OPROFILE_RS64:
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index 5d1bbaf..cc599eb 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -81,7 +81,7 @@
 
 /* Configures the counters on this CPU based on the global
  * settings */
-static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+static int fsl7450_cpu_setup(struct op_counter_config *ctr)
 {
 	/* freeze all counters */
 	pmc_stop_ctrs();
@@ -89,12 +89,14 @@
 	mtspr(SPRN_MMCR0, mmcr0_val);
 	mtspr(SPRN_MMCR1, mmcr1_val);
 	mtspr(SPRN_MMCR2, mmcr2_val);
+
+	return 0;
 }
 
 #define NUM_CTRS 6
 
 /* Configures the global settings for the countes on all CPUs. */
-static void fsl7450_reg_setup(struct op_counter_config *ctr,
+static int fsl7450_reg_setup(struct op_counter_config *ctr,
 			     struct op_system_config *sys,
 			     int num_ctrs)
 {
@@ -126,10 +128,12 @@
 		| mmcr1_event6(ctr[5].event);
 
 	mmcr2_val = 0;
+
+	return 0;
 }
 
 /* Sets the counters on this CPU to the chosen values, and starts them */
-static void fsl7450_start(struct op_counter_config *ctr)
+static int fsl7450_start(struct op_counter_config *ctr)
 {
 	int i;
 
@@ -148,6 +152,8 @@
 	pmc_start_ctrs();
 
 	oprofile_running = 1;
+
+	return 0;
 }
 
 /* Stop the counters on this CPU */
@@ -193,7 +199,7 @@
 	/* The freeze bit was set by the interrupt. */
 	/* Clear the freeze bit, and reenable the interrupt.
 	 * The counters won't actually start until the rfi clears
-	 * the PMM bit */
+	 * the PM/M bit */
 	pmc_start_ctrs();
 }
 
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index c29293b..d928b54 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -5,8 +5,8 @@
  *
  * Author: David Erb (djerb@us.ibm.com)
  * Modifications:
- *         Carl Love <carll@us.ibm.com>
- *         Maynard Johnson <maynardj@us.ibm.com>
+ *	   Carl Love <carll@us.ibm.com>
+ *	   Maynard Johnson <maynardj@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
@@ -38,12 +38,25 @@
 
 #include "../platforms/cell/interrupt.h"
 #include "../platforms/cell/cbe_regs.h"
+#include "cell/pr_util.h"
+
+static void cell_global_stop_spu(void);
+
+/*
+ * spu_cycle_reset is the number of cycles between samples.
+ * This variable is used for SPU profiling and should ONLY be set
+ * at the beginning of cell_reg_setup; otherwise, it's read-only.
+ */
+static unsigned int spu_cycle_reset;
+
+#define NUM_SPUS_PER_NODE    8
+#define SPU_CYCLES_EVENT_NUM 2	/*  event number for SPU_CYCLES */
 
 #define PPU_CYCLES_EVENT_NUM 1	/*  event number for CYCLES */
-#define PPU_CYCLES_GRP_NUM   1  /* special group number for identifying
-                                 * PPU_CYCLES event
-                                 */
-#define CBE_COUNT_ALL_CYCLES 0x42800000	/* PPU cycle event specifier */
+#define PPU_CYCLES_GRP_NUM   1	/* special group number for identifying
+				 * PPU_CYCLES event
+				 */
+#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
 
 #define NUM_THREADS 2         /* number of physical threads in
 			       * physical processor
@@ -51,6 +64,7 @@
 #define NUM_TRACE_BUS_WORDS 4
 #define NUM_INPUT_BUS_WORDS 2
 
+#define MAX_SPU_COUNT 0xFFFFFF	/* maximum 24 bit LFSR value */
 
 struct pmc_cntrl_data {
 	unsigned long vcntr;
@@ -62,11 +76,10 @@
 /*
  * ibm,cbe-perftools rtas parameters
  */
-
 struct pm_signal {
 	u16 cpu;		/* Processor to modify */
-	u16 sub_unit;		/* hw subunit this applies to (if applicable) */
-	short int signal_group;	/* Signal Group to Enable/Disable */
+	u16 sub_unit;		/* hw subunit this applies to (if applicable)*/
+	short int signal_group; /* Signal Group to Enable/Disable */
 	u8 bus_word;		/* Enable/Disable on this Trace/Trigger/Event
 				 * Bus Word(s) (bitmask)
 				 */
@@ -112,21 +125,42 @@
 
 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
 
-/* Interpetation of hdw_thread:
+/*
+ * The CELL profiling code makes rtas calls to setup the debug bus to
+ * route the performance signals.  Additionally, SPU profiling requires
+ * a second rtas call to setup the hardware to capture the SPU PCs.
+ * The EIO error value is returned if the token lookups or the rtas
+ * call fail.  The EIO error number is the best choice of the existing
+ * error numbers.  The probability of rtas related error is very low.  But
+ * by returning EIO and printing additional information to dmsg the user
+ * will know that OProfile did not start and dmesg will tell them why.
+ * OProfile does not support returning errors on Stop.	Not a huge issue
+ * since failure to reset the debug bus or stop the SPU PC collection is
+ * not a fatel issue.  Chances are if the Stop failed, Start doesn't work
+ * either.
+ */
+
+/*
+ * Interpetation of hdw_thread:
  * 0 - even virtual cpus 0, 2, 4,...
  * 1 - odd virtual cpus 1, 3, 5, ...
+ *
+ * FIXME: this is strictly wrong, we need to clean this up in a number
+ * of places. It works for now. -arnd
  */
 static u32 hdw_thread;
 
 static u32 virt_cntr_inter_mask;
 static struct timer_list timer_virt_cntr;
 
-/* pm_signal needs to be global since it is initialized in
+/*
+ * pm_signal needs to be global since it is initialized in
  * cell_reg_setup at the time when the necessary information
  * is available.
  */
 static struct pm_signal pm_signal[NR_PHYS_CTRS];
-static int pm_rtas_token;
+static int pm_rtas_token;    /* token for debug bus setup call */
+static int spu_rtas_token;   /* token for SPU cycle profiling */
 
 static u32 reset_value[NR_PHYS_CTRS];
 static int num_counters;
@@ -147,8 +181,8 @@
 {
 	u64 paddr = __pa(address);
 
-	return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
-			 paddr >> 32, paddr & 0xffffffff, length);
+	return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc,
+			 passthru, paddr >> 32, paddr & 0xffffffff, length);
 }
 
 static void pm_rtas_reset_signals(u32 node)
@@ -156,12 +190,13 @@
 	int ret;
 	struct pm_signal pm_signal_local;
 
-	/*  The debug bus is being set to the passthru disable state.
-	 *  However, the FW still expects atleast one legal signal routing
-	 *  entry or it will return an error on the arguments.  If we don't
-	 *  supply a valid entry, we must ignore all return values.  Ignoring
-	 *  all return values means we might miss an error we should be
-	 *  concerned about.
+	/*
+	 * The debug bus is being set to the passthru disable state.
+	 * However, the FW still expects atleast one legal signal routing
+	 * entry or it will return an error on the arguments.	If we don't
+	 * supply a valid entry, we must ignore all return values.  Ignoring
+	 * all return values means we might miss an error we should be
+	 * concerned about.
 	 */
 
 	/*  fw expects physical cpu #. */
@@ -175,18 +210,24 @@
 				     &pm_signal_local,
 				     sizeof(struct pm_signal));
 
-	if (ret)
+	if (unlikely(ret))
+		/*
+		 * Not a fatal error. For Oprofile stop, the oprofile
+		 * functions do not support returning an error for
+		 * failure to stop OProfile.
+		 */
 		printk(KERN_WARNING "%s: rtas returned: %d\n",
 		       __FUNCTION__, ret);
 }
 
-static void pm_rtas_activate_signals(u32 node, u32 count)
+static int pm_rtas_activate_signals(u32 node, u32 count)
 {
 	int ret;
 	int i, j;
 	struct pm_signal pm_signal_local[NR_PHYS_CTRS];
 
-	/* There is no debug setup required for the cycles event.
+	/*
+	 * There is no debug setup required for the cycles event.
 	 * Note that only events in the same group can be used.
 	 * Otherwise, there will be conflicts in correctly routing
 	 * the signals on the debug bus.  It is the responsiblity
@@ -213,10 +254,14 @@
 					     pm_signal_local,
 					     i * sizeof(struct pm_signal));
 
-		if (ret)
+		if (unlikely(ret)) {
 			printk(KERN_WARNING "%s: rtas returned: %d\n",
 			       __FUNCTION__, ret);
+			return -EIO;
+		}
 	}
+
+	return 0;
 }
 
 /*
@@ -260,11 +305,12 @@
 	pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
 	pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
 
-	/* Some of the islands signal selection is based on 64 bit words.
+	/*
+	 * Some of the islands signal selection is based on 64 bit words.
 	 * The debug bus words are 32 bits, the input words to the performance
 	 * counters are defined as 32 bits.  Need to convert the 64 bit island
 	 * specification to the appropriate 32 input bit and bus word for the
-	 * performance counter event selection.  See the CELL Performance
+	 * performance counter event selection.	 See the CELL Performance
 	 * monitoring signals manual and the Perf cntr hardware descriptions
 	 * for the details.
 	 */
@@ -298,6 +344,7 @@
 					input_bus[j] = i;
 					pm_regs.group_control |=
 					    (i << (31 - i));
+
 					break;
 				}
 			}
@@ -309,7 +356,8 @@
 
 static void write_pm_cntrl(int cpu)
 {
-	/* Oprofile will use 32 bit counters, set bits 7:10 to 0
+	/*
+	 * Oprofile will use 32 bit counters, set bits 7:10 to 0
 	 * pmregs.pm_cntrl is a global
 	 */
 
@@ -326,7 +374,8 @@
 	if (pm_regs.pm_cntrl.freeze == 1)
 		val |= CBE_PM_FREEZE_ALL_CTRS;
 
-	/* Routine set_count_mode must be called previously to set
+	/*
+	 * Routine set_count_mode must be called previously to set
 	 * the count mode based on the user selection of user and kernel.
 	 */
 	val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode);
@@ -336,7 +385,8 @@
 static inline void
 set_count_mode(u32 kernel, u32 user)
 {
-	/* The user must specify user and kernel if they want them. If
+	/*
+	 * The user must specify user and kernel if they want them. If
 	 *  neither is specified, OProfile will count in hypervisor mode.
 	 *  pm_regs.pm_cntrl is a global
 	 */
@@ -364,7 +414,7 @@
 
 /*
  * Oprofile is expected to collect data on all CPUs simultaneously.
- * However, there is one set of performance counters per node.  There are
+ * However, there is one set of performance counters per node.	There are
  * two hardware threads or virtual CPUs on each node.  Hence, OProfile must
  * multiplex in time the performance counter collection on the two virtual
  * CPUs.  The multiplexing of the performance counters is done by this
@@ -377,19 +427,19 @@
  * pair of per-cpu arrays is used for storing the previous and next
  * pmc values for a given node.
  * NOTE: We use the per-cpu variable to improve cache performance.
+ *
+ * This routine will alternate loading the virtual counters for
+ * virtual CPUs
  */
 static void cell_virtual_cntr(unsigned long data)
 {
-	/* This routine will alternate loading the virtual counters for
-	 * virtual CPUs
-	 */
 	int i, prev_hdw_thread, next_hdw_thread;
 	u32 cpu;
 	unsigned long flags;
 
-	/* Make sure that the interrupt_hander and
-	 * the virt counter are not both playing with
-	 * the counters on the same node.
+	/*
+	 * Make sure that the interrupt_hander and the virt counter are
+	 * not both playing with the counters on the same node.
 	 */
 
 	spin_lock_irqsave(&virt_cntr_lock, flags);
@@ -400,22 +450,25 @@
 	hdw_thread = 1 ^ hdw_thread;
 	next_hdw_thread = hdw_thread;
 
-	for (i = 0; i < num_counters; i++)
-	/* There are some per thread events.  Must do the
+	/*
+	 * There are some per thread events.  Must do the
 	 * set event, for the thread that is being started
 	 */
+	for (i = 0; i < num_counters; i++)
 		set_pm_event(i,
 			pmc_cntrl[next_hdw_thread][i].evnts,
 			pmc_cntrl[next_hdw_thread][i].masks);
 
-	/* The following is done only once per each node, but
+	/*
+	 * The following is done only once per each node, but
 	 * we need cpu #, not node #, to pass to the cbe_xxx functions.
 	 */
 	for_each_online_cpu(cpu) {
 		if (cbe_get_hw_thread_id(cpu))
 			continue;
 
-		/* stop counters, save counter values, restore counts
+		/*
+		 * stop counters, save counter values, restore counts
 		 * for previous thread
 		 */
 		cbe_disable_pm(cpu);
@@ -428,7 +481,7 @@
 			    == 0xFFFFFFFF)
 				/* If the cntr value is 0xffffffff, we must
 				 * reset that to 0xfffffff0 when the current
-				 * thread is restarted.  This will generate a
+				 * thread is restarted.	 This will generate a
 				 * new interrupt and make sure that we never
 				 * restore the counters to the max value.  If
 				 * the counters were restored to the max value,
@@ -444,13 +497,15 @@
 						      next_hdw_thread)[i]);
 		}
 
-		/* Switch to the other thread. Change the interrupt
+		/*
+		 * Switch to the other thread. Change the interrupt
 		 * and control regs to be scheduled on the CPU
 		 * corresponding to the thread to execute.
 		 */
 		for (i = 0; i < num_counters; i++) {
 			if (pmc_cntrl[next_hdw_thread][i].enabled) {
-				/* There are some per thread events.
+				/*
+				 * There are some per thread events.
 				 * Must do the set event, enable_cntr
 				 * for each cpu.
 				 */
@@ -482,17 +537,42 @@
 }
 
 /* This function is called once for all cpus combined */
-static void
-cell_reg_setup(struct op_counter_config *ctr,
-	       struct op_system_config *sys, int num_ctrs)
+static int cell_reg_setup(struct op_counter_config *ctr,
+			struct op_system_config *sys, int num_ctrs)
 {
 	int i, j, cpu;
+	spu_cycle_reset = 0;
+
+	if (ctr[0].event == SPU_CYCLES_EVENT_NUM) {
+		spu_cycle_reset = ctr[0].count;
+
+		/*
+		 * Each node will need to make the rtas call to start
+		 * and stop SPU profiling.  Get the token once and store it.
+		 */
+		spu_rtas_token = rtas_token("ibm,cbe-spu-perftools");
+
+		if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+			printk(KERN_ERR
+			       "%s: rtas token ibm,cbe-spu-perftools unknown\n",
+			       __FUNCTION__);
+			return -EIO;
+		}
+	}
 
 	pm_rtas_token = rtas_token("ibm,cbe-perftools");
-	if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+
+	/*
+	 * For all events excetp PPU CYCLEs, each node will need to make
+	 * the rtas cbe-perftools call to setup and reset the debug bus.
+	 * Make the token lookup call once and store it in the global
+	 * variable pm_rtas_token.
+	 */
+	if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+		printk(KERN_ERR
+		       "%s: rtas token ibm,cbe-perftools unknown\n",
 		       __FUNCTION__);
-		goto out;
+		return -EIO;
 	}
 
 	num_counters = num_ctrs;
@@ -520,7 +600,8 @@
 			per_cpu(pmc_values, j)[i] = 0;
 	}
 
-	/* Setup the thread 1 events, map the thread 0 event to the
+	/*
+	 * Setup the thread 1 events, map the thread 0 event to the
 	 * equivalent thread 1 event.
 	 */
 	for (i = 0; i < num_ctrs; ++i) {
@@ -544,9 +625,10 @@
 	for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
 		input_bus[i] = 0xff;
 
-	/* Our counters count up, and "count" refers to
+	/*
+	 * Our counters count up, and "count" refers to
 	 * how much before the next interrupt, and we interrupt
-	 * on overflow.  So we calculate the starting value
+	 * on overflow.	 So we calculate the starting value
 	 * which will give us "count" until overflow.
 	 * Then we set the events on the enabled counters.
 	 */
@@ -569,28 +651,27 @@
 		for (i = 0; i < num_counters; ++i) {
 			per_cpu(pmc_values, cpu)[i] = reset_value[i];
 		}
-out:
-	;
+
+	return 0;
 }
 
+
+
 /* This function is called once for each cpu */
-static void cell_cpu_setup(struct op_counter_config *cntr)
+static int cell_cpu_setup(struct op_counter_config *cntr)
 {
 	u32 cpu = smp_processor_id();
 	u32 num_enabled = 0;
 	int i;
 
+	if (spu_cycle_reset)
+		return 0;
+
 	/* There is one performance monitor per processor chip (i.e. node),
 	 * so we only need to perform this function once per node.
 	 */
 	if (cbe_get_hw_thread_id(cpu))
-		goto out;
-
-	if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-		printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
-		       __FUNCTION__);
-		goto out;
-	}
+		return 0;
 
 	/* Stop all counters */
 	cbe_disable_pm(cpu);
@@ -609,16 +690,286 @@
 		}
 	}
 
-	pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
-out:
-	;
+	/*
+	 * The pm_rtas_activate_signals will return -EIO if the FW
+	 * call failed.
+	 */
+	return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
 }
 
-static void cell_global_start(struct op_counter_config *ctr)
+#define ENTRIES	 303
+#define MAXLFSR	 0xFFFFFF
+
+/* precomputed table of 24 bit LFSR values */
+static int initial_lfsr[] = {
+ 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098, 10753424,
+ 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768, 1548716,
+ 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526, 4421547,
+ 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480, 6071392,
+ 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769, 4547026,
+ 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157, 10745556,
+ 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879, 7587769,
+ 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541, 15906893,
+ 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291, 2917017,
+ 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428, 1737756,
+ 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160, 12149558,
+ 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617, 1965401,
+ 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315, 9309720,
+ 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963, 3326042,
+ 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926, 4774955,
+ 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836, 9646934,
+ 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017, 8237783,
+ 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251, 16467278,
+ 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886, 14485051,
+ 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695, 15409741,
+ 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586, 366972,
+ 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431, 10426302,
+ 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013, 1742384,
+ 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130, 6072469,
+ 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576, 8816697,
+ 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560, 5636398,
+ 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001, 6799140,
+ 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577, 1611214,
+ 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308, 2410386,
+ 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581, 6395087,
+ 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962, 9658130,
+ 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848, 8659300,
+ 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501, 9561475,
+ 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990, 2290950,
+ 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949, 9027003,
+ 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761, 10431375,
+ 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212, 2003426,
+ 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607
+};
+
+/*
+ * The hardware uses an LFSR counting sequence to determine when to capture
+ * the SPU PCs.	 An LFSR sequence is like a puesdo random number sequence
+ * where each number occurs once in the sequence but the sequence is not in
+ * numerical order. The SPU PC capture is done when the LFSR sequence reaches
+ * the last value in the sequence.  Hence the user specified value N
+ * corresponds to the LFSR number that is N from the end of the sequence.
+ *
+ * To avoid the time to compute the LFSR, a lookup table is used.  The 24 bit
+ * LFSR sequence is broken into four ranges.  The spacing of the precomputed
+ * values is adjusted in each range so the error between the user specifed
+ * number (N) of events between samples and the actual number of events based
+ * on the precomputed value will be les then about 6.2%.  Note, if the user
+ * specifies N < 2^16, the LFSR value that is 2^16 from the end will be used.
+ * This is to prevent the loss of samples because the trace buffer is full.
+ *
+ *	   User specified N		     Step between	   Index in
+ *					 precomputed values	 precomputed
+ *								    table
+ * 0		    to	2^16-1			----		      0
+ * 2^16	    to	2^16+2^19-1		2^12		    1 to 128
+ * 2^16+2^19	    to	2^16+2^19+2^22-1	2^15		  129 to 256
+ * 2^16+2^19+2^22  to	2^24-1			2^18		  257 to 302
+ *
+ *
+ * For example, the LFSR values in the second range are computed for 2^16,
+ * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies
+ * 1, 2,..., 127, 128.
+ *
+ * The 24 bit LFSR value for the nth number in the sequence can be
+ * calculated using the following code:
+ *
+ * #define size 24
+ * int calculate_lfsr(int n)
+ * {
+ *	int i;
+ *	unsigned int newlfsr0;
+ *	unsigned int lfsr = 0xFFFFFF;
+ *	unsigned int howmany = n;
+ *
+ *	for (i = 2; i < howmany + 2; i++) {
+ *		newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^
+ *		((lfsr >> (size - 1 - 1)) & 1) ^
+ *		(((lfsr >> (size - 1 - 6)) & 1) ^
+ *		((lfsr >> (size - 1 - 23)) & 1)));
+ *
+ *		lfsr >>= 1;
+ *		lfsr = lfsr | (newlfsr0 << (size - 1));
+ *	}
+ *	return lfsr;
+ * }
+ */
+
+#define V2_16  (0x1 << 16)
+#define V2_19  (0x1 << 19)
+#define V2_22  (0x1 << 22)
+
+static int calculate_lfsr(int n)
 {
-	u32 cpu;
+	/*
+	 * The ranges and steps are in powers of 2 so the calculations
+	 * can be done using shifts rather then divide.
+	 */
+	int index;
+
+	if ((n >> 16) == 0)
+		index = 0;
+	else if (((n - V2_16) >> 19) == 0)
+		index = ((n - V2_16) >> 12) + 1;
+	else if (((n - V2_16 - V2_19) >> 22) == 0)
+		index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128;
+	else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0)
+		index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256;
+	else
+		index = ENTRIES-1;
+
+	/* make sure index is valid */
+	if ((index > ENTRIES) || (index < 0))
+		index = ENTRIES-1;
+
+	return initial_lfsr[index];
+}
+
+static int pm_rtas_activate_spu_profiling(u32 node)
+{
+	int ret, i;
+	struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+	/*
+	 * Set up the rtas call to configure the debug bus to
+	 * route the SPU PCs.  Setup the pm_signal for each SPU
+	 */
+	for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
+		pm_signal_local[i].cpu = node;
+		pm_signal_local[i].signal_group = 41;
+		/* spu i on word (i/2) */
+		pm_signal_local[i].bus_word = 1 << i / 2;
+		/* spu i */
+		pm_signal_local[i].sub_unit = i;
+		pm_signal_local[i].bit = 63;
+	}
+
+	ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
+				     PASSTHRU_ENABLE, pm_signal_local,
+				     (NUM_SPUS_PER_NODE
+				      * sizeof(struct pm_signal)));
+
+	if (unlikely(ret)) {
+		printk(KERN_WARNING "%s: rtas returned: %d\n",
+		       __FUNCTION__, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+	int ret = 0;
+	struct cpufreq_freqs *frq = data;
+	if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
+	    (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
+	    (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+		set_spu_profiling_frequency(frq->new, spu_cycle_reset);
+	return ret;
+}
+
+static struct notifier_block cpu_freq_notifier_block = {
+	.notifier_call	= oprof_cpufreq_notify
+};
+#endif
+
+static int cell_global_start_spu(struct op_counter_config *ctr)
+{
+	int subfunc;
+	unsigned int lfsr_value;
+	int cpu;
+	int ret;
+	int rtas_error;
+	unsigned int cpu_khzfreq = 0;
+
+	/* The SPU profiling uses time-based profiling based on
+	 * cpu frequency, so if configured with the CPU_FREQ
+	 * option, we should detect frequency changes and react
+	 * accordingly.
+	 */
+#ifdef CONFIG_CPU_FREQ
+	ret = cpufreq_register_notifier(&cpu_freq_notifier_block,
+					CPUFREQ_TRANSITION_NOTIFIER);
+	if (ret < 0)
+		/* this is not a fatal error */
+		printk(KERN_ERR "CPU freq change registration failed: %d\n",
+		       ret);
+
+	else
+		cpu_khzfreq = cpufreq_quick_get(smp_processor_id());
+#endif
+
+	set_spu_profiling_frequency(cpu_khzfreq, spu_cycle_reset);
+
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		/*
+		 * Setup SPU cycle-based profiling.
+		 * Set perf_mon_control bit 0 to a zero before
+		 * enabling spu collection hardware.
+		 */
+		cbe_write_pm(cpu, pm_control, 0);
+
+		if (spu_cycle_reset > MAX_SPU_COUNT)
+			/* use largest possible value */
+			lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1);
+		else
+			lfsr_value = calculate_lfsr(spu_cycle_reset);
+
+		/* must use a non zero value. Zero disables data collection. */
+		if (lfsr_value == 0)
+			lfsr_value = calculate_lfsr(1);
+
+		lfsr_value = lfsr_value << 8; /* shift lfsr to correct
+						* register location
+						*/
+
+		/* debug bus setup */
+		ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu));
+
+		if (unlikely(ret)) {
+			rtas_error = ret;
+			goto out;
+		}
+
+
+		subfunc = 2;	/* 2 - activate SPU tracing, 3 - deactivate */
+
+		/* start profiling */
+		ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc,
+		  cbe_cpu_to_node(cpu), lfsr_value);
+
+		if (unlikely(ret != 0)) {
+			printk(KERN_ERR
+			       "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+			       __FUNCTION__, ret);
+			rtas_error = -EIO;
+			goto out;
+		}
+	}
+
+	rtas_error = start_spu_profiling(spu_cycle_reset);
+	if (rtas_error)
+		goto out_stop;
+
+	oprofile_running = 1;
+	return 0;
+
+out_stop:
+	cell_global_stop_spu();		/* clean up the PMU/debug bus */
+out:
+	return rtas_error;
+}
+
+static int cell_global_start_ppu(struct op_counter_config *ctr)
+{
+	u32 cpu, i;
 	u32 interrupt_mask = 0;
-	u32 i;
 
 	/* This routine gets called once for the system.
 	 * There is one performance monitor per node, so we
@@ -651,19 +1002,79 @@
 	oprofile_running = 1;
 	smp_wmb();
 
-	/* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
-	 * executed which manipulates the PMU.  We start the "virtual counter"
+	/*
+	 * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+	 * executed which manipulates the PMU.	We start the "virtual counter"
 	 * here so that we do not need to synchronize access to the PMU in
 	 * the above for-loop.
 	 */
 	start_virt_cntrs();
+
+	return 0;
 }
 
-static void cell_global_stop(void)
+static int cell_global_start(struct op_counter_config *ctr)
+{
+	if (spu_cycle_reset)
+		return cell_global_start_spu(ctr);
+	else
+		return cell_global_start_ppu(ctr);
+}
+
+/*
+ * Note the generic OProfile stop calls do not support returning
+ * an error on stop.  Hence, will not return an error if the FW
+ * calls fail on stop.	Failure to reset the debug bus is not an issue.
+ * Failure to disable the SPU profiling is not an issue.  The FW calls
+ * to enable the performance counters and debug bus will work even if
+ * the hardware was not cleanly reset.
+ */
+static void cell_global_stop_spu(void)
+{
+	int subfunc, rtn_value;
+	unsigned int lfsr_value;
+	int cpu;
+
+	oprofile_running = 0;
+
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_unregister_notifier(&cpu_freq_notifier_block,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+	for_each_online_cpu(cpu) {
+		if (cbe_get_hw_thread_id(cpu))
+			continue;
+
+		subfunc = 3;	/*
+				 * 2 - activate SPU tracing,
+				 * 3 - deactivate
+				 */
+		lfsr_value = 0x8f100000;
+
+		rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL,
+				      subfunc, cbe_cpu_to_node(cpu),
+				      lfsr_value);
+
+		if (unlikely(rtn_value != 0)) {
+			printk(KERN_ERR
+			       "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+			       __FUNCTION__, rtn_value);
+		}
+
+		/* Deactivate the signals */
+		pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+	}
+
+	stop_spu_profiling();
+}
+
+static void cell_global_stop_ppu(void)
 {
 	int cpu;
 
-	/* This routine will be called once for the system.
+	/*
+	 * This routine will be called once for the system.
 	 * There is one performance monitor per node, so we
 	 * only need to perform this function once per node.
 	 */
@@ -687,8 +1098,16 @@
 	}
 }
 
-static void
-cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
+static void cell_global_stop(void)
+{
+	if (spu_cycle_reset)
+		cell_global_stop_spu();
+	else
+		cell_global_stop_ppu();
+}
+
+static void cell_handle_interrupt(struct pt_regs *regs,
+				struct op_counter_config *ctr)
 {
 	u32 cpu;
 	u64 pc;
@@ -699,13 +1118,15 @@
 
 	cpu = smp_processor_id();
 
-	/* Need to make sure the interrupt handler and the virt counter
+	/*
+	 * Need to make sure the interrupt handler and the virt counter
 	 * routine are not running at the same time. See the
 	 * cell_virtual_cntr() routine for additional comments.
 	 */
 	spin_lock_irqsave(&virt_cntr_lock, flags);
 
-	/* Need to disable and reenable the performance counters
+	/*
+	 * Need to disable and reenable the performance counters
 	 * to get the desired behavior from the hardware.  This
 	 * is hardware specific.
 	 */
@@ -714,7 +1135,8 @@
 
 	interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu);
 
-	/* If the interrupt mask has been cleared, then the virt cntr
+	/*
+	 * If the interrupt mask has been cleared, then the virt cntr
 	 * has cleared the interrupt.  When the thread that generated
 	 * the interrupt is restored, the data count will be restored to
 	 * 0xffffff0 to cause the interrupt to be regenerated.
@@ -732,18 +1154,20 @@
 			}
 		}
 
-		/* The counters were frozen by the interrupt.
+		/*
+		 * The counters were frozen by the interrupt.
 		 * Reenable the interrupt and restart the counters.
 		 * If there was a race between the interrupt handler and
-		 * the virtual counter routine.  The virutal counter
+		 * the virtual counter routine.	 The virutal counter
 		 * routine may have cleared the interrupts.  Hence must
 		 * use the virt_cntr_inter_mask to re-enable the interrupts.
 		 */
 		cbe_enable_pm_interrupts(cpu, hdw_thread,
 					 virt_cntr_inter_mask);
 
-		/* The writes to the various performance counters only writes
-		 * to a latch.  The new values (interrupt setting bits, reset
+		/*
+		 * The writes to the various performance counters only writes
+		 * to a latch.	The new values (interrupt setting bits, reset
 		 * counter value etc.) are not copied to the actual registers
 		 * until the performance monitor is enabled.  In order to get
 		 * this to work as desired, the permormance monitor needs to
@@ -755,10 +1179,33 @@
 	spin_unlock_irqrestore(&virt_cntr_lock, flags);
 }
 
+/*
+ * This function is called from the generic OProfile
+ * driver.  When profiling PPUs, we need to do the
+ * generic sync start; otherwise, do spu_sync_start.
+ */
+static int cell_sync_start(void)
+{
+	if (spu_cycle_reset)
+		return spu_sync_start();
+	else
+		return DO_GENERIC_SYNC;
+}
+
+static int cell_sync_stop(void)
+{
+	if (spu_cycle_reset)
+		return spu_sync_stop();
+	else
+		return 1;
+}
+
 struct op_powerpc_model op_model_cell = {
 	.reg_setup = cell_reg_setup,
 	.cpu_setup = cell_cpu_setup,
 	.global_start = cell_global_start,
 	.global_stop = cell_global_stop,
+	.sync_start = cell_sync_start,
+	.sync_stop = cell_sync_stop,
 	.handle_interrupt = cell_handle_interrupt,
 };
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 2267eb8..183a28b 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -244,7 +244,7 @@
 			mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
 }
 
-static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
 {
 	int i;
 
@@ -258,9 +258,11 @@
 
 		set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
 	}
+
+	return 0;
 }
 
-static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
 			     struct op_system_config *sys,
 			     int num_ctrs)
 {
@@ -276,9 +278,10 @@
 	for (i = 0; i < num_counters; ++i)
 		reset_value[i] = 0x80000000UL - ctr[i].count;
 
+	return 0;
 }
 
-static void fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
 {
 	int i;
 
@@ -308,6 +311,8 @@
 
 	pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
 			mfpmr(PMRN_PMGC0));
+
+	return 0;
 }
 
 static void fsl_booke_stop(void)
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
index e8a56b0..c40de46 100644
--- a/arch/powerpc/oprofile/op_model_pa6t.c
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -89,7 +89,7 @@
 
 
 /* precompute the values to stuff in the hardware registers */
-static void pa6t_reg_setup(struct op_counter_config *ctr,
+static int pa6t_reg_setup(struct op_counter_config *ctr,
 			   struct op_system_config *sys,
 			   int num_ctrs)
 {
@@ -135,10 +135,12 @@
 		pr_debug("reset_value for pmc%u inited to 0x%lx\n",
 				 pmc, reset_value[pmc]);
 	}
+
+	return 0;
 }
 
 /* configure registers on this cpu */
-static void pa6t_cpu_setup(struct op_counter_config *ctr)
+static int pa6t_cpu_setup(struct op_counter_config *ctr)
 {
 	u64 mmcr0 = mmcr0_val;
 	u64 mmcr1 = mmcr1_val;
@@ -154,9 +156,11 @@
 		mfspr(SPRN_PA6T_MMCR0));
 	pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
 		mfspr(SPRN_PA6T_MMCR1));
+
+	return 0;
 }
 
-static void pa6t_start(struct op_counter_config *ctr)
+static int pa6t_start(struct op_counter_config *ctr)
 {
 	int i;
 
@@ -174,6 +178,8 @@
 	oprofile_running = 1;
 
 	pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+
+	return 0;
 }
 
 static void pa6t_stop(void)
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index a7c206b..cddc250 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -32,7 +32,7 @@
 static u64 mmcr1_val;
 static u64 mmcra_val;
 
-static void power4_reg_setup(struct op_counter_config *ctr,
+static int power4_reg_setup(struct op_counter_config *ctr,
 			     struct op_system_config *sys,
 			     int num_ctrs)
 {
@@ -60,6 +60,8 @@
 		mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
 	else
 		mmcr0_val |= MMCR0_PROBLEM_DISABLE;
+
+	return 0;
 }
 
 extern void ppc64_enable_pmcs(void);
@@ -84,7 +86,7 @@
 	return 0;
 }
 
-static void power4_cpu_setup(struct op_counter_config *ctr)
+static int power4_cpu_setup(struct op_counter_config *ctr)
 {
 	unsigned int mmcr0 = mmcr0_val;
 	unsigned long mmcra = mmcra_val;
@@ -111,9 +113,11 @@
 	    mfspr(SPRN_MMCR1));
 	dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
 	    mfspr(SPRN_MMCRA));
+
+	return 0;
 }
 
-static void power4_start(struct op_counter_config *ctr)
+static int power4_start(struct op_counter_config *ctr)
 {
 	int i;
 	unsigned int mmcr0;
@@ -148,6 +152,7 @@
 	oprofile_running = 1;
 
 	dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+	return 0;
 }
 
 static void power4_stop(void)
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index c731acb..a20afe4 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -88,7 +88,7 @@
 
 static int num_counters;
 
-static void rs64_reg_setup(struct op_counter_config *ctr,
+static int rs64_reg_setup(struct op_counter_config *ctr,
 			   struct op_system_config *sys,
 			   int num_ctrs)
 {
@@ -100,9 +100,10 @@
 		reset_value[i] = 0x80000000UL - ctr[i].count;
 
 	/* XXX setup user and kernel profiling */
+	return 0;
 }
 
-static void rs64_cpu_setup(struct op_counter_config *ctr)
+static int rs64_cpu_setup(struct op_counter_config *ctr)
 {
 	unsigned int mmcr0;
 
@@ -125,9 +126,11 @@
 	    mfspr(SPRN_MMCR0));
 	dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
 	    mfspr(SPRN_MMCR1));
+
+	return 0;
 }
 
-static void rs64_start(struct op_counter_config *ctr)
+static int rs64_start(struct op_counter_config *ctr)
 {
 	int i;
 	unsigned int mmcr0;
@@ -155,6 +158,7 @@
 	mtspr(SPRN_MMCR0, mmcr0);
 
 	dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+	return 0;
 }
 
 static void rs64_stop(void)
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 33545d3..932538a 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -272,4 +272,14 @@
 	  you wish to build a kernel for a machine with a CPM2 coprocessor
 	  on it (826x, 827x, 8560).
 
+config AXON_RAM
+	tristate "Axon DDR2 memory device driver"
+	depends on PPC_IBM_CELL_BLADE
+	default m
+	help
+	  It registers one block device per Axon's DDR2 memory bank found
+	  on a system. Block devices are called axonram?, their major and
+	  minor numbers are available in /proc/devices, /proc/partitions or
+	  in /sys/block/axonram?/dev.
+
 endmenu
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index b8b5fde94..e4b2aee 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -215,7 +215,7 @@
 	depends on 4xx || 8xx || E200
 	default y
 
-config CONFIG_CHECK_CACHE_COHERENCY
+config CHECK_CACHE_COHERENCY
 	bool
 
 endmenu
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 9b2b386..ac80320 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -73,4 +73,14 @@
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 	  If you don't have such processor, say N
 
+config CBE_CPUFREQ_PMI
+	tristate "CBE frequency scaling using PMI interface"
+	depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL
+	default n
+	help
+	  Select this, if you want to use the PMI interface
+	  to switch frequencies. Using PMI, the
+	  processor will not only be able to run at lower speed,
+	  but also at lower core voltage.
+
 endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 869af89..f88a7c7 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -4,7 +4,9 @@
 obj-$(CONFIG_CBE_RAS)			+= ras.o
 
 obj-$(CONFIG_CBE_THERM)			+= cbe_thermal.o
-obj-$(CONFIG_CBE_CPUFREQ)		+= cbe_cpufreq.o
+obj-$(CONFIG_CBE_CPUFREQ_PMI)		+= cbe_cpufreq_pmi.o
+obj-$(CONFIG_CBE_CPUFREQ)		+= cbe-cpufreq.o
+cbe-cpufreq-y				+= cbe_cpufreq_pervasive.o cbe_cpufreq.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)		+= smp.o
@@ -23,3 +25,5 @@
 					   $(spu-priv1-y) \
 					   $(spu-manage-y) \
 					   spufs/
+
+obj-$(CONFIG_PCI_MSI)			+= axon_msi.o
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
new file mode 100644
index 0000000..4c9ab5b
--- /dev/null
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/reboot.h>
+
+#include <asm/dcr.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+
+
+/*
+ * MSIC registers, specified as offsets from dcr_base
+ */
+#define MSIC_CTRL_REG	0x0
+
+/* Base Address registers specify FIFO location in BE memory */
+#define MSIC_BASE_ADDR_HI_REG	0x3
+#define MSIC_BASE_ADDR_LO_REG	0x4
+
+/* Hold the read/write offsets into the FIFO */
+#define MSIC_READ_OFFSET_REG	0x5
+#define MSIC_WRITE_OFFSET_REG	0x6
+
+
+/* MSIC control register flags */
+#define MSIC_CTRL_ENABLE		0x0001
+#define MSIC_CTRL_FIFO_FULL_ENABLE	0x0002
+#define MSIC_CTRL_IRQ_ENABLE		0x0008
+#define MSIC_CTRL_FULL_STOP_ENABLE	0x0010
+
+/*
+ * The MSIC can be configured to use a FIFO of 32KB, 64KB, 128KB or 256KB.
+ * Currently we're using a 64KB FIFO size.
+ */
+#define MSIC_FIFO_SIZE_SHIFT	16
+#define MSIC_FIFO_SIZE_BYTES	(1 << MSIC_FIFO_SIZE_SHIFT)
+
+/*
+ * To configure the FIFO size as (1 << n) bytes, we write (n - 15) into bits
+ * 8-9 of the MSIC control reg.
+ */
+#define MSIC_CTRL_FIFO_SIZE	(((MSIC_FIFO_SIZE_SHIFT - 15) << 8) & 0x300)
+
+/*
+ * We need to mask the read/write offsets to make sure they stay within
+ * the bounds of the FIFO. Also they should always be 16-byte aligned.
+ */
+#define MSIC_FIFO_SIZE_MASK	((MSIC_FIFO_SIZE_BYTES - 1) & ~0xFu)
+
+/* Each entry in the FIFO is 16 bytes, the first 4 bytes hold the irq # */
+#define MSIC_FIFO_ENTRY_SIZE	0x10
+
+
+struct axon_msic {
+	struct device_node *dn;
+	struct irq_host *irq_host;
+	__le32 *fifo;
+	dcr_host_t dcr_host;
+	struct list_head list;
+	u32 read_offset;
+	u32 dcr_base;
+};
+
+static LIST_HEAD(axon_msic_list);
+
+static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
+{
+	pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+
+	dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val);
+}
+
+static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
+{
+	return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n);
+}
+
+static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	struct axon_msic *msic = get_irq_data(irq);
+	u32 write_offset, msi;
+	int idx;
+
+	write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+	pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+
+	/* write_offset doesn't wrap properly, so we have to mask it */
+	write_offset &= MSIC_FIFO_SIZE_MASK;
+
+	while (msic->read_offset != write_offset) {
+		idx  = msic->read_offset / sizeof(__le32);
+		msi  = le32_to_cpu(msic->fifo[idx]);
+		msi &= 0xFFFF;
+
+		pr_debug("axon_msi: woff %x roff %x msi %x\n",
+			  write_offset, msic->read_offset, msi);
+
+		msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+		msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+
+		if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
+			generic_handle_irq(msi);
+		else
+			pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+	}
+
+	desc->chip->eoi(irq);
+}
+
+static struct axon_msic *find_msi_translator(struct pci_dev *dev)
+{
+	struct irq_host *irq_host;
+	struct device_node *dn, *tmp;
+	const phandle *ph;
+	struct axon_msic *msic = NULL;
+
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+		return NULL;
+	}
+
+	for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+		ph = of_get_property(dn, "msi-translator", NULL);
+		if (ph)
+			break;
+	}
+
+	if (!ph) {
+		dev_dbg(&dev->dev,
+			"axon_msi: no msi-translator property found\n");
+		goto out_error;
+	}
+
+	tmp = dn;
+	dn = of_find_node_by_phandle(*ph);
+	if (!dn) {
+		dev_dbg(&dev->dev,
+			"axon_msi: msi-translator doesn't point to a node\n");
+		goto out_error;
+	}
+
+	irq_host = irq_find_host(dn);
+	if (!irq_host) {
+		dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+			dn->full_name);
+		goto out_error;
+	}
+
+	msic = irq_host->host_data;
+
+out_error:
+	of_node_put(dn);
+	of_node_put(tmp);
+
+	return msic;
+}
+
+static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+	if (!find_msi_translator(dev))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
+{
+	struct device_node *dn, *tmp;
+	struct msi_desc *entry;
+	int len;
+	const u32 *prop;
+
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+		return -ENODEV;
+	}
+
+	entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
+
+	for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+		if (entry->msi_attrib.is_64) {
+			prop = of_get_property(dn, "msi-address-64", &len);
+			if (prop)
+				break;
+		}
+
+		prop = of_get_property(dn, "msi-address-32", &len);
+		if (prop)
+			break;
+	}
+
+	if (!prop) {
+		dev_dbg(&dev->dev,
+			"axon_msi: no msi-address-(32|64) properties found\n");
+		return -ENOENT;
+	}
+
+	switch (len) {
+	case 8:
+		msg->address_hi = prop[0];
+		msg->address_lo = prop[1];
+		break;
+	case 4:
+		msg->address_hi = 0;
+		msg->address_lo = prop[0];
+		break;
+	default:
+		dev_dbg(&dev->dev,
+			"axon_msi: malformed msi-address-(32|64) property\n");
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+	of_node_put(dn);
+
+	return 0;
+}
+
+static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	unsigned int virq, rc;
+	struct msi_desc *entry;
+	struct msi_msg msg;
+	struct axon_msic *msic;
+
+	msic = find_msi_translator(dev);
+	if (!msic)
+		return -ENODEV;
+
+	rc = setup_msi_msg_address(dev, &msg);
+	if (rc)
+		return rc;
+
+	/* We rely on being able to stash a virq in a u16 */
+	BUILD_BUG_ON(NR_IRQS > 65536);
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		virq = irq_create_direct_mapping(msic->irq_host);
+		if (virq == NO_IRQ) {
+			dev_warn(&dev->dev,
+				 "axon_msi: virq allocation failed!\n");
+			return -1;
+		}
+		dev_dbg(&dev->dev, "axon_msi: allocated virq 0x%x\n", virq);
+
+		set_irq_msi(virq, entry);
+		msg.data = virq;
+		write_msi_msg(virq, &msg);
+	}
+
+	return 0;
+}
+
+static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+
+	dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+
+		set_irq_msi(entry->irq, NULL);
+		irq_dispose_mapping(entry->irq);
+	}
+}
+
+static struct irq_chip msic_irq_chip = {
+	.mask		= mask_msi_irq,
+	.unmask		= unmask_msi_irq,
+	.shutdown	= unmask_msi_irq,
+	.typename	= "AXON-MSI",
+};
+
+static int msic_host_map(struct irq_host *h, unsigned int virq,
+			 irq_hw_number_t hw)
+{
+	set_irq_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
+
+	return 0;
+}
+
+static int msic_host_match(struct irq_host *host, struct device_node *dn)
+{
+	struct axon_msic *msic = host->host_data;
+
+	return msic->dn == dn;
+}
+
+static struct irq_host_ops msic_host_ops = {
+	.match	= msic_host_match,
+	.map	= msic_host_map,
+};
+
+static int axon_msi_notify_reboot(struct notifier_block *nb,
+				  unsigned long code, void *data)
+{
+	struct axon_msic *msic;
+	u32 tmp;
+
+	list_for_each_entry(msic, &axon_msic_list, list) {
+		pr_debug("axon_msi: disabling %s\n", msic->dn->full_name);
+		tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
+		tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+		msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+	}
+
+	return 0;
+}
+
+static struct notifier_block axon_msi_reboot_notifier = {
+	.notifier_call = axon_msi_notify_reboot
+};
+
+static int axon_msi_setup_one(struct device_node *dn)
+{
+	struct page *page;
+	struct axon_msic *msic;
+	unsigned int virq;
+	int dcr_len;
+
+	pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+
+	msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
+	if (!msic) {
+		printk(KERN_ERR "axon_msi: couldn't allocate msic for %s\n",
+		       dn->full_name);
+		goto out;
+	}
+
+	msic->dcr_base = dcr_resource_start(dn, 0);
+	dcr_len = dcr_resource_len(dn, 0);
+
+	if (msic->dcr_base == 0 || dcr_len == 0) {
+		printk(KERN_ERR
+		       "axon_msi: couldn't parse dcr properties on %s\n",
+			dn->full_name);
+		goto out;
+	}
+
+	msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len);
+	if (!DCR_MAP_OK(msic->dcr_host)) {
+		printk(KERN_ERR "axon_msi: dcr_map failed for %s\n",
+		       dn->full_name);
+		goto out_free_msic;
+	}
+
+	page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
+				get_order(MSIC_FIFO_SIZE_BYTES));
+	if (!page) {
+		printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
+		       dn->full_name);
+		goto out_free_msic;
+	}
+
+	msic->fifo = page_address(page);
+
+	msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS,
+					&msic_host_ops, 0);
+	if (!msic->irq_host) {
+		printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+		       dn->full_name);
+		goto out_free_fifo;
+	}
+
+	msic->irq_host->host_data = msic;
+
+	virq = irq_of_parse_and_map(dn, 0);
+	if (virq == NO_IRQ) {
+		printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
+		       dn->full_name);
+		goto out_free_host;
+	}
+
+	msic->dn = of_node_get(dn);
+
+	set_irq_data(virq, msic);
+	set_irq_chained_handler(virq, axon_msi_cascade);
+	pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+
+	/* Enable the MSIC hardware */
+	msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+	msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
+				  (u64)msic->fifo & 0xFFFFFFFF);
+	msic_dcr_write(msic, MSIC_CTRL_REG,
+			MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
+			MSIC_CTRL_FIFO_SIZE);
+
+	list_add(&msic->list, &axon_msic_list);
+
+	printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
+
+	return 0;
+
+out_free_host:
+	kfree(msic->irq_host);
+out_free_fifo:
+	__free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+out_free_msic:
+	kfree(msic);
+out:
+
+	return -1;
+}
+
+static int axon_msi_init(void)
+{
+	struct device_node *dn;
+	int found = 0;
+
+	pr_debug("axon_msi: initialising ...\n");
+
+	for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
+		if (axon_msi_setup_one(dn) == 0)
+			found++;
+	}
+
+	if (found) {
+		ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+		ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+		ppc_md.msi_check_device = axon_msi_check_device;
+
+		register_reboot_notifier(&axon_msi_reboot_notifier);
+
+		pr_debug("axon_msi: registered callbacks!\n");
+	}
+
+	return 0;
+}
+arch_initcall(axon_msi_init);
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index ab511d5..0b6e8ee 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -1,7 +1,7 @@
 /*
  * cpufreq driver for the cell processor
  *
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
  *
  * Author: Christian Krafft <krafft@de.ibm.com>
  *
@@ -21,18 +21,11 @@
  */
 
 #include <linux/cpufreq.h>
-#include <linux/timer.h>
-
-#include <asm/hw_irq.h>
-#include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/processor.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-#include <asm/pmi.h>
 #include <asm/of_platform.h>
-
+#include <asm/prom.h>
 #include "cbe_regs.h"
+#include "cbe_cpufreq.h"
 
 static DEFINE_MUTEX(cbe_switch_mutex);
 
@@ -50,159 +43,24 @@
 	{0,	CPUFREQ_TABLE_END},
 };
 
-/* to write to MIC register */
-static u64 MIC_Slow_Fast_Timer_table[] = {
-	[0 ... 7] = 0x007fc00000000000ull,
-};
-
-/* more values for the MIC */
-static u64 MIC_Slow_Next_Timer_table[] = {
-	0x0000240000000000ull,
-	0x0000268000000000ull,
-	0x000029C000000000ull,
-	0x00002D0000000000ull,
-	0x0000300000000000ull,
-	0x0000334000000000ull,
-	0x000039C000000000ull,
-	0x00003FC000000000ull,
-};
-
-static unsigned int pmi_frequency_limit = 0;
 /*
  * hardware specific functions
  */
 
-static struct of_device *pmi_dev;
-
-#ifdef CONFIG_PPC_PMI
-static int set_pmode_pmi(int cpu, unsigned int pmode)
+static int set_pmode(unsigned int cpu, unsigned int slow_mode)
 {
-	int ret;
-	pmi_message_t pmi_msg;
-#ifdef DEBUG
-	u64 time;
-#endif
+	int rc;
 
-	pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
-	pmi_msg.data1 =	cbe_cpu_to_node(cpu);
-	pmi_msg.data2 = pmode;
-
-#ifdef DEBUG
-	time = (u64) get_cycles();
-#endif
-
-	pmi_send_message(pmi_dev, pmi_msg);
-	ret = pmi_msg.data2;
-
-	pr_debug("PMI returned slow mode %d\n", ret);
-
-#ifdef DEBUG
-	time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
-	time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
-	pr_debug("had to wait %lu ns for a transition\n", time);
-#endif
-	return ret;
-}
-#endif
-
-static int get_pmode(int cpu)
-{
-	int ret;
-	struct cbe_pmd_regs __iomem *pmd_regs;
-
-	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-	ret = in_be64(&pmd_regs->pmsr) & 0x07;
-
-	return ret;
-}
-
-static int set_pmode_reg(int cpu, unsigned int pmode)
-{
-	struct cbe_pmd_regs __iomem *pmd_regs;
-	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
-	u64 flags;
-	u64 value;
-
-	local_irq_save(flags);
-
-	mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
-	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-
-	pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
-	pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
-
-	out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
-	out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
-
-	out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
-	out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
-
-	value = in_be64(&pmd_regs->pmcr);
-	/* set bits to zero */
-	value &= 0xFFFFFFFFFFFFFFF8ull;
-	/* set bits to next pmode */
-	value |= pmode;
-
-	out_be64(&pmd_regs->pmcr, value);
-
-	/* wait until new pmode appears in status register */
-	value = in_be64(&pmd_regs->pmsr) & 0x07;
-	while(value != pmode) {
-		cpu_relax();
-		value = in_be64(&pmd_regs->pmsr) & 0x07;
-	}
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-static int set_pmode(int cpu, unsigned int slow_mode) {
-#ifdef CONFIG_PPC_PMI
-	if (pmi_dev)
-		return set_pmode_pmi(cpu, slow_mode);
+	if (cbe_cpufreq_has_pmi)
+		rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
 	else
-#endif
-		return set_pmode_reg(cpu, slow_mode);
+		rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
+
+	pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
+
+	return rc;
 }
 
-static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
-{
-	u8 cpu;
-	u8 cbe_pmode_new;
-
-	BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
-
-	cpu = cbe_node_to_cpu(pmi_msg.data1);
-	cbe_pmode_new = pmi_msg.data2;
-
-	pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency;
-
-	pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit);
-}
-
-static int pmi_notifier(struct notifier_block *nb,
-				       unsigned long event, void *data)
-{
-	struct cpufreq_policy *policy = data;
-
-	if (event != CPUFREQ_INCOMPATIBLE)
-		return 0;
-
-	cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit);
-	return 0;
-}
-
-static struct notifier_block pmi_notifier_block = {
-	.notifier_call = pmi_notifier,
-};
-
-static struct pmi_handler cbe_pmi_handler = {
-	.type			= PMI_TYPE_FREQ_CHANGE,
-	.handle_pmi_message	= cbe_cpufreq_handle_pmi,
-};
-
-
 /*
  * cpufreq functions
  */
@@ -221,8 +79,19 @@
 
 	pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 
+	/*
+	 * Let's check we can actually get to the CELL regs
+	 */
+	if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
+	    !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
+		pr_info("invalid CBE regs pointers for cpufreq\n");
+		return -EINVAL;
+	}
+
 	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 
+	of_node_put(cpu);
+
 	if (!max_freqp)
 		return -EINVAL;
 
@@ -239,10 +108,12 @@
 	}
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-	/* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+
+	/* if DEBUG is enabled set_pmode() measures the latency
+	 * of a transition */
 	policy->cpuinfo.transition_latency = 25000;
 
-	cur_pmode = get_pmode(policy->cpu);
+	cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
 	pr_debug("current pmode is at %d\n",cur_pmode);
 
 	policy->cur = cbe_freqs[cur_pmode].frequency;
@@ -253,21 +124,13 @@
 
 	cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 
-	if (pmi_dev) {
-		/* frequency might get limited later, initialize limit with max_freq */
-		pmi_frequency_limit = max_freq;
-		cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-	}
-
-	/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+	/* this ensures that policy->cpuinfo_min
+	 * and policy->cpuinfo_max are set correctly */
 	return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 }
 
 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-	if (pmi_dev)
-		cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-
 	cpufreq_frequency_table_put_attr(policy->cpu);
 	return 0;
 }
@@ -277,13 +140,13 @@
 	return cpufreq_frequency_table_verify(policy, cbe_freqs);
 }
 
-
-static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
-			    unsigned int relation)
+static int cbe_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
 {
 	int rc;
 	struct cpufreq_freqs freqs;
-	int cbe_pmode_new;
+	unsigned int cbe_pmode_new;
 
 	cpufreq_frequency_table_target(policy,
 				       cbe_freqs,
@@ -298,12 +161,14 @@
 	mutex_lock(&cbe_switch_mutex);
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-	pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+	pr_debug("setting frequency for cpu %d to %d kHz, " \
+		 "1/%d of max frequency\n",
 		 policy->cpu,
 		 cbe_freqs[cbe_pmode_new].frequency,
 		 cbe_freqs[cbe_pmode_new].index);
 
 	rc = set_pmode(policy->cpu, cbe_pmode_new);
+
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 	mutex_unlock(&cbe_switch_mutex);
 
@@ -326,28 +191,14 @@
 
 static int __init cbe_cpufreq_init(void)
 {
-#ifdef CONFIG_PPC_PMI
-	struct device_node *np;
-#endif
 	if (!machine_is(cell))
 		return -ENODEV;
-#ifdef CONFIG_PPC_PMI
-	np = of_find_node_by_type(NULL, "ibm,pmi");
 
-	pmi_dev = of_find_device_by_node(np);
-
-	if (pmi_dev)
-		pmi_register_handler(pmi_dev, &cbe_pmi_handler);
-#endif
 	return cpufreq_register_driver(&cbe_cpufreq_driver);
 }
 
 static void __exit cbe_cpufreq_exit(void)
 {
-#ifdef CONFIG_PPC_PMI
-	if (pmi_dev)
-		pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
-#endif
 	cpufreq_unregister_driver(&cbe_cpufreq_driver);
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/arch/powerpc/platforms/cell/cbe_cpufreq.h
new file mode 100644
index 0000000..c1d86bf
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.h
@@ -0,0 +1,24 @@
+/*
+ * cbe_cpufreq.h
+ *
+ * This file contains the definitions used by the cbe_cpufreq driver.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode);
+int cbe_cpufreq_get_pmode(int cpu);
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
+
+#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE)
+extern bool cbe_cpufreq_has_pmi;
+#else
+#define cbe_cpufreq_has_pmi (0)
+#endif
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
new file mode 100644
index 0000000..163263b
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
@@ -0,0 +1,115 @@
+/*
+ * pervasive backend for the cbe_cpufreq driver
+ *
+ * This driver makes use of the pervasive unit to
+ * engage the desired frequency.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.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, 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/io.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/machdep.h>
+#include <asm/hw_irq.h>
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+	[0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+	0x0000240000000000ull,
+	0x0000268000000000ull,
+	0x000029C000000000ull,
+	0x00002D0000000000ull,
+	0x0000300000000000ull,
+	0x0000334000000000ull,
+	0x000039C000000000ull,
+	0x00003FC000000000ull,
+};
+
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode)
+{
+	struct cbe_pmd_regs __iomem *pmd_regs;
+	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+	u64 flags;
+	u64 value;
+#ifdef DEBUG
+	long time;
+#endif
+
+	local_irq_save(flags);
+
+	mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+#ifdef DEBUG
+	time = jiffies;
+#endif
+
+	out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+	out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+	out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+	out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+	value = in_be64(&pmd_regs->pmcr);
+	/* set bits to zero */
+	value &= 0xFFFFFFFFFFFFFFF8ull;
+	/* set bits to next pmode */
+	value |= pmode;
+
+	out_be64(&pmd_regs->pmcr, value);
+
+#ifdef DEBUG
+	/* wait until new pmode appears in status register */
+	value = in_be64(&pmd_regs->pmsr) & 0x07;
+	while (value != pmode) {
+		cpu_relax();
+		value = in_be64(&pmd_regs->pmsr) & 0x07;
+	}
+
+	time = jiffies  - time;
+	time = jiffies_to_msecs(time);
+	pr_debug("had to wait %lu ms for a transition using " \
+		 "pervasive unit\n", time);
+#endif
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+
+int cbe_cpufreq_get_pmode(int cpu)
+{
+	int ret;
+	struct cbe_pmd_regs __iomem *pmd_regs;
+
+	pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+	ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+	return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
new file mode 100644
index 0000000..fc6f389
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
@@ -0,0 +1,148 @@
+/*
+ * pmi backend for the cbe_cpufreq driver
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.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, 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/kernel.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <asm/of_platform.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmi.h>
+
+#ifdef DEBUG
+#include <asm/time.h>
+#endif
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+static u8 pmi_slow_mode_limit[MAX_CBE];
+
+bool cbe_cpufreq_has_pmi = false;
+EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
+
+/*
+ * hardware specific functions
+ */
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
+{
+	int ret;
+	pmi_message_t pmi_msg;
+#ifdef DEBUG
+	long time;
+#endif
+	pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+	pmi_msg.data1 =	cbe_cpu_to_node(cpu);
+	pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+	time = jiffies;
+#endif
+	pmi_send_message(pmi_msg);
+
+#ifdef DEBUG
+	time = jiffies  - time;
+	time = jiffies_to_msecs(time);
+	pr_debug("had to wait %lu ms for a transition using " \
+		 "PMI\n", time);
+#endif
+	ret = pmi_msg.data2;
+	pr_debug("PMI returned slow mode %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
+
+
+static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
+{
+	u8 node, slow_mode;
+
+	BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+	node = pmi_msg.data1;
+	slow_mode = pmi_msg.data2;
+
+	pmi_slow_mode_limit[node] = slow_mode;
+
+	pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
+}
+
+static int pmi_notifier(struct notifier_block *nb,
+				       unsigned long event, void *data)
+{
+	struct cpufreq_policy *policy = data;
+	struct cpufreq_frequency_table *cbe_freqs;
+	u8 node;
+
+	cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
+	node = cbe_cpu_to_node(policy->cpu);
+
+	pr_debug("got notified, event=%lu, node=%u\n", event, node);
+
+	if (pmi_slow_mode_limit[node] != 0) {
+		pr_debug("limiting node %d to slow mode %d\n",
+			 node, pmi_slow_mode_limit[node]);
+
+		cpufreq_verify_within_limits(policy, 0,
+
+			cbe_freqs[pmi_slow_mode_limit[node]].frequency);
+	}
+
+	return 0;
+}
+
+static struct notifier_block pmi_notifier_block = {
+	.notifier_call = pmi_notifier,
+};
+
+static struct pmi_handler cbe_pmi_handler = {
+	.type			= PMI_TYPE_FREQ_CHANGE,
+	.handle_pmi_message	= cbe_cpufreq_handle_pmi,
+};
+
+
+
+static int __init cbe_cpufreq_pmi_init(void)
+{
+	cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0;
+
+	if (!cbe_cpufreq_has_pmi)
+		return -ENODEV;
+
+	cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+	return 0;
+}
+
+static void __exit cbe_cpufreq_pmi_exit(void)
+{
+	cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+	pmi_unregister_handler(&cbe_pmi_handler);
+}
+
+module_init(cbe_cpufreq_pmi_init);
+module_exit(cbe_cpufreq_pmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 12c9674..c8f7f00 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -174,6 +174,13 @@
 
 		cpu_handle = of_get_property(np, "cpus", &len);
 
+		/*
+		 * the CAB SLOF tree is non compliant, so we just assume
+		 * there is only one node
+		 */
+		if (WARN_ON_ONCE(!cpu_handle))
+			return np;
+
 		for (i=0; i<len; i++)
 			if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
 				return np;
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index f370f0f..e4132f8 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -292,7 +292,7 @@
 /*
  * initialize throttling with default values
  */
-static void __init init_default_values(void)
+static int __init init_default_values(void)
 {
 	int cpu;
 	struct cbe_pmd_regs __iomem *pmd_regs;
@@ -339,25 +339,40 @@
 	for_each_possible_cpu (cpu) {
 		pr_debug("processing cpu %d\n", cpu);
 		sysdev = get_cpu_sysdev(cpu);
+
+		if (!sysdev) {
+			pr_info("invalid sysdev pointer for cbe_thermal\n");
+			return -EINVAL;
+		}
+
 		pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
 
+		if (!pmd_regs) {
+			pr_info("invalid CBE regs pointer for cbe_thermal\n");
+			return -EINVAL;
+		}
+
 		out_be64(&pmd_regs->tm_str2, str2);
 		out_be64(&pmd_regs->tm_str1.val, str1.val);
 		out_be64(&pmd_regs->tm_tpr.val, tpr.val);
 		out_be64(&pmd_regs->tm_cr1.val, cr1.val);
 		out_be64(&pmd_regs->tm_cr2, cr2);
 	}
+
+	return 0;
 }
 
 
 static int __init thermal_init(void)
 {
-	init_default_values();
+	int rc = init_default_values();
 
-	spu_add_sysdev_attr_group(&spu_attribute_group);
-	cpu_add_sysdev_attr_group(&ppe_attribute_group);
+	if (rc == 0) {
+		spu_add_sysdev_attr_group(&spu_attribute_group);
+		cpu_add_sysdev_attr_group(&ppe_attribute_group);
+	}
 
-	return 0;
+	return rc;
 }
 module_init(thermal_init);
 
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 96a8f60..9012422 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -35,19 +35,38 @@
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/xmon.h>
+#include <asm/prom.h>
+#include "spu_priv1_mmio.h"
 
 const struct spu_management_ops *spu_management_ops;
 EXPORT_SYMBOL_GPL(spu_management_ops);
 
 const struct spu_priv1_ops *spu_priv1_ops;
-
-static struct list_head spu_list[MAX_NUMNODES];
-static LIST_HEAD(spu_full_list);
-static DEFINE_MUTEX(spu_mutex);
-static DEFINE_SPINLOCK(spu_list_lock);
-
 EXPORT_SYMBOL_GPL(spu_priv1_ops);
 
+struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
+EXPORT_SYMBOL_GPL(cbe_spu_info);
+
+/*
+ * Protects cbe_spu_info and spu->number.
+ */
+static DEFINE_SPINLOCK(spu_lock);
+
+/*
+ * List of all spus in the system.
+ *
+ * This list is iterated by callers from irq context and callers that
+ * want to sleep.  Thus modifications need to be done with both
+ * spu_full_list_lock and spu_full_list_mutex held, while iterating
+ * through it requires either of these locks.
+ *
+ * In addition spu_full_list_lock protects all assignmens to
+ * spu->mm.
+ */
+static LIST_HEAD(spu_full_list);
+static DEFINE_SPINLOCK(spu_full_list_lock);
+static DEFINE_MUTEX(spu_full_list_mutex);
+
 void spu_invalidate_slbs(struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
@@ -65,12 +84,12 @@
 	struct spu *spu;
 	unsigned long flags;
 
-	spin_lock_irqsave(&spu_list_lock, flags);
+	spin_lock_irqsave(&spu_full_list_lock, flags);
 	list_for_each_entry(spu, &spu_full_list, full_list) {
 		if (spu->mm == mm)
 			spu_invalidate_slbs(spu);
 	}
-	spin_unlock_irqrestore(&spu_list_lock, flags);
+	spin_unlock_irqrestore(&spu_full_list_lock, flags);
 }
 
 /* The hack below stinks... try to do something better one of
@@ -88,9 +107,9 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&spu_list_lock, flags);
+	spin_lock_irqsave(&spu_full_list_lock, flags);
 	spu->mm = mm;
-	spin_unlock_irqrestore(&spu_list_lock, flags);
+	spin_unlock_irqrestore(&spu_full_list_lock, flags);
 	if (mm)
 		mm_needs_global_tlbie(mm);
 }
@@ -390,7 +409,7 @@
 		free_irq(spu->irqs[2], spu);
 }
 
-static void spu_init_channels(struct spu *spu)
+void spu_init_channels(struct spu *spu)
 {
 	static const struct {
 		 unsigned channel;
@@ -423,46 +442,7 @@
 		out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
 	}
 }
-
-struct spu *spu_alloc_node(int node)
-{
-	struct spu *spu = NULL;
-
-	mutex_lock(&spu_mutex);
-	if (!list_empty(&spu_list[node])) {
-		spu = list_entry(spu_list[node].next, struct spu, list);
-		list_del_init(&spu->list);
-		pr_debug("Got SPU %d %d\n", spu->number, spu->node);
-	}
-	mutex_unlock(&spu_mutex);
-
-	if (spu)
-		spu_init_channels(spu);
-	return spu;
-}
-EXPORT_SYMBOL_GPL(spu_alloc_node);
-
-struct spu *spu_alloc(void)
-{
-	struct spu *spu = NULL;
-	int node;
-
-	for (node = 0; node < MAX_NUMNODES; node++) {
-		spu = spu_alloc_node(node);
-		if (spu)
-			break;
-	}
-
-	return spu;
-}
-
-void spu_free(struct spu *spu)
-{
-	mutex_lock(&spu_mutex);
-	list_add_tail(&spu->list, &spu_list[spu->node]);
-	mutex_unlock(&spu_mutex);
-}
-EXPORT_SYMBOL_GPL(spu_free);
+EXPORT_SYMBOL_GPL(spu_init_channels);
 
 static int spu_shutdown(struct sys_device *sysdev)
 {
@@ -481,12 +461,12 @@
 int spu_add_sysdev_attr(struct sysdev_attribute *attr)
 {
 	struct spu *spu;
-	mutex_lock(&spu_mutex);
 
+	mutex_lock(&spu_full_list_mutex);
 	list_for_each_entry(spu, &spu_full_list, full_list)
 		sysdev_create_file(&spu->sysdev, attr);
+	mutex_unlock(&spu_full_list_mutex);
 
-	mutex_unlock(&spu_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
@@ -494,12 +474,12 @@
 int spu_add_sysdev_attr_group(struct attribute_group *attrs)
 {
 	struct spu *spu;
-	mutex_lock(&spu_mutex);
 
+	mutex_lock(&spu_full_list_mutex);
 	list_for_each_entry(spu, &spu_full_list, full_list)
 		sysfs_create_group(&spu->sysdev.kobj, attrs);
+	mutex_unlock(&spu_full_list_mutex);
 
-	mutex_unlock(&spu_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
@@ -508,24 +488,22 @@
 void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
 {
 	struct spu *spu;
-	mutex_lock(&spu_mutex);
 
+	mutex_lock(&spu_full_list_mutex);
 	list_for_each_entry(spu, &spu_full_list, full_list)
 		sysdev_remove_file(&spu->sysdev, attr);
-
-	mutex_unlock(&spu_mutex);
+	mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
 
 void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
 {
 	struct spu *spu;
-	mutex_lock(&spu_mutex);
 
+	mutex_lock(&spu_full_list_mutex);
 	list_for_each_entry(spu, &spu_full_list, full_list)
 		sysfs_remove_group(&spu->sysdev.kobj, attrs);
-
-	mutex_unlock(&spu_mutex);
+	mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
 
@@ -553,16 +531,19 @@
 	int ret;
 	static int number;
 	unsigned long flags;
+	struct timespec ts;
 
 	ret = -ENOMEM;
 	spu = kzalloc(sizeof (*spu), GFP_KERNEL);
 	if (!spu)
 		goto out;
 
+	spu->alloc_state = SPU_FREE;
+
 	spin_lock_init(&spu->register_lock);
-	mutex_lock(&spu_mutex);
+	spin_lock(&spu_lock);
 	spu->number = number++;
-	mutex_unlock(&spu_mutex);
+	spin_unlock(&spu_lock);
 
 	ret = spu_create_spu(spu, data);
 
@@ -579,15 +560,22 @@
 	if (ret)
 		goto out_free_irqs;
 
-	mutex_lock(&spu_mutex);
-	spin_lock_irqsave(&spu_list_lock, flags);
-	list_add(&spu->list, &spu_list[spu->node]);
-	list_add(&spu->full_list, &spu_full_list);
-	spin_unlock_irqrestore(&spu_list_lock, flags);
-	mutex_unlock(&spu_mutex);
+	mutex_lock(&cbe_spu_info[spu->node].list_mutex);
+	list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
+	cbe_spu_info[spu->node].n_spus++;
+	mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
 
-	spu->stats.utilization_state = SPU_UTIL_IDLE;
-	spu->stats.tstamp = jiffies;
+	mutex_lock(&spu_full_list_mutex);
+	spin_lock_irqsave(&spu_full_list_lock, flags);
+	list_add(&spu->full_list, &spu_full_list);
+	spin_unlock_irqrestore(&spu_full_list_lock, flags);
+	mutex_unlock(&spu_full_list_mutex);
+
+	spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
+	ktime_get_ts(&ts);
+	spu->stats.tstamp = timespec_to_ns(&ts);
+
+	INIT_LIST_HEAD(&spu->aff_list);
 
 	goto out;
 
@@ -608,12 +596,20 @@
 static unsigned long long spu_acct_time(struct spu *spu,
 		enum spu_utilization_state state)
 {
+	struct timespec ts;
 	unsigned long long time = spu->stats.times[state];
 
-	if (spu->stats.utilization_state == state)
-		time += jiffies - spu->stats.tstamp;
+	/*
+	 * If the spu is idle or the context is stopped, utilization
+	 * statistics are not updated.  Apply the time delta from the
+	 * last recorded state of the spu.
+	 */
+	if (spu->stats.util_state == state) {
+		ktime_get_ts(&ts);
+		time += timespec_to_ns(&ts) - spu->stats.tstamp;
+	}
 
-	return jiffies_to_msecs(time);
+	return time / NSEC_PER_MSEC;
 }
 
 
@@ -623,11 +619,11 @@
 
 	return sprintf(buf, "%s %llu %llu %llu %llu "
 		      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-		spu_state_names[spu->stats.utilization_state],
+		spu_state_names[spu->stats.util_state],
 		spu_acct_time(spu, SPU_UTIL_USER),
 		spu_acct_time(spu, SPU_UTIL_SYSTEM),
 		spu_acct_time(spu, SPU_UTIL_IOWAIT),
-		spu_acct_time(spu, SPU_UTIL_IDLE),
+		spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
 		spu->stats.vol_ctx_switch,
 		spu->stats.invol_ctx_switch,
 		spu->stats.slb_flt,
@@ -640,12 +636,146 @@
 
 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
 
+/* Hardcoded affinity idxs for QS20 */
+#define SPES_PER_BE 8
+static int QS20_reg_idxs[SPES_PER_BE] =   { 0, 2, 4, 6, 7, 5, 3, 1 };
+static int QS20_reg_memory[SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
+
+static struct spu *spu_lookup_reg(int node, u32 reg)
+{
+	struct spu *spu;
+
+	list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+		if (*(u32 *)get_property(spu_devnode(spu), "reg", NULL) == reg)
+			return spu;
+	}
+	return NULL;
+}
+
+static void init_aff_QS20_harcoded(void)
+{
+	int node, i;
+	struct spu *last_spu, *spu;
+	u32 reg;
+
+	for (node = 0; node < MAX_NUMNODES; node++) {
+		last_spu = NULL;
+		for (i = 0; i < SPES_PER_BE; i++) {
+			reg = QS20_reg_idxs[i];
+			spu = spu_lookup_reg(node, reg);
+			if (!spu)
+				continue;
+			spu->has_mem_affinity = QS20_reg_memory[reg];
+			if (last_spu)
+				list_add_tail(&spu->aff_list,
+						&last_spu->aff_list);
+			last_spu = spu;
+		}
+	}
+}
+
+static int of_has_vicinity(void)
+{
+	struct spu* spu;
+
+	spu = list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list);
+	return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL;
+}
+
+static struct spu *aff_devnode_spu(int cbe, struct device_node *dn)
+{
+	struct spu *spu;
+
+	list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list)
+		if (spu_devnode(spu) == dn)
+			return spu;
+	return NULL;
+}
+
+static struct spu *
+aff_node_next_to(int cbe, struct device_node *target, struct device_node *avoid)
+{
+	struct spu *spu;
+	const phandle *vic_handles;
+	int lenp, i;
+
+	list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) {
+		if (spu_devnode(spu) == avoid)
+			continue;
+		vic_handles = get_property(spu_devnode(spu), "vicinity", &lenp);
+		for (i=0; i < (lenp / sizeof(phandle)); i++) {
+			if (vic_handles[i] == target->linux_phandle)
+				return spu;
+		}
+	}
+	return NULL;
+}
+
+static void init_aff_fw_vicinity_node(int cbe)
+{
+	struct spu *spu, *last_spu;
+	struct device_node *vic_dn, *last_spu_dn;
+	phandle avoid_ph;
+	const phandle *vic_handles;
+	const char *name;
+	int lenp, i, added, mem_aff;
+
+	last_spu = list_entry(cbe_spu_info[cbe].spus.next, struct spu, cbe_list);
+	avoid_ph = 0;
+	for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) {
+		last_spu_dn = spu_devnode(last_spu);
+		vic_handles = get_property(last_spu_dn, "vicinity", &lenp);
+
+		for (i = 0; i < (lenp / sizeof(phandle)); i++) {
+			if (vic_handles[i] == avoid_ph)
+				continue;
+
+			vic_dn = of_find_node_by_phandle(vic_handles[i]);
+			if (!vic_dn)
+				continue;
+
+			name = get_property(vic_dn, "name", NULL);
+			if (strcmp(name, "spe") == 0) {
+				spu = aff_devnode_spu(cbe, vic_dn);
+				avoid_ph = last_spu_dn->linux_phandle;
+			}
+			else {
+				mem_aff = strcmp(name, "mic-tm") == 0;
+				spu = aff_node_next_to(cbe, vic_dn, last_spu_dn);
+				if (!spu)
+					continue;
+				if (mem_aff) {
+					last_spu->has_mem_affinity = 1;
+					spu->has_mem_affinity = 1;
+				}
+				avoid_ph = vic_dn->linux_phandle;
+			}
+			list_add_tail(&spu->aff_list, &last_spu->aff_list);
+			last_spu = spu;
+			break;
+		}
+	}
+}
+
+static void init_aff_fw_vicinity(void)
+{
+	int cbe;
+
+	/* sets has_mem_affinity for each spu, as long as the
+	 * spu->aff_list list, linking each spu to its neighbors
+	 */
+	for (cbe = 0; cbe < MAX_NUMNODES; cbe++)
+		init_aff_fw_vicinity_node(cbe);
+}
+
 static int __init init_spu_base(void)
 {
 	int i, ret = 0;
 
-	for (i = 0; i < MAX_NUMNODES; i++)
-		INIT_LIST_HEAD(&spu_list[i]);
+	for (i = 0; i < MAX_NUMNODES; i++) {
+		mutex_init(&cbe_spu_info[i].list_mutex);
+		INIT_LIST_HEAD(&cbe_spu_info[i].spus);
+	}
 
 	if (!spu_management_ops)
 		goto out;
@@ -675,16 +805,25 @@
 		fb_append_extra_logo(&logo_spe_clut224, ret);
 	}
 
+	mutex_lock(&spu_full_list_mutex);
 	xmon_register_spus(&spu_full_list);
-
+	crash_register_spus(&spu_full_list);
+	mutex_unlock(&spu_full_list_mutex);
 	spu_add_sysdev_attr(&attr_stat);
 
+	if (of_has_vicinity()) {
+		init_aff_fw_vicinity();
+	} else {
+		long root = of_get_flat_dt_root();
+		if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+			init_aff_QS20_harcoded();
+	}
+
 	return 0;
 
  out_unregister_sysdev_class:
 	sysdev_class_unregister(&spu_sysdev_class);
  out:
-
 	return ret;
 }
 module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
index 261b507..dd2c668 100644
--- a/arch/powerpc/platforms/cell/spu_syscalls.c
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -34,14 +34,27 @@
  * this file is not used and the syscalls directly enter the fs code */
 
 asmlinkage long sys_spu_create(const char __user *name,
-		unsigned int flags, mode_t mode)
+		unsigned int flags, mode_t mode, int neighbor_fd)
 {
 	long ret;
 	struct module *owner = spufs_calls.owner;
+	struct file *neighbor;
+	int fput_needed;
 
 	ret = -ENOSYS;
 	if (owner && try_module_get(owner)) {
-		ret = spufs_calls.create_thread(name, flags, mode);
+		if (flags & SPU_CREATE_AFFINITY_SPU) {
+			neighbor = fget_light(neighbor_fd, &fput_needed);
+			if (neighbor) {
+				ret = spufs_calls.create_thread(name, flags,
+								mode, neighbor);
+				fput_light(neighbor, fput_needed);
+			}
+		}
+		else {
+			ret = spufs_calls.create_thread(name, flags,
+							mode, NULL);
+		}
 		module_put(owner);
 	}
 	return ret;
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 6d7bd60..6694f86 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -22,6 +22,7 @@
 
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/spu.h>
@@ -55,12 +56,12 @@
 	ctx->ops = &spu_backing_ops;
 	ctx->owner = get_task_mm(current);
 	INIT_LIST_HEAD(&ctx->rq);
+	INIT_LIST_HEAD(&ctx->aff_list);
 	if (gang)
 		spu_gang_add_ctx(gang, ctx);
 	ctx->cpus_allowed = current->cpus_allowed;
 	spu_set_timeslice(ctx);
-	ctx->stats.execution_state = SPUCTX_UTIL_USER;
-	ctx->stats.tstamp = jiffies;
+	ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
 
 	atomic_inc(&nr_spu_contexts);
 	goto out;
@@ -81,6 +82,8 @@
 	spu_fini_csa(&ctx->csa);
 	if (ctx->gang)
 		spu_gang_remove_ctx(ctx->gang, ctx);
+	if (ctx->prof_priv_kref)
+		kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
 	BUG_ON(!list_empty(&ctx->rq));
 	atomic_dec(&nr_spu_contexts);
 	kfree(ctx);
@@ -166,6 +169,39 @@
 void spu_acquire_saved(struct spu_context *ctx)
 {
 	spu_acquire(ctx);
-	if (ctx->state != SPU_STATE_SAVED)
+	if (ctx->state != SPU_STATE_SAVED) {
+		set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
 		spu_deactivate(ctx);
+	}
 }
+
+/**
+ * spu_release_saved - unlock spu context and return it to the runqueue
+ * @ctx:	context to unlock
+ */
+void spu_release_saved(struct spu_context *ctx)
+{
+	BUG_ON(ctx->state != SPU_STATE_SAVED);
+
+	if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags))
+		spu_activate(ctx, 0);
+
+	spu_release(ctx);
+}
+
+void spu_set_profile_private_kref(struct spu_context *ctx,
+				  struct kref *prof_info_kref,
+				  void ( * prof_info_release) (struct kref *kref))
+{
+	ctx->prof_priv_kref = prof_info_kref;
+	ctx->prof_priv_release = prof_info_release;
+}
+EXPORT_SYMBOL_GPL(spu_set_profile_private_kref);
+
+void *spu_get_profile_private_kref(struct spu_context *ctx)
+{
+	return ctx->prof_priv_kref;
+}
+EXPORT_SYMBOL_GPL(spu_get_profile_private_kref);
+
+
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 5d9ad5a..5e31799 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -226,7 +226,7 @@
 		spu_acquire_saved(ctx_info->ctx);
 		for (j = 0; j < spufs_coredump_num_notes; j++)
 			spufs_arch_write_note(ctx_info, j, file);
-		spu_release(ctx_info->ctx);
+		spu_release_saved(ctx_info->ctx);
 		list_del(&ctx_info->list);
 		kfree(ctx_info);
 	}
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index f53a074..917eab4 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -179,16 +179,14 @@
 	if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
 		return 0;
 
-	spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT);
+	spuctx_switch_state(ctx, SPU_UTIL_IOWAIT);
 
 	pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
 		dsisr, ctx->state);
 
 	ctx->stats.hash_flt++;
-	if (ctx->state == SPU_STATE_RUNNABLE) {
+	if (ctx->state == SPU_STATE_RUNNABLE)
 		ctx->spu->stats.hash_flt++;
-		spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT);
-	}
 
 	/* we must not hold the lock when entering spu_handle_mm_fault */
 	spu_release(ctx);
@@ -226,7 +224,7 @@
 	} else
 		spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
 
-	spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
+	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index c2814ea..4100ddc 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -370,7 +370,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_regs_read(ctx, buffer, size, pos);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 
@@ -392,7 +392,7 @@
 	ret = copy_from_user(lscsa->gprs + *pos - size,
 			     buffer, size) ? -EFAULT : size;
 
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 
@@ -421,7 +421,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_fpcr_read(ctx, buffer, size, pos);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 
@@ -443,7 +443,7 @@
 	ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
 			     buffer, size) ? -EFAULT : size;
 
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 
@@ -868,7 +868,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_signal1_read(ctx, buf, len, pos);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -934,6 +934,13 @@
 	.mmap = spufs_signal1_mmap,
 };
 
+static const struct file_operations spufs_signal1_nosched_fops = {
+	.open = spufs_signal1_open,
+	.release = spufs_signal1_release,
+	.write = spufs_signal1_write,
+	.mmap = spufs_signal1_mmap,
+};
+
 static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
 	struct spufs_inode_info *i = SPUFS_I(inode);
@@ -992,7 +999,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_signal2_read(ctx, buf, len, pos);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -1062,6 +1069,13 @@
 	.mmap = spufs_signal2_mmap,
 };
 
+static const struct file_operations spufs_signal2_nosched_fops = {
+	.open = spufs_signal2_open,
+	.release = spufs_signal2_release,
+	.write = spufs_signal2_write,
+	.mmap = spufs_signal2_mmap,
+};
+
 static void spufs_signal1_type_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
@@ -1612,7 +1626,7 @@
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	spu_acquire_saved(ctx);
 	lscsa->decr.slot[0] = (u32) val;
-	spu_release(ctx);
+	spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_get(void *data)
@@ -1628,7 +1642,7 @@
 	u64 ret;
 	spu_acquire_saved(ctx);
 	ret = __spufs_decr_get(data);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
@@ -1637,17 +1651,21 @@
 static void spufs_decr_status_set(void *data, u64 val)
 {
 	struct spu_context *ctx = data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	spu_acquire_saved(ctx);
-	lscsa->decr_status.slot[0] = (u32) val;
-	spu_release(ctx);
+	if (val)
+		ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+	else
+		ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
+	spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_status_get(void *data)
 {
 	struct spu_context *ctx = data;
-	struct spu_lscsa *lscsa = ctx->csa.lscsa;
-	return lscsa->decr_status.slot[0];
+	if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING)
+		return SPU_DECR_STATUS_RUNNING;
+	else
+		return 0;
 }
 
 static u64 spufs_decr_status_get(void *data)
@@ -1656,7 +1674,7 @@
 	u64 ret;
 	spu_acquire_saved(ctx);
 	ret = __spufs_decr_status_get(data);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
@@ -1668,7 +1686,7 @@
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	spu_acquire_saved(ctx);
 	lscsa->event_mask.slot[0] = (u32) val;
-	spu_release(ctx);
+	spu_release_saved(ctx);
 }
 
 static u64 __spufs_event_mask_get(void *data)
@@ -1684,7 +1702,7 @@
 	u64 ret;
 	spu_acquire_saved(ctx);
 	ret = __spufs_event_mask_get(data);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
@@ -1708,7 +1726,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_event_status_get(data);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
@@ -1720,7 +1738,7 @@
 	struct spu_lscsa *lscsa = ctx->csa.lscsa;
 	spu_acquire_saved(ctx);
 	lscsa->srr0.slot[0] = (u32) val;
-	spu_release(ctx);
+	spu_release_saved(ctx);
 }
 
 static u64 spufs_srr0_get(void *data)
@@ -1730,7 +1748,7 @@
 	u64 ret;
 	spu_acquire_saved(ctx);
 	ret = lscsa->srr0.slot[0];
-	spu_release(ctx);
+	spu_release_saved(ctx);
 	return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
@@ -1786,7 +1804,7 @@
 
 	spu_acquire_saved(ctx);
 	ret = __spufs_lslr_get(data);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -1850,7 +1868,7 @@
 	spin_lock(&ctx->csa.register_lock);
 	ret = __spufs_mbox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -1888,7 +1906,7 @@
 	spin_lock(&ctx->csa.register_lock);
 	ret = __spufs_ibox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -1929,7 +1947,7 @@
 	spin_lock(&ctx->csa.register_lock);
 	ret = __spufs_wbox_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -1979,7 +1997,7 @@
 	spin_lock(&ctx->csa.register_lock);
 	ret = __spufs_dma_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -2030,7 +2048,7 @@
 	spin_lock(&ctx->csa.register_lock);
 	ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
 	spin_unlock(&ctx->csa.register_lock);
-	spu_release(ctx);
+	spu_release_saved(ctx);
 
 	return ret;
 }
@@ -2065,14 +2083,26 @@
 };
 
 static unsigned long long spufs_acct_time(struct spu_context *ctx,
-		enum spuctx_execution_state state)
+		enum spu_utilization_state state)
 {
-	unsigned long time = ctx->stats.times[state];
+	struct timespec ts;
+	unsigned long long time = ctx->stats.times[state];
 
-	if (ctx->stats.execution_state == state)
-		time += jiffies - ctx->stats.tstamp;
+	/*
+	 * In general, utilization statistics are updated by the controlling
+	 * thread as the spu context moves through various well defined
+	 * state transitions, but if the context is lazily loaded its
+	 * utilization statistics are not updated as the controlling thread
+	 * is not tightly coupled with the execution of the spu context.  We
+	 * calculate and apply the time delta from the last recorded state
+	 * of the spu context.
+	 */
+	if (ctx->spu && ctx->stats.util_state == state) {
+		ktime_get_ts(&ts);
+		time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+	}
 
-	return jiffies_to_msecs(time);
+	return time / NSEC_PER_MSEC;
 }
 
 static unsigned long long spufs_slb_flts(struct spu_context *ctx)
@@ -2107,11 +2137,11 @@
 	spu_acquire(ctx);
 	seq_printf(s, "%s %llu %llu %llu %llu "
 		      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-		ctx_state_names[ctx->stats.execution_state],
-		spufs_acct_time(ctx, SPUCTX_UTIL_USER),
-		spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM),
-		spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT),
-		spufs_acct_time(ctx, SPUCTX_UTIL_LOADED),
+		ctx_state_names[ctx->stats.util_state],
+		spufs_acct_time(ctx, SPU_UTIL_USER),
+		spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+		spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+		spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
 		ctx->stats.vol_ctx_switch,
 		ctx->stats.invol_ctx_switch,
 		spufs_slb_flts(ctx),
@@ -2147,8 +2177,8 @@
 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-	{ "signal1", &spufs_signal1_fops, 0666, },
-	{ "signal2", &spufs_signal2_fops, 0666, },
+	{ "signal1", &spufs_signal1_nosched_fops, 0222, },
+	{ "signal2", &spufs_signal2_nosched_fops, 0222, },
 	{ "signal1_type", &spufs_signal1_type, 0666, },
 	{ "signal2_type", &spufs_signal2_type, 0666, },
 	{ "cntl", &spufs_cntl_fops,  0666, },
@@ -2184,8 +2214,8 @@
 	{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
 	{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
 	{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-	{ "signal1", &spufs_signal1_fops, 0666, },
-	{ "signal2", &spufs_signal2_fops, 0666, },
+	{ "signal1", &spufs_signal1_nosched_fops, 0222, },
+	{ "signal2", &spufs_signal2_nosched_fops, 0222, },
 	{ "signal1_type", &spufs_signal1_type, 0666, },
 	{ "signal2_type", &spufs_signal2_type, 0666, },
 	{ "mss", &spufs_mss_fops, 0666, },
diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c
index 212ea78..71a4432 100644
--- a/arch/powerpc/platforms/cell/spufs/gang.c
+++ b/arch/powerpc/platforms/cell/spufs/gang.c
@@ -35,7 +35,9 @@
 
 	kref_init(&gang->kref);
 	mutex_init(&gang->mutex);
+	mutex_init(&gang->aff_mutex);
 	INIT_LIST_HEAD(&gang->list);
+	INIT_LIST_HEAD(&gang->aff_list_head);
 
 out:
 	return gang;
@@ -73,6 +75,10 @@
 {
 	mutex_lock(&gang->mutex);
 	WARN_ON(ctx->gang != gang);
+	if (!list_empty(&ctx->aff_list)) {
+		list_del_init(&ctx->aff_list);
+		gang->aff_flags &= ~AFF_OFFSETS_SET;
+	}
 	list_del_init(&ctx->gang_list);
 	gang->contexts--;
 	mutex_unlock(&gang->mutex);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 7eb4d6c..b3d0dd1 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -316,11 +316,107 @@
 	return ret;
 }
 
-static int spufs_create_context(struct inode *inode,
-			struct dentry *dentry,
-			struct vfsmount *mnt, int flags, int mode)
+static struct spu_context *
+spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
+						struct file *filp)
+{
+	struct spu_context *tmp, *neighbor;
+	int count, node;
+	int aff_supp;
+
+	aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
+					struct spu, cbe_list))->aff_list);
+
+	if (!aff_supp)
+		return ERR_PTR(-EINVAL);
+
+	if (flags & SPU_CREATE_GANG)
+		return ERR_PTR(-EINVAL);
+
+	if (flags & SPU_CREATE_AFFINITY_MEM &&
+	    gang->aff_ref_ctx &&
+	    gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
+		return ERR_PTR(-EEXIST);
+
+	if (gang->aff_flags & AFF_MERGED)
+		return ERR_PTR(-EBUSY);
+
+	neighbor = NULL;
+	if (flags & SPU_CREATE_AFFINITY_SPU) {
+		if (!filp || filp->f_op != &spufs_context_fops)
+			return ERR_PTR(-EINVAL);
+
+		neighbor = get_spu_context(
+				SPUFS_I(filp->f_dentry->d_inode)->i_ctx);
+
+		if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
+		    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
+		    !list_entry(neighbor->aff_list.next, struct spu_context,
+		    aff_list)->aff_head)
+			return ERR_PTR(-EEXIST);
+
+		if (gang != neighbor->gang)
+			return ERR_PTR(-EINVAL);
+
+		count = 1;
+		list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+			count++;
+		if (list_empty(&neighbor->aff_list))
+			count++;
+
+		for (node = 0; node < MAX_NUMNODES; node++) {
+			if ((cbe_spu_info[node].n_spus - atomic_read(
+				&cbe_spu_info[node].reserved_spus)) >= count)
+				break;
+		}
+
+		if (node == MAX_NUMNODES)
+			return ERR_PTR(-EEXIST);
+	}
+
+	return neighbor;
+}
+
+static void
+spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
+					struct spu_context *neighbor)
+{
+	if (flags & SPU_CREATE_AFFINITY_MEM)
+		ctx->gang->aff_ref_ctx = ctx;
+
+	if (flags & SPU_CREATE_AFFINITY_SPU) {
+		if (list_empty(&neighbor->aff_list)) {
+			list_add_tail(&neighbor->aff_list,
+				&ctx->gang->aff_list_head);
+			neighbor->aff_head = 1;
+		}
+
+		if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
+		    || list_entry(neighbor->aff_list.next, struct spu_context,
+							aff_list)->aff_head) {
+			list_add(&ctx->aff_list, &neighbor->aff_list);
+		} else  {
+			list_add_tail(&ctx->aff_list, &neighbor->aff_list);
+			if (neighbor->aff_head) {
+				neighbor->aff_head = 0;
+				ctx->aff_head = 1;
+			}
+		}
+
+		if (!ctx->gang->aff_ref_ctx)
+			ctx->gang->aff_ref_ctx = ctx;
+	}
+}
+
+static int
+spufs_create_context(struct inode *inode, struct dentry *dentry,
+			struct vfsmount *mnt, int flags, int mode,
+			struct file *aff_filp)
 {
 	int ret;
+	int affinity;
+	struct spu_gang *gang;
+	struct spu_context *neighbor;
 
 	ret = -EPERM;
 	if ((flags & SPU_CREATE_NOSCHED) &&
@@ -336,9 +432,29 @@
 	if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
 		goto out_unlock;
 
+	gang = NULL;
+	neighbor = NULL;
+	affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
+	if (affinity) {
+		gang = SPUFS_I(inode)->i_gang;
+		ret = -EINVAL;
+		if (!gang)
+			goto out_unlock;
+		mutex_lock(&gang->aff_mutex);
+		neighbor = spufs_assert_affinity(flags, gang, aff_filp);
+		if (IS_ERR(neighbor)) {
+			ret = PTR_ERR(neighbor);
+			goto out_aff_unlock;
+		}
+	}
+
 	ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
 	if (ret)
-		goto out_unlock;
+		goto out_aff_unlock;
+
+	if (affinity)
+		spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
+								neighbor);
 
 	/*
 	 * get references for dget and mntget, will be released
@@ -352,6 +468,9 @@
 		goto out;
 	}
 
+out_aff_unlock:
+	if (affinity)
+		mutex_unlock(&gang->aff_mutex);
 out_unlock:
 	mutex_unlock(&inode->i_mutex);
 out:
@@ -450,7 +569,8 @@
 
 static struct file_system_type spufs_type;
 
-long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
+							struct file *filp)
 {
 	struct dentry *dentry;
 	int ret;
@@ -487,7 +607,7 @@
 					dentry, nd->mnt, mode);
 	else
 		return spufs_create_context(nd->dentry->d_inode,
-					dentry, nd->mnt, flags, mode);
+					dentry, nd->mnt, flags, mode, filp);
 
 out_dput:
 	dput(dentry);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 58ae13b..0b50fa5 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,15 +18,17 @@
 	wake_up_all(&ctx->stop_wq);
 }
 
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
 {
 	struct spu *spu;
 	u64 pte_fault;
 
 	*stat = ctx->ops->status_read(ctx);
-	if (ctx->state != SPU_STATE_RUNNABLE)
-		return 1;
+
 	spu = ctx->spu;
+	if (ctx->state != SPU_STATE_RUNNABLE ||
+	    test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
+		return 1;
 	pte_fault = spu->dsisr &
 	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
 	return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
@@ -124,8 +126,10 @@
 	return ret;
 }
 
-static int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 *npc)
 {
+	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
 	if (ctx->flags & SPU_CREATE_ISOLATE) {
 		unsigned long runcntl;
 
@@ -151,16 +155,20 @@
 		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
 	}
 
+	spuctx_switch_state(ctx, SPU_UTIL_USER);
+
 	return 0;
 }
 
-static int spu_run_fini(struct spu_context *ctx, u32 * npc,
-			       u32 * status)
+static int spu_run_fini(struct spu_context *ctx, u32 *npc,
+			       u32 *status)
 {
 	int ret = 0;
 
 	*status = ctx->ops->status_read(ctx);
 	*npc = ctx->ops->npc_read(ctx);
+
+	spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
 	spu_release(ctx);
 
 	if (signal_pending(current))
@@ -289,10 +297,10 @@
 	return ret;
 }
 
-long spufs_run_spu(struct file *file, struct spu_context *ctx,
-		   u32 *npc, u32 *event)
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
 {
 	int ret;
+	struct spu *spu;
 	u32 status;
 
 	if (mutex_lock_interruptible(&ctx->run_mutex))
@@ -328,6 +336,17 @@
 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
 		if (unlikely(ret))
 			break;
+		spu = ctx->spu;
+		if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
+						&ctx->sched_flags))) {
+			if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
+				spu_switch_notify(spu, ctx);
+				continue;
+			}
+		}
+
+		spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
 		if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
 		    (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
 			ret = spu_process_callback(ctx);
@@ -356,6 +375,7 @@
 	    (ctx->state == SPU_STATE_RUNNABLE))
 		ctx->stats.libassist++;
 
+
 	ctx->ops->master_stop(ctx);
 	ret = spu_run_fini(ctx, npc, &status);
 	spu_yield(ctx);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index e5b4dd1..227968b 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -51,9 +51,6 @@
 	DECLARE_BITMAP(bitmap, MAX_PRIO);
 	struct list_head runq[MAX_PRIO];
 	spinlock_t runq_lock;
-	struct list_head active_list[MAX_NUMNODES];
-	struct mutex active_mutex[MAX_NUMNODES];
-	int nr_active[MAX_NUMNODES];
 	int nr_waiting;
 };
 
@@ -127,7 +124,7 @@
 	ctx->policy = current->policy;
 
 	/*
-	 * A lot of places that don't hold active_mutex poke into
+	 * A lot of places that don't hold list_mutex poke into
 	 * cpus_allowed, including grab_runnable_context which
 	 * already holds the runq_lock.  So abuse runq_lock
 	 * to protect this field aswell.
@@ -141,9 +138,9 @@
 {
 	int node = ctx->spu->node;
 
-	mutex_lock(&spu_prio->active_mutex[node]);
+	mutex_lock(&cbe_spu_info[node].list_mutex);
 	__spu_update_sched_info(ctx);
-	mutex_unlock(&spu_prio->active_mutex[node]);
+	mutex_unlock(&cbe_spu_info[node].list_mutex);
 }
 
 static int __node_allowed(struct spu_context *ctx, int node)
@@ -169,56 +166,56 @@
 	return rval;
 }
 
-/**
- * spu_add_to_active_list - add spu to active list
- * @spu:	spu to add to the active list
- */
-static void spu_add_to_active_list(struct spu *spu)
-{
-	int node = spu->node;
-
-	mutex_lock(&spu_prio->active_mutex[node]);
-	spu_prio->nr_active[node]++;
-	list_add_tail(&spu->list, &spu_prio->active_list[node]);
-	mutex_unlock(&spu_prio->active_mutex[node]);
-}
-
-static void __spu_remove_from_active_list(struct spu *spu)
-{
-	list_del_init(&spu->list);
-	spu_prio->nr_active[spu->node]--;
-}
-
-/**
- * spu_remove_from_active_list - remove spu from active list
- * @spu:       spu to remove from the active list
- */
-static void spu_remove_from_active_list(struct spu *spu)
-{
-	int node = spu->node;
-
-	mutex_lock(&spu_prio->active_mutex[node]);
-	__spu_remove_from_active_list(spu);
-	mutex_unlock(&spu_prio->active_mutex[node]);
-}
-
 static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
 
-static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
 {
 	blocking_notifier_call_chain(&spu_switch_notifier,
 			    ctx ? ctx->object_id : 0, spu);
 }
 
+static void notify_spus_active(void)
+{
+	int node;
+
+	/*
+	 * Wake up the active spu_contexts.
+	 *
+	 * When the awakened processes see their "notify_active" flag is set,
+	 * they will call spu_switch_notify();
+	 */
+	for_each_online_node(node) {
+		struct spu *spu;
+
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+			if (spu->alloc_state != SPU_FREE) {
+				struct spu_context *ctx = spu->ctx;
+				set_bit(SPU_SCHED_NOTIFY_ACTIVE,
+					&ctx->sched_flags);
+				mb();
+				wake_up_all(&ctx->stop_wq);
+			}
+		}
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
+	}
+}
+
 int spu_switch_event_register(struct notifier_block * n)
 {
-	return blocking_notifier_chain_register(&spu_switch_notifier, n);
+	int ret;
+	ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
+	if (!ret)
+		notify_spus_active();
+	return ret;
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_register);
 
 int spu_switch_event_unregister(struct notifier_block * n)
 {
 	return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
 
 /**
  * spu_bind_context - bind spu context to physical spu
@@ -229,6 +226,12 @@
 {
 	pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
 		 spu->number, spu->node);
+	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
+	if (ctx->flags & SPU_CREATE_NOSCHED)
+		atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
+	if (!list_empty(&ctx->aff_list))
+		atomic_inc(&ctx->gang->aff_sched_count);
 
 	ctx->stats.slb_flt_base = spu->stats.slb_flt;
 	ctx->stats.class2_intr_base = spu->stats.class2_intr;
@@ -238,6 +241,7 @@
 	ctx->spu = spu;
 	ctx->ops = &spu_hw_ops;
 	spu->pid = current->pid;
+	spu->tgid = current->tgid;
 	spu_associate_mm(spu, ctx->owner);
 	spu->ibox_callback = spufs_ibox_callback;
 	spu->wbox_callback = spufs_wbox_callback;
@@ -251,7 +255,153 @@
 	spu_cpu_affinity_set(spu, raw_smp_processor_id());
 	spu_switch_notify(spu, ctx);
 	ctx->state = SPU_STATE_RUNNABLE;
-	spu_switch_state(spu, SPU_UTIL_SYSTEM);
+
+	spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+}
+
+/*
+ * Must be used with the list_mutex held.
+ */
+static inline int sched_spu(struct spu *spu)
+{
+	BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex));
+
+	return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED));
+}
+
+static void aff_merge_remaining_ctxs(struct spu_gang *gang)
+{
+	struct spu_context *ctx;
+
+	list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
+		if (list_empty(&ctx->aff_list))
+			list_add(&ctx->aff_list, &gang->aff_list_head);
+	}
+	gang->aff_flags |= AFF_MERGED;
+}
+
+static void aff_set_offsets(struct spu_gang *gang)
+{
+	struct spu_context *ctx;
+	int offset;
+
+	offset = -1;
+	list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+								aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		ctx->aff_offset = offset--;
+	}
+
+	offset = 0;
+	list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		ctx->aff_offset = offset++;
+	}
+
+	gang->aff_flags |= AFF_OFFSETS_SET;
+}
+
+static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff,
+		 int group_size, int lowest_offset)
+{
+	struct spu *spu;
+	int node, n;
+
+	/*
+	 * TODO: A better algorithm could be used to find a good spu to be
+	 *       used as reference location for the ctxs chain.
+	 */
+	node = cpu_to_node(raw_smp_processor_id());
+	for (n = 0; n < MAX_NUMNODES; n++, node++) {
+		node = (node < MAX_NUMNODES) ? node : 0;
+		if (!node_allowed(ctx, node))
+			continue;
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+			if ((!mem_aff || spu->has_mem_affinity) &&
+							sched_spu(spu)) {
+				mutex_unlock(&cbe_spu_info[node].list_mutex);
+				return spu;
+			}
+		}
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
+	}
+	return NULL;
+}
+
+static void aff_set_ref_point_location(struct spu_gang *gang)
+{
+	int mem_aff, gs, lowest_offset;
+	struct spu_context *ctx;
+	struct spu *tmp;
+
+	mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM;
+	lowest_offset = 0;
+	gs = 0;
+
+	list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+		gs++;
+
+	list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+								aff_list) {
+		if (&ctx->aff_list == &gang->aff_list_head)
+			break;
+		lowest_offset = ctx->aff_offset;
+	}
+
+	gang->aff_ref_spu = aff_ref_location(ctx, mem_aff, gs, lowest_offset);
+}
+
+static struct spu *ctx_location(struct spu *ref, int offset, int node)
+{
+	struct spu *spu;
+
+	spu = NULL;
+	if (offset >= 0) {
+		list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
+			BUG_ON(spu->node != node);
+			if (offset == 0)
+				break;
+			if (sched_spu(spu))
+				offset--;
+		}
+	} else {
+		list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
+			BUG_ON(spu->node != node);
+			if (offset == 0)
+				break;
+			if (sched_spu(spu))
+				offset++;
+		}
+	}
+
+	return spu;
+}
+
+/*
+ * affinity_check is called each time a context is going to be scheduled.
+ * It returns the spu ptr on which the context must run.
+ */
+static int has_affinity(struct spu_context *ctx)
+{
+	struct spu_gang *gang = ctx->gang;
+
+	if (list_empty(&ctx->aff_list))
+		return 0;
+
+	mutex_lock(&gang->aff_mutex);
+	if (!gang->aff_ref_spu) {
+		if (!(gang->aff_flags & AFF_MERGED))
+			aff_merge_remaining_ctxs(gang);
+		if (!(gang->aff_flags & AFF_OFFSETS_SET))
+			aff_set_offsets(gang);
+		aff_set_ref_point_location(gang);
+	}
+	mutex_unlock(&gang->aff_mutex);
+
+	return gang->aff_ref_spu != NULL;
 }
 
 /**
@@ -263,9 +413,13 @@
 {
 	pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
 		 spu->pid, spu->number, spu->node);
+	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
-	spu_switch_state(spu, SPU_UTIL_IDLE);
-
+ 	if (spu->ctx->flags & SPU_CREATE_NOSCHED)
+		atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
+ 	if (!list_empty(&ctx->aff_list))
+ 		if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
+ 			ctx->gang->aff_ref_spu = NULL;
 	spu_switch_notify(spu, NULL);
 	spu_unmap_mappings(ctx);
 	spu_save(&ctx->csa, spu);
@@ -278,8 +432,8 @@
 	spu->dma_callback = NULL;
 	spu_associate_mm(spu, NULL);
 	spu->pid = 0;
+	spu->tgid = 0;
 	ctx->ops = &spu_backing_ops;
-	ctx->spu = NULL;
 	spu->flags = 0;
 	spu->ctx = NULL;
 
@@ -287,6 +441,10 @@
 		(spu->stats.slb_flt - ctx->stats.slb_flt_base);
 	ctx->stats.class2_intr +=
 		(spu->stats.class2_intr - ctx->stats.class2_intr_base);
+
+	/* This maps the underlying spu state to idle */
+	spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+	ctx->spu = NULL;
 }
 
 /**
@@ -352,18 +510,41 @@
 
 static struct spu *spu_get_idle(struct spu_context *ctx)
 {
-	struct spu *spu = NULL;
-	int node = cpu_to_node(raw_smp_processor_id());
-	int n;
+	struct spu *spu;
+	int node, n;
 
+	if (has_affinity(ctx)) {
+		node = ctx->gang->aff_ref_spu->node;
+
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node);
+		if (spu && spu->alloc_state == SPU_FREE)
+			goto found;
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
+		return NULL;
+	}
+
+	node = cpu_to_node(raw_smp_processor_id());
 	for (n = 0; n < MAX_NUMNODES; n++, node++) {
 		node = (node < MAX_NUMNODES) ? node : 0;
 		if (!node_allowed(ctx, node))
 			continue;
-		spu = spu_alloc_node(node);
-		if (spu)
-			break;
+
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+			if (spu->alloc_state == SPU_FREE)
+				goto found;
+		}
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
 	}
+
+	return NULL;
+
+ found:
+	spu->alloc_state = SPU_USED;
+	mutex_unlock(&cbe_spu_info[node].list_mutex);
+	pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+	spu_init_channels(spu);
 	return spu;
 }
 
@@ -393,15 +574,15 @@
 		if (!node_allowed(ctx, node))
 			continue;
 
-		mutex_lock(&spu_prio->active_mutex[node]);
-		list_for_each_entry(spu, &spu_prio->active_list[node], list) {
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
 			struct spu_context *tmp = spu->ctx;
 
 			if (tmp->prio > ctx->prio &&
 			    (!victim || tmp->prio > victim->prio))
 				victim = spu->ctx;
 		}
-		mutex_unlock(&spu_prio->active_mutex[node]);
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
 
 		if (victim) {
 			/*
@@ -426,7 +607,11 @@
 				victim = NULL;
 				goto restart;
 			}
-			spu_remove_from_active_list(spu);
+
+			mutex_lock(&cbe_spu_info[node].list_mutex);
+			cbe_spu_info[node].nr_active--;
+			mutex_unlock(&cbe_spu_info[node].list_mutex);
+
 			spu_unbind_context(spu, victim);
 			victim->stats.invol_ctx_switch++;
 			spu->stats.invol_ctx_switch++;
@@ -455,8 +640,6 @@
  */
 int spu_activate(struct spu_context *ctx, unsigned long flags)
 {
-	spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
-
 	do {
 		struct spu *spu;
 
@@ -477,8 +660,12 @@
 		if (!spu && rt_prio(ctx->prio))
 			spu = find_victim(ctx);
 		if (spu) {
+			int node = spu->node;
+
+			mutex_lock(&cbe_spu_info[node].list_mutex);
 			spu_bind_context(spu, ctx);
-			spu_add_to_active_list(spu);
+			cbe_spu_info[node].nr_active++;
+			mutex_unlock(&cbe_spu_info[node].list_mutex);
 			return 0;
 		}
 
@@ -500,7 +687,7 @@
 	int best;
 
 	spin_lock(&spu_prio->runq_lock);
-	best = sched_find_first_bit(spu_prio->bitmap);
+	best = find_first_bit(spu_prio->bitmap, prio);
 	while (best < prio) {
 		struct list_head *rq = &spu_prio->runq[best];
 
@@ -527,11 +714,17 @@
 	if (spu) {
 		new = grab_runnable_context(max_prio, spu->node);
 		if (new || force) {
-			spu_remove_from_active_list(spu);
+			int node = spu->node;
+
+			mutex_lock(&cbe_spu_info[node].list_mutex);
 			spu_unbind_context(spu, ctx);
+			spu->alloc_state = SPU_FREE;
+			cbe_spu_info[node].nr_active--;
+			mutex_unlock(&cbe_spu_info[node].list_mutex);
+
 			ctx->stats.vol_ctx_switch++;
 			spu->stats.vol_ctx_switch++;
-			spu_free(spu);
+
 			if (new)
 				wake_up(&new->stop_wq);
 		}
@@ -550,21 +743,11 @@
  */
 void spu_deactivate(struct spu_context *ctx)
 {
-	/*
-	 * We must never reach this for a nosched context,
-	 * but handle the case gracefull instead of panicing.
-	 */
-	if (ctx->flags & SPU_CREATE_NOSCHED) {
-		WARN_ON(1);
-		return;
-	}
-
 	__spu_deactivate(ctx, 1, MAX_PRIO);
-	spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
 }
 
 /**
- * spu_yield -  yield a physical spu if others are waiting
+ * spu_yield -	yield a physical spu if others are waiting
  * @ctx:	spu context to yield
  *
  * Check if there is a higher priority context waiting and if yes
@@ -575,17 +758,12 @@
 {
 	if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
 		mutex_lock(&ctx->state_mutex);
-		if (__spu_deactivate(ctx, 0, MAX_PRIO))
-			spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
-		else {
-			spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
-			spu_switch_state(ctx->spu, SPU_UTIL_USER);
-		}
+		__spu_deactivate(ctx, 0, MAX_PRIO);
 		mutex_unlock(&ctx->state_mutex);
 	}
 }
 
-static void spusched_tick(struct spu_context *ctx)
+static noinline void spusched_tick(struct spu_context *ctx)
 {
 	if (ctx->flags & SPU_CREATE_NOSCHED)
 		return;
@@ -596,7 +774,7 @@
 		return;
 
 	/*
-	 * Unfortunately active_mutex ranks outside of state_mutex, so
+	 * Unfortunately list_mutex ranks outside of state_mutex, so
 	 * we have to trylock here.  If we fail give the context another
 	 * tick and try again.
 	 */
@@ -606,12 +784,11 @@
 
 		new = grab_runnable_context(ctx->prio + 1, spu->node);
 		if (new) {
-
-			__spu_remove_from_active_list(spu);
 			spu_unbind_context(spu, ctx);
 			ctx->stats.invol_ctx_switch++;
 			spu->stats.invol_ctx_switch++;
-			spu_free(spu);
+			spu->alloc_state = SPU_FREE;
+			cbe_spu_info[spu->node].nr_active--;
 			wake_up(&new->stop_wq);
 			/*
 			 * We need to break out of the wait loop in
@@ -632,7 +809,7 @@
  *
  * Return the number of tasks currently running or waiting to run.
  *
- * Note that we don't take runq_lock / active_mutex here.  Reading
+ * Note that we don't take runq_lock / list_mutex here.  Reading
  * a single 32bit value is atomic on powerpc, and we don't care
  * about memory ordering issues here.
  */
@@ -641,7 +818,7 @@
 	int nr_active = 0, node;
 
 	for (node = 0; node < MAX_NUMNODES; node++)
-		nr_active += spu_prio->nr_active[node];
+		nr_active += cbe_spu_info[node].nr_active;
 	nr_active += spu_prio->nr_waiting;
 
 	return nr_active;
@@ -681,19 +858,18 @@
 
 static int spusched_thread(void *unused)
 {
-	struct spu *spu, *next;
+	struct spu *spu;
 	int node;
 
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 		for (node = 0; node < MAX_NUMNODES; node++) {
-			mutex_lock(&spu_prio->active_mutex[node]);
-			list_for_each_entry_safe(spu, next,
-						 &spu_prio->active_list[node],
-						 list)
-				spusched_tick(spu->ctx);
-			mutex_unlock(&spu_prio->active_mutex[node]);
+			mutex_lock(&cbe_spu_info[node].list_mutex);
+			list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+				if (spu->ctx)
+					spusched_tick(spu->ctx);
+			mutex_unlock(&cbe_spu_info[node].list_mutex);
 		}
 	}
 
@@ -751,10 +927,9 @@
 		INIT_LIST_HEAD(&spu_prio->runq[i]);
 		__clear_bit(i, spu_prio->bitmap);
 	}
-	__set_bit(MAX_PRIO, spu_prio->bitmap);
 	for (i = 0; i < MAX_NUMNODES; i++) {
-		mutex_init(&spu_prio->active_mutex[i]);
-		INIT_LIST_HEAD(&spu_prio->active_list[i]);
+		mutex_init(&cbe_spu_info[i].list_mutex);
+		INIT_LIST_HEAD(&cbe_spu_info[i].spus);
 	}
 	spin_lock_init(&spu_prio->runq_lock);
 
@@ -783,9 +958,9 @@
 	return err;
 }
 
-void __exit spu_sched_exit(void)
+void spu_sched_exit(void)
 {
-	struct spu *spu, *tmp;
+	struct spu *spu;
 	int node;
 
 	remove_proc_entry("spu_loadavg", NULL);
@@ -794,13 +969,11 @@
 	kthread_stop(spusched_task);
 
 	for (node = 0; node < MAX_NUMNODES; node++) {
-		mutex_lock(&spu_prio->active_mutex[node]);
-		list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
-					 list) {
-			list_del_init(&spu->list);
-			spu_free(spu);
-		}
-		mutex_unlock(&spu_prio->active_mutex[node]);
+		mutex_lock(&cbe_spu_info[node].list_mutex);
+		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+			if (spu->alloc_state != SPU_FREE)
+				spu->alloc_state = SPU_FREE;
+		mutex_unlock(&cbe_spu_info[node].list_mutex);
 	}
 	kfree(spu_prio);
 }
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c
index 4e19ed7..21a9c95 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_restore.c
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c
@@ -84,13 +84,13 @@
 	unsigned int decr_running;
 	unsigned int decr;
 
-	/* Restore, Step 6:
+	/* Restore, Step 6(moved):
 	 *    If the LSCSA "decrementer running" flag is set
 	 *    then write the SPU_WrDec channel with the
 	 *    decrementer value from LSCSA.
 	 */
 	offset = LSCSA_QW_OFFSET(decr_status);
-	decr_running = regs_spill[offset].slot[0];
+	decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
 	if (decr_running) {
 		offset = LSCSA_QW_OFFSET(decr);
 		decr = regs_spill[offset].slot[0];
@@ -318,10 +318,10 @@
 	build_dma_list(lscsa_ea);	/* Step 3.  */
 	restore_upper_240kb(lscsa_ea);	/* Step 4.  */
 					/* Step 5: done by 'exit'. */
-	restore_decr();			/* Step 6. */
 	enqueue_putllc(lscsa_ea);	/* Step 7. */
 	set_tag_update();		/* Step 8. */
 	read_tag_status();		/* Step 9. */
+	restore_decr();			/* moved Step 6. */
 	read_llar_status();		/* Step 10. */
 	write_ppu_mb();			/* Step 11. */
 	write_ppuint_mb();		/* Step 12. */
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
index 15183d2..f383b02 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
@@ -10,7 +10,7 @@
 0x24fd8081,
 0x1cd80081,
 0x33001180,
-0x42030003,
+0x42034003,
 0x33800284,
 0x1c010204,
 0x40200000,
@@ -24,22 +24,22 @@
 0x23fffd84,
 0x1c100183,
 0x217ffa85,
-0x3080a000,
-0x3080a201,
-0x3080a402,
-0x3080a603,
-0x3080a804,
-0x3080aa05,
-0x3080ac06,
-0x3080ae07,
-0x3080b008,
-0x3080b209,
-0x3080b40a,
-0x3080b60b,
-0x3080b80c,
-0x3080ba0d,
-0x3080bc0e,
-0x3080be0f,
+0x3080b000,
+0x3080b201,
+0x3080b402,
+0x3080b603,
+0x3080b804,
+0x3080ba05,
+0x3080bc06,
+0x3080be07,
+0x3080c008,
+0x3080c209,
+0x3080c40a,
+0x3080c60b,
+0x3080c80c,
+0x3080ca0d,
+0x3080cc0e,
+0x3080ce0f,
 0x00003ffc,
 0x00000000,
 0x00000000,
@@ -48,19 +48,18 @@
 0x3ec00083,
 0xb0a14103,
 0x01a00204,
-0x3ec10082,
-0x4202800e,
-0x04000703,
-0xb0a14202,
-0x21a00803,
-0x3fbf028d,
-0x3f20068d,
-0x3fbe0682,
+0x3ec10083,
+0x4202c002,
+0xb0a14203,
+0x21a00802,
+0x3fbf028a,
+0x3f20050a,
+0x3fbe0502,
 0x3fe30102,
 0x21a00882,
-0x3f82028f,
-0x3fe3078f,
-0x3fbf0784,
+0x3f82028b,
+0x3fe3058b,
+0x3fbf0584,
 0x3f200204,
 0x3fbe0204,
 0x3fe30204,
@@ -75,254 +74,287 @@
 0x21a00083,
 0x40800082,
 0x21a00b02,
-0x10002818,
-0x42a00002,
-0x32800007,
-0x4207000c,
-0x18008208,
-0x40a0000b,
-0x4080020a,
-0x40800709,
-0x00200000,
-0x42070002,
-0x3ac30384,
+0x10002612,
+0x42a00003,
+0x42074006,
+0x1800c204,
+0x40a00008,
+0x40800789,
+0x1c010305,
+0x34000302,
 0x1cffc489,
-0x00200000,
-0x18008383,
-0x38830382,
-0x4cffc486,
-0x3ac28185,
-0xb0408584,
-0x28830382,
-0x1c020387,
-0x38828182,
-0xb0408405,
-0x1802c408,
-0x28828182,
-0x217ff886,
-0x04000583,
-0x21a00803,
-0x3fbe0682,
-0x3fe30102,
-0x04000106,
-0x21a00886,
-0x04000603,
-0x21a00903,
-0x40803c02,
-0x21a00982,
-0x40800003,
-0x04000184,
-0x21a00a04,
+0x3ec00303,
+0x3ec00287,
+0xb0408403,
+0x24000302,
+0x34000282,
+0x1c020306,
+0xb0408207,
+0x18020204,
+0x24000282,
+0x217ffa09,
+0x04000402,
+0x21a00802,
+0x3fbe0504,
+0x3fe30204,
+0x21a00884,
+0x42074002,
+0x21a00902,
+0x40803c03,
+0x21a00983,
+0x04000485,
+0x21a00a05,
 0x40802202,
 0x21a00a82,
-0x42028005,
-0x34208702,
-0x21002282,
-0x21a00804,
-0x21a00886,
-0x3fbf0782,
+0x21a00805,
+0x21a00884,
+0x3fbf0582,
 0x3f200102,
 0x3fbe0102,
 0x3fe30102,
 0x21a00902,
 0x40804003,
 0x21a00983,
-0x21a00a04,
+0x21a00a05,
 0x40805a02,
 0x21a00a82,
 0x40800083,
 0x21a00b83,
 0x01a00c02,
-0x01a00d83,
-0x3420c282,
+0x30809c03,
+0x34000182,
+0x14004102,
+0x21002082,
+0x01a00d82,
+0x3080a003,
+0x34000182,
 0x21a00e02,
-0x34210283,
-0x21a00f03,
-0x34200284,
-0x77400200,
-0x3421c282,
+0x3080a203,
+0x34000182,
+0x21a00f02,
+0x3080a403,
+0x34000182,
+0x77400100,
+0x3080a603,
+0x34000182,
 0x21a00702,
-0x34218283,
-0x21a00083,
-0x34214282,
+0x3080a803,
+0x34000182,
+0x21a00082,
+0x3080aa03,
+0x34000182,
 0x21a00b02,
-0x4200480c,
-0x00200000,
-0x1c010286,
-0x34220284,
-0x34220302,
-0x0f608203,
-0x5c024204,
-0x3b81810b,
-0x42013c02,
-0x00200000,
-0x18008185,
-0x38808183,
-0x3b814182,
-0x21004e84,
+0x4020007f,
+0x3080ae02,
+0x42004805,
+0x3080ac04,
+0x34000103,
+0x34000202,
+0x1cffc183,
+0x3b810106,
+0x0f608184,
+0x42013802,
+0x5c020183,
+0x38810102,
+0x3b810102,
+0x21000e83,
 0x4020007f,
 0x35000100,
-0x000004e0,
-0x000002a0,
-0x000002e8,
-0x00000428,
+0x00000470,
+0x000002f8,
+0x00000430,
 0x00000360,
-0x000002e8,
-0x000004a0,
-0x00000468,
+0x000002f8,
 0x000003c8,
+0x000004a8,
+0x00000298,
 0x00000360,
-0x409ffe02,
-0x30801203,
-0x40800204,
-0x3ec40085,
-0x10009c09,
-0x3ac10606,
-0xb060c105,
-0x4020007f,
-0x4020007f,
-0x20801203,
-0x38810602,
-0xb0408586,
-0x28810602,
-0x32004180,
-0x34204702,
-0x21a00382,
-0x4020007f,
-0x327fdc80,
-0x409ffe02,
-0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
 0x00200000,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x409ffe02,
+0x30801203,
+0x40800208,
+0x3ec40084,
+0x40800407,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
+0x38820282,
 0x41004003,
-0x38810602,
-0x4020007f,
-0xb0408188,
-0x4020007f,
-0x28810602,
-0x41201002,
-0x38814603,
-0x10009c09,
-0xb060c109,
-0x4020007f,
-0x28814603,
-0x41193f83,
-0x38818602,
-0x60ffc003,
-0xb040818a,
-0x28818602,
-0x32003080,
-0x409ffe02,
-0x30801203,
-0x40800204,
-0x3ec40087,
-0x41201008,
-0x10009c14,
-0x40800405,
-0x3ac10609,
-0x40800606,
-0x3ac1460a,
-0xb060c107,
-0x3ac1860b,
-0x20801203,
-0x38810602,
-0xb0408409,
-0x28810602,
-0x38814603,
-0xb060c40a,
-0x4020007f,
-0x28814603,
-0x41193f83,
-0x38818602,
-0x60ffc003,
-0xb040818b,
-0x28818602,
-0x32002380,
-0x409ffe02,
-0x30801204,
-0x40800205,
-0x3ec40083,
-0x40800406,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x41004002,
-0x20801204,
-0x4020007f,
-0x38814603,
-0x10009c0b,
-0xb060c107,
-0x4020007f,
-0x4020007f,
-0x28814603,
-0x38818602,
-0x4020007f,
-0x4020007f,
-0xb0408588,
-0x28818602,
-0x4020007f,
-0x32001780,
-0x409ffe02,
-0x1000640e,
-0x40800204,
-0x30801203,
-0x40800405,
-0x3ec40087,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
-0x20801203,
-0x413d8003,
-0x38810602,
-0x4020007f,
-0x327fd780,
-0x409ffe02,
-0x10007f0c,
-0x40800205,
-0x30801204,
-0x40800406,
-0x3ec40083,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x413d8002,
-0x20801204,
-0x38814603,
-0x4020007f,
-0x327feb80,
-0x409ffe02,
-0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x1000650a,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
-0x20801203,
-0x38810602,
-0xb0408588,
-0x4020007f,
-0x327fc980,
+0xb0408189,
+0x28820282,
+0x3881c282,
+0xb0408304,
+0x2881c282,
 0x00400000,
 0x40800003,
-0x4020007f,
 0x35000000,
+0x30809e03,
+0x34000182,
+0x21a00382,
+0x4020007f,
+0x327fde00,
+0x409ffe02,
+0x30801203,
+0x40800206,
+0x3ec40084,
+0x40800407,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
+0x20801203,
+0x38818282,
+0x41004003,
+0xb040818a,
+0x10005b0b,
+0x41201003,
+0x28818282,
+0x3881c282,
+0xb0408184,
+0x41193f83,
+0x60ffc003,
+0x2881c282,
+0x38820282,
+0xb0408189,
+0x28820282,
+0x327fef80,
+0x409ffe02,
+0x30801203,
+0x40800207,
+0x3ec40086,
+0x4120100b,
+0x10005b14,
+0x40800404,
+0x3ac1c289,
+0x40800608,
+0xb060c106,
+0x3ac10286,
+0x3ac2028a,
+0x20801203,
+0x3881c282,
+0x41193f83,
+0x60ffc003,
+0xb0408589,
+0x2881c282,
+0x38810282,
+0xb0408586,
+0x28810282,
+0x38820282,
+0xb040818a,
+0x28820282,
+0x4020007f,
+0x327fe280,
+0x409ffe02,
+0x30801203,
+0x40800207,
+0x3ec40084,
+0x40800408,
+0x10005b14,
+0x40800609,
+0x3ac1c28a,
+0x3ac2028b,
+0xb060c104,
+0x3ac24284,
+0x20801203,
+0x41201003,
+0x3881c282,
+0xb040830a,
+0x2881c282,
+0x38820282,
+0xb040818b,
+0x41193f83,
+0x60ffc003,
+0x28820282,
+0x38824282,
+0xb0408184,
+0x28824282,
+0x4020007f,
+0x327fd580,
+0x409ffe02,
+0x1000658e,
+0x40800206,
+0x30801203,
+0x40800407,
+0x3ec40084,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
+0x20801203,
+0x413d8003,
+0x38818282,
+0x4020007f,
+0x327fd800,
+0x409ffe03,
+0x30801202,
+0x40800207,
+0x3ec40084,
+0x10005b09,
+0x3ac1c288,
+0xb0408184,
+0x4020007f,
+0x4020007f,
+0x20801202,
+0x3881c282,
+0xb0408308,
+0x2881c282,
+0x327fc680,
+0x409ffe02,
+0x1000588b,
+0x40800208,
+0x30801203,
+0x40800407,
+0x3ec40084,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
+0x20801203,
+0x413d8003,
+0x38820282,
+0x327fbd80,
+0x00200000,
+0x00000da0,
 0x00000000,
 0x00000000,
 0x00000000,
+0x00000d90,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000db0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dc0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d80,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000df0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000de0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dd0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000e04,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000e00,
+0x00000000,
+0x00000000,
 0x00000000,
 0x00000000,
 0x00000000,
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 08b3530..8b20c0c 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -40,17 +40,13 @@
 struct spu_context_ops;
 struct spu_gang;
 
-/*
- * This is the state for spu utilization reporting to userspace.
- * Because this state is visible to userspace it must never change and needs
- * to be kept strictly separate from any internal state kept by the kernel.
- */
-enum spuctx_execution_state {
-	SPUCTX_UTIL_USER = 0,
-	SPUCTX_UTIL_SYSTEM,
-	SPUCTX_UTIL_IOWAIT,
-	SPUCTX_UTIL_LOADED,
-	SPUCTX_UTIL_MAX
+enum {
+	SPU_SCHED_WAS_ACTIVE,	/* was active upon spu_acquire_saved()  */
+};
+
+/* ctx->sched_flags */
+enum {
+	SPU_SCHED_NOTIFY_ACTIVE,
 };
 
 struct spu_context {
@@ -89,6 +85,8 @@
 
 	struct list_head gang_list;
 	struct spu_gang *gang;
+	struct kref *prof_priv_kref;
+	void ( * prof_priv_release) (struct kref *kref);
 
 	/* owner thread */
 	pid_t tid;
@@ -104,9 +102,9 @@
 	/* statistics */
 	struct {
 		/* updates protected by ctx->state_mutex */
-		enum spuctx_execution_state execution_state;
-		unsigned long tstamp;		/* time of last ctx switch */
-		unsigned long times[SPUCTX_UTIL_MAX];
+		enum spu_utilization_state util_state;
+		unsigned long long tstamp;	/* time of last state switch */
+		unsigned long long times[SPU_UTIL_MAX];
 		unsigned long long vol_ctx_switch;
 		unsigned long long invol_ctx_switch;
 		unsigned long long min_flt;
@@ -118,6 +116,10 @@
 		unsigned long long class2_intr_base; /* # at last ctx switch */
 		unsigned long long libassist;
 	} stats;
+
+	struct list_head aff_list;
+	int aff_head;
+	int aff_offset;
 };
 
 struct spu_gang {
@@ -125,8 +127,19 @@
 	struct mutex mutex;
 	struct kref kref;
 	int contexts;
+
+	struct spu_context *aff_ref_ctx;
+	struct list_head aff_list_head;
+	struct mutex aff_mutex;
+	int aff_flags;
+	struct spu *aff_ref_spu;
+	atomic_t aff_sched_count;
 };
 
+/* Flag bits for spu_gang aff_flags */
+#define AFF_OFFSETS_SET		1
+#define AFF_MERGED		2
+
 struct mfc_dma_command {
 	int32_t pad;	/* reserved */
 	uint32_t lsa;	/* local storage address */
@@ -190,10 +203,9 @@
 extern struct tree_descr spufs_dir_nosched_contents[];
 
 /* system call implementation */
-long spufs_run_spu(struct file *file,
-		   struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create(struct nameidata *nd,
-			 unsigned int flags, mode_t mode);
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create(struct nameidata *nd, unsigned int flags,
+			mode_t mode, struct file *filp);
 extern const struct file_operations spufs_context_fops;
 
 /* gang management */
@@ -206,6 +218,9 @@
 /* fault handling */
 int spufs_handle_class1(struct spu_context *ctx);
 
+/* affinity */
+struct spu *affinity_check(struct spu_context *ctx);
+
 /* context management */
 extern atomic_t nr_spu_contexts;
 static inline void spu_acquire(struct spu_context *ctx)
@@ -227,15 +242,17 @@
 void spu_forget(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
 void spu_acquire_saved(struct spu_context *ctx);
+void spu_release_saved(struct spu_context *ctx);
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
 void spu_yield(struct spu_context *ctx);
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
 void spu_set_timeslice(struct spu_context *ctx);
 void spu_update_sched_info(struct spu_context *ctx);
 void __spu_update_sched_info(struct spu_context *ctx);
 int __init spu_sched_init(void);
-void __exit spu_sched_exit(void);
+void spu_sched_exit(void);
 
 extern char *isolated_loader;
 
@@ -293,30 +310,34 @@
  * line.
  */
 static inline void spuctx_switch_state(struct spu_context *ctx,
-		enum spuctx_execution_state new_state)
+		enum spu_utilization_state new_state)
 {
+	unsigned long long curtime;
+	signed long long delta;
+	struct timespec ts;
+	struct spu *spu;
+	enum spu_utilization_state old_state;
+
+	ktime_get_ts(&ts);
+	curtime = timespec_to_ns(&ts);
+	delta = curtime - ctx->stats.tstamp;
+
 	WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+	WARN_ON(delta < 0);
 
-	if (ctx->stats.execution_state != new_state) {
-		unsigned long curtime = jiffies;
+	spu = ctx->spu;
+	old_state = ctx->stats.util_state;
+	ctx->stats.util_state = new_state;
+	ctx->stats.tstamp = curtime;
 
-		ctx->stats.times[ctx->stats.execution_state] +=
-				 curtime - ctx->stats.tstamp;
-		ctx->stats.tstamp = curtime;
-		ctx->stats.execution_state = new_state;
-	}
-}
-
-static inline void spu_switch_state(struct spu *spu,
-		enum spuctx_execution_state new_state)
-{
-	if (spu->stats.utilization_state != new_state) {
-		unsigned long curtime = jiffies;
-
-		spu->stats.times[spu->stats.utilization_state] +=
-				 curtime - spu->stats.tstamp;
+	/*
+	 * Update the physical SPU utilization statistics.
+	 */
+	if (spu) {
+		ctx->stats.times[old_state] += delta;
+		spu->stats.times[old_state] += delta;
+		spu->stats.util_state = new_state;
 		spu->stats.tstamp = curtime;
-		spu->stats.utilization_state = new_state;
 	}
 }
 
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 9c506ba..27ffdae 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -180,7 +180,7 @@
 	case MFC_CNTL_SUSPEND_COMPLETE:
 		if (csa) {
 			csa->priv2.mfc_control_RW =
-				in_be64(&priv2->mfc_control_RW) |
+				MFC_CNTL_SUSPEND_MASK |
 				MFC_CNTL_SUSPEND_DMA_QUEUE;
 		}
 		break;
@@ -190,9 +190,7 @@
 				  MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
 				 MFC_CNTL_SUSPEND_COMPLETE);
 		if (csa) {
-			csa->priv2.mfc_control_RW =
-				in_be64(&priv2->mfc_control_RW) &
-				~MFC_CNTL_SUSPEND_DMA_QUEUE;
+			csa->priv2.mfc_control_RW = 0;
 		}
 		break;
 	}
@@ -251,16 +249,8 @@
 	 *     Read MFC_CNTL[Ds].  Update saved copy of
 	 *     CSA.MFC_CNTL[Ds].
 	 */
-	if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
-		csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
-		csa->suspend_time = get_cycles();
-		out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
-		eieio();
-		csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
-		eieio();
-	} else {
-		csa->priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
-	}
+	csa->priv2.mfc_control_RW |=
+		in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING;
 }
 
 static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
@@ -271,7 +261,8 @@
 	 *     Write MFC_CNTL[Dh] set to a '1' to halt
 	 *     the decrementer.
 	 */
-	out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+	out_be64(&priv2->mfc_control_RW,
+		 MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK);
 	eieio();
 }
 
@@ -615,7 +606,7 @@
 static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
-	u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
 	int i;
 
 	/* Save, Step 42:
@@ -626,7 +617,7 @@
 	csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
 
 	/* Save the following CH: [0,3,4,24,25,27] */
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
 		idx = ch_indices[i];
 		out_be64(&priv2->spu_chnlcntptr_RW, idx);
 		eieio();
@@ -983,13 +974,13 @@
 	 */
 }
 
-static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+static inline void suspend_mfc_and_halt_decr(struct spu_state *csa,
+		struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
 
 	/* Restore, Step 7:
-	 * Restore, Step 47.
-	 *     Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+	 *     Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend
 	 *     the queue and halt the decrementer.
 	 */
 	out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
@@ -1090,7 +1081,7 @@
 static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
-	u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
 	u64 idx;
 	int i;
 
@@ -1102,7 +1093,7 @@
 	out_be64(&priv2->spu_chnldata_RW, 0UL);
 
 	/* Reset the following CH: [0,3,4,24,25,27] */
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
 		idx = ch_indices[i];
 		out_be64(&priv2->spu_chnlcntptr_RW, idx);
 		eieio();
@@ -1289,7 +1280,15 @@
 		cycles_t resume_time = get_cycles();
 		cycles_t delta_time = resume_time - csa->suspend_time;
 
+		csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
+		if (csa->lscsa->decr.slot[0] < delta_time) {
+			csa->lscsa->decr_status.slot[0] |=
+				 SPU_DECR_STATUS_WRAPPED;
+		}
+
 		csa->lscsa->decr.slot[0] -= delta_time;
+	} else {
+		csa->lscsa->decr_status.slot[0] = 0;
 	}
 }
 
@@ -1398,6 +1397,18 @@
 	send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
 }
 
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+	struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+	/* Restore, Step 47.
+	 *     Write MFC_Cntl[Sc,Sm]='1','0' to suspend
+	 *     the queue.
+	 */
+	out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
+	eieio();
+}
+
 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
 {
 	/* Restore, Step 49:
@@ -1548,10 +1559,10 @@
 	 *     "wrapped" flag is set, OR in a '1' to
 	 *     CSA.SPU_Event_Status[Tm].
 	 */
-	if (csa->lscsa->decr_status.slot[0] == 1) {
+	if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) {
 		csa->spu_chnldata_RW[0] |= 0x20;
 	}
-	if ((csa->lscsa->decr_status.slot[0] == 1) &&
+	if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) &&
 	    (csa->spu_chnlcnt_RW[0] == 0 &&
 	     ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
 	     ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
@@ -1562,18 +1573,13 @@
 static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
 {
 	struct spu_priv2 __iomem *priv2 = spu->priv2;
-	u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+	u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
 	int i;
 
 	/* Restore, Step 59:
+	 *	Restore the following CH: [0,3,4,24,25,27]
 	 */
-
-	/* Restore CH 1 without count */
-	out_be64(&priv2->spu_chnlcntptr_RW, 1);
-	out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]);
-
-	/* Restore the following CH: [0,3,4,24,25,27] */
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
 		idx = ch_indices[i];
 		out_be64(&priv2->spu_chnlcntptr_RW, idx);
 		eieio();
@@ -1932,7 +1938,7 @@
 	set_switch_pending(prev, spu);	        /* Step 5.  */
 	stop_spu_isolate(spu);			/* NEW.     */
 	remove_other_spu_access(prev, spu);	/* Step 6.  */
-	suspend_mfc(prev, spu);	                /* Step 7.  */
+	suspend_mfc_and_halt_decr(prev, spu);	/* Step 7.  */
 	wait_suspend_mfc_complete(prev, spu);	/* Step 8.  */
 	if (!suspend_spe(prev, spu))	        /* Step 9.  */
 		clear_spu_status(prev, spu);	/* Step 10. */
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 8e37bdf..43f0fb8 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -47,7 +47,7 @@
 		goto out;
 
 	i = SPUFS_I(filp->f_path.dentry->d_inode);
-	ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+	ret = spufs_run_spu(i->i_ctx, &npc, &status);
 
 	if (put_user(npc, unpc))
 		ret = -EFAULT;
@@ -76,8 +76,8 @@
 }
 #endif
 
-asmlinkage long sys_spu_create(const char __user *pathname,
-					unsigned int flags, mode_t mode)
+asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags,
+				mode_t mode, struct file *neighbor)
 {
 	char *tmp;
 	int ret;
@@ -90,7 +90,7 @@
 		ret = path_lookup(tmp, LOOKUP_PARENT|
 				LOOKUP_OPEN|LOOKUP_CREATE, &nd);
 		if (!ret) {
-			ret = spufs_create(&nd, flags, mode);
+			ret = spufs_create(&nd, flags, mode, neighbor);
 			path_release(&nd);
 		}
 		putname(tmp);
@@ -99,8 +99,32 @@
 	return ret;
 }
 
+#ifndef MODULE
+asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
+				mode_t mode, int neighbor_fd)
+{
+	int fput_needed;
+	struct file *neighbor;
+	long ret;
+
+	if (flags & SPU_CREATE_AFFINITY_SPU) {
+		ret = -EBADF;
+		neighbor = fget_light(neighbor_fd, &fput_needed);
+		if (neighbor) {
+			ret = do_spu_create(pathname, flags, mode, neighbor);
+			fput_light(neighbor, fput_needed);
+		}
+	}
+	else {
+		ret = do_spu_create(pathname, flags, mode, NULL);
+	}
+
+	return ret;
+}
+#endif
+
 struct spufs_calls spufs_calls = {
-	.create_thread = sys_spu_create,
+	.create_thread = do_spu_create,
 	.spu_run = do_spu_run,
 	.owner = THIS_MODULE,
 };
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index bec7726..2d12f77 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -59,7 +59,7 @@
 config MV64X60
 	bool
 	select PPC_INDIRECT_PCI
-	select CONFIG_CHECK_CACHE_COHERENCY
+	select CHECK_CACHE_COHERENCY
 
 config MPC10X_OPENPIC
 	bool
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index a05079b..d4fc74f 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -102,4 +102,40 @@
 	depends on PPC_PS3
 	tristate
 
+config PS3_DISK
+	tristate "PS3 Disk Storage Driver"
+	depends on PPC_PS3 && BLOCK
+	select PS3_STORAGE
+	help
+	  Include support for the PS3 Disk Storage.
+
+	  This support is required to access the PS3 hard disk.
+	  In general, all users will say Y or M.
+
+config PS3_ROM
+	tristate "PS3 BD/DVD/CD-ROM Storage Driver"
+	depends on PPC_PS3 && SCSI
+	select PS3_STORAGE
+	help
+	  Include support for the PS3 ROM Storage.
+
+	  This support is required to access the PS3 BD/DVD/CD-ROM drive.
+	  In general, all users will say Y or M.
+	  Also make sure to say Y or M to "SCSI CDROM support" later.
+
+config PS3_FLASH
+	tristate "PS3 FLASH ROM Storage Driver"
+	depends on PPC_PS3
+	select PS3_STORAGE
+	help
+	  Include support for the PS3 FLASH ROM Storage.
+
+	  This support is required to access the PS3 FLASH ROM, which
+	  contains the boot loader and some boot options.
+	  In general, all users will say Y or M.
+
+	  As this driver needs a fixed buffer of 256 KiB of memory, it can
+	  be disabled on the kernel command line using "ps3flash=off", to
+	  not allocate this fixed buffer.
+
 endmenu
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 29bf83b..8b18a1c 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -66,24 +66,13 @@
  * device-tree/ibm,hypertas-functions.  Ultimately this functionality may
  * be moved into prom.c prom_init().
  */
-void __init fw_feature_init(void)
+void __init fw_feature_init(const char *hypertas, unsigned long len)
 {
-	struct device_node *dn;
-	const char *hypertas, *s;
-	int len, i;
+	const char *s;
+	int i;
 
 	DBG(" -> fw_feature_init()\n");
 
-	dn = of_find_node_by_path("/rtas");
-	if (dn == NULL) {
-		printk(KERN_ERR "WARNING! Cannot find RTAS in device-tree!\n");
-		goto out;
-	}
-
-	hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
-	if (hypertas == NULL)
-		goto out;
-
 	for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
 		for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
 			/* check value against table of strings */
@@ -98,7 +87,5 @@
 		}
 	}
 
-out:
-	of_node_put(dn);
 	DBG(" <- fw_feature_init()\n");
 }
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 61e19f7..61136d0 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -10,7 +10,7 @@
 #ifndef _PSERIES_PSERIES_H
 #define _PSERIES_PSERIES_H
 
-extern void __init fw_feature_init(void);
+extern void __init fw_feature_init(const char *hypertas, unsigned long len);
 
 struct pt_regs;
 
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 59e69f0..f0b7146 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -320,8 +320,6 @@
 {
 	DBG(" -> pSeries_init_early()\n");
 
-	fw_feature_init();
-
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 		find_udbg_vterm();
 
@@ -343,14 +341,21 @@
 					 const char *uname, int depth,
 					 void *data)
 {
+	const char *hypertas;
+	unsigned long len;
+
 	if (depth != 1 ||
 	    (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
- 		return 0;
+		return 0;
 
-	if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
- 		powerpc_firmware_features |= FW_FEATURE_LPAR;
+	hypertas = of_get_flat_dt_prop(node, "ibm,hypertas-functions", &len);
+	if (!hypertas)
+		return 1;
 
- 	return 1;
+	powerpc_firmware_features |= FW_FEATURE_LPAR;
+	fw_feature_init(hypertas, len);
+
+	return 1;
 }
 
 static int __init pSeries_probe(void)
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f65078c..484eb4e 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -17,6 +17,7 @@
 mv64x60-$(CONFIG_PCI)		+= mv64x60_pci.o
 obj-$(CONFIG_MV64X60)		+= $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc_cmos_setup.o
+obj-$(CONFIG_AXON_RAM)		+= axonram.o
 
 # contains only the suspend handler for time
 ifeq ($(CONFIG_RTC_CLASS),)
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
new file mode 100644
index 0000000..2326d5d
--- /dev/null
+++ b/arch/powerpc/sysdev/axonram.c
@@ -0,0 +1,381 @@
+/*
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2006
+ *
+ * Author: Maxim Shchetynin <maxim@de.ibm.com>
+ *
+ * Axon DDR2 device driver.
+ * It registers one block device per Axon's DDR2 memory bank found on a system.
+ * Block devices are called axonram?, their major and minor numbers are
+ * available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+
+#define AXON_RAM_MODULE_NAME		"axonram"
+#define AXON_RAM_DEVICE_NAME		"axonram"
+#define AXON_RAM_MINORS_PER_DISK	16
+#define AXON_RAM_BLOCK_SHIFT		PAGE_SHIFT
+#define AXON_RAM_BLOCK_SIZE		1 << AXON_RAM_BLOCK_SHIFT
+#define AXON_RAM_SECTOR_SHIFT		9
+#define AXON_RAM_SECTOR_SIZE		1 << AXON_RAM_SECTOR_SHIFT
+#define AXON_RAM_IRQ_FLAGS		IRQF_SHARED | IRQF_TRIGGER_RISING
+
+struct axon_ram_bank {
+	struct of_device	*device;
+	struct gendisk		*disk;
+	unsigned int		irq_correctable;
+	unsigned int		irq_uncorrectable;
+	unsigned long		ph_addr;
+	unsigned long		io_addr;
+	unsigned long		size;
+	unsigned long		ecc_counter;
+};
+
+static ssize_t
+axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct of_device *device = to_of_device(dev);
+	struct axon_ram_bank *bank = device->dev.platform_data;
+
+	BUG_ON(!bank);
+
+	return sprintf(buf, "%ld\n", bank->ecc_counter);
+}
+
+static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL);
+
+/**
+ * axon_ram_irq_handler - interrupt handler for Axon RAM ECC
+ * @irq: interrupt ID
+ * @dev: pointer to of_device
+ */
+static irqreturn_t
+axon_ram_irq_handler(int irq, void *dev)
+{
+	struct of_device *device = dev;
+	struct axon_ram_bank *bank = device->dev.platform_data;
+
+	BUG_ON(!bank);
+
+	if (irq == bank->irq_correctable) {
+		dev_err(&device->dev, "Correctable memory error occured\n");
+		bank->ecc_counter++;
+		return IRQ_HANDLED;
+	} else if (irq == bank->irq_uncorrectable) {
+		dev_err(&device->dev, "Uncorrectable memory error occured\n");
+		panic("Critical ECC error on %s", device->node->full_name);
+	}
+
+	return IRQ_NONE;
+}
+
+/**
+ * axon_ram_make_request - make_request() method for block device
+ * @queue, @bio: see blk_queue_make_request()
+ */
+static int
+axon_ram_make_request(struct request_queue *queue, struct bio *bio)
+{
+	struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
+	unsigned long phys_mem, phys_end;
+	void *user_mem;
+	struct bio_vec *vec;
+	unsigned int transfered;
+	unsigned short idx;
+	int rc = 0;
+
+	phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+	phys_end = bank->io_addr + bank->size;
+	transfered = 0;
+	bio_for_each_segment(vec, bio, idx) {
+		if (unlikely(phys_mem + vec->bv_len > phys_end)) {
+			bio_io_error(bio, bio->bi_size);
+			rc = -ERANGE;
+			break;
+		}
+
+		user_mem = page_address(vec->bv_page) + vec->bv_offset;
+		if (bio_data_dir(bio) == READ)
+			memcpy(user_mem, (void *) phys_mem, vec->bv_len);
+		else
+			memcpy((void *) phys_mem, user_mem, vec->bv_len);
+
+		phys_mem += vec->bv_len;
+		transfered += vec->bv_len;
+	}
+	bio_endio(bio, transfered, 0);
+
+	return rc;
+}
+
+/**
+ * axon_ram_direct_access - direct_access() method for block device
+ * @device, @sector, @data: see block_device_operations method
+ */
+static int
+axon_ram_direct_access(struct block_device *device, sector_t sector,
+		       unsigned long *data)
+{
+	struct axon_ram_bank *bank = device->bd_disk->private_data;
+	loff_t offset;
+
+	offset = sector << AXON_RAM_SECTOR_SHIFT;
+	if (offset >= bank->size) {
+		dev_err(&bank->device->dev, "Access outside of address space\n");
+		return -ERANGE;
+	}
+
+	*data = bank->ph_addr + offset;
+
+	return 0;
+}
+
+static struct block_device_operations axon_ram_devops = {
+	.owner		= THIS_MODULE,
+	.direct_access	= axon_ram_direct_access
+};
+
+/**
+ * axon_ram_probe - probe() method for platform driver
+ * @device, @device_id: see of_platform_driver method
+ */
+static int
+axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
+{
+	static int axon_ram_bank_id = -1;
+	struct axon_ram_bank *bank;
+	struct resource resource;
+	int rc = 0;
+
+	axon_ram_bank_id++;
+
+	dev_info(&device->dev, "Found memory controller on %s\n",
+			device->node->full_name);
+
+	bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
+	if (bank == NULL) {
+		dev_err(&device->dev, "Out of memory\n");
+		rc = -ENOMEM;
+		goto failed;
+	}
+
+	device->dev.platform_data = bank;
+
+	bank->device = device;
+
+	if (of_address_to_resource(device->node, 0, &resource) != 0) {
+		dev_err(&device->dev, "Cannot access device tree\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	bank->size = resource.end - resource.start + 1;
+
+	if (bank->size == 0) {
+		dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
+				AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+		rc = -ENODEV;
+		goto failed;
+	}
+
+	dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
+			AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
+
+	bank->ph_addr = resource.start;
+	bank->io_addr = (unsigned long) ioremap_flags(
+			bank->ph_addr, bank->size, _PAGE_NO_CACHE);
+	if (bank->io_addr == 0) {
+		dev_err(&device->dev, "ioremap() failed\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
+	if (bank->disk == NULL) {
+		dev_err(&device->dev, "Cannot register disk\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	bank->disk->first_minor = 0;
+	bank->disk->fops = &axon_ram_devops;
+	bank->disk->private_data = bank;
+	bank->disk->driverfs_dev = &device->dev;
+
+	sprintf(bank->disk->disk_name, "%s%d",
+			AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+	bank->disk->major = register_blkdev(0, bank->disk->disk_name);
+	if (bank->disk->major < 0) {
+		dev_err(&device->dev, "Cannot register block device\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
+	if (bank->disk->queue == NULL) {
+		dev_err(&device->dev, "Cannot register disk queue\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
+	blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
+	blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
+	add_disk(bank->disk);
+
+	bank->irq_correctable = irq_of_parse_and_map(device->node, 0);
+	bank->irq_uncorrectable = irq_of_parse_and_map(device->node, 1);
+	if ((bank->irq_correctable <= 0) || (bank->irq_uncorrectable <= 0)) {
+		dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	rc = request_irq(bank->irq_correctable, axon_ram_irq_handler,
+			AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+	if (rc != 0) {
+		dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+		bank->irq_correctable = bank->irq_uncorrectable = 0;
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	rc = request_irq(bank->irq_uncorrectable, axon_ram_irq_handler,
+			AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+	if (rc != 0) {
+		dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+		bank->irq_uncorrectable = 0;
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	rc = device_create_file(&device->dev, &dev_attr_ecc);
+	if (rc != 0) {
+		dev_err(&device->dev, "Cannot create sysfs file\n");
+		rc = -EFAULT;
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	if (bank != NULL) {
+		if (bank->irq_uncorrectable > 0)
+			free_irq(bank->irq_uncorrectable, device);
+		if (bank->irq_correctable > 0)
+			free_irq(bank->irq_correctable, device);
+		if (bank->disk != NULL) {
+			if (bank->disk->queue != NULL)
+				blk_cleanup_queue(bank->disk->queue);
+			if (bank->disk->major > 0)
+				unregister_blkdev(bank->disk->major,
+						bank->disk->disk_name);
+			del_gendisk(bank->disk);
+		}
+		device->dev.platform_data = NULL;
+		if (bank->io_addr != 0)
+			iounmap((void __iomem *) bank->io_addr);
+		kfree(bank);
+	}
+
+	return rc;
+}
+
+/**
+ * axon_ram_remove - remove() method for platform driver
+ * @device: see of_platform_driver method
+ */
+static int
+axon_ram_remove(struct of_device *device)
+{
+	struct axon_ram_bank *bank = device->dev.platform_data;
+
+	BUG_ON(!bank || !bank->disk);
+
+	device_remove_file(&device->dev, &dev_attr_ecc);
+	free_irq(bank->irq_uncorrectable, device);
+	free_irq(bank->irq_correctable, device);
+	blk_cleanup_queue(bank->disk->queue);
+	unregister_blkdev(bank->disk->major, bank->disk->disk_name);
+	del_gendisk(bank->disk);
+	iounmap((void __iomem *) bank->io_addr);
+	kfree(bank);
+
+	return 0;
+}
+
+static struct of_device_id axon_ram_device_id[] = {
+	{
+		.type	= "dma-memory"
+	},
+	{}
+};
+
+static struct of_platform_driver axon_ram_driver = {
+	.owner		= THIS_MODULE,
+	.name		= AXON_RAM_MODULE_NAME,
+	.match_table	= axon_ram_device_id,
+	.probe		= axon_ram_probe,
+	.remove		= axon_ram_remove
+};
+
+/**
+ * axon_ram_init
+ */
+static int __init
+axon_ram_init(void)
+{
+	return of_register_platform_driver(&axon_ram_driver);
+}
+
+/**
+ * axon_ram_exit
+ */
+static void __exit
+axon_ram_exit(void)
+{
+	of_unregister_platform_driver(&axon_ram_driver);
+}
+
+module_init(axon_ram_init);
+module_exit(axon_ram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>");
+MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 75aad38..74c64c0 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -877,6 +877,8 @@
 
 	if (hw == mpic->spurious_vec)
 		return -EINVAL;
+	if (mpic->protected && test_bit(hw, mpic->protected))
+		return -EINVAL;
 
 #ifdef CONFIG_SMP
 	else if (hw >= mpic->ipi_vecs[0]) {
@@ -1034,6 +1036,25 @@
 	if (node && of_get_property(node, "big-endian", NULL) != NULL)
 		mpic->flags |= MPIC_BIG_ENDIAN;
 
+	/* Look for protected sources */
+	if (node) {
+		unsigned int psize, bits, mapsize;
+		const u32 *psrc =
+			of_get_property(node, "protected-sources", &psize);
+		if (psrc) {
+			psize /= 4;
+			bits = intvec_top + 1;
+			mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+			mpic->protected = alloc_bootmem(mapsize);
+			BUG_ON(mpic->protected == NULL);
+			memset(mpic->protected, 0, mapsize);
+			for (i = 0; i < psize; i++) {
+				if (psrc[i] > intvec_top)
+					continue;
+				__set_bit(psrc[i], mpic->protected);
+			}
+		}
+	}
 
 #ifdef CONFIG_MPIC_WEIRD
 	mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
@@ -1213,6 +1234,9 @@
 		u32 vecpri = MPIC_VECPRI_MASK | i |
 			(8 << MPIC_VECPRI_PRIORITY_SHIFT);
 		
+		/* check if protected */
+		if (mpic->protected && test_bit(i, mpic->protected))
+			continue;
 		/* init hw */
 		mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
 		mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
@@ -1407,6 +1431,14 @@
 			mpic_eoi(mpic);
 		return NO_IRQ;
 	}
+	if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING "%s: Got protected source %d !\n",
+			       mpic->name, (int)src);
+		mpic_eoi(mpic);
+		return NO_IRQ;
+	}
+
 	return irq_linear_revmap(mpic->irqhost, src);
 }
 
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index 85a7c99..2f91b55 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -48,15 +48,13 @@
 	struct work_struct	work;
 };
 
+static struct pmi_data *data;
 
 static int pmi_irq_handler(int irq, void *dev_id)
 {
-	struct pmi_data *data;
 	u8 type;
 	int rc;
 
-	data = dev_id;
-
 	spin_lock(&data->pmi_spinlock);
 
 	type = ioread8(data->pmi_reg + PMI_READ_TYPE);
@@ -111,16 +109,13 @@
 
 static void pmi_notify_handlers(struct work_struct *work)
 {
-	struct pmi_data *data;
 	struct pmi_handler *handler;
 
-	data = container_of(work, struct pmi_data, work);
-
 	spin_lock(&data->handler_spinlock);
 	list_for_each_entry(handler, &data->handler, node) {
 		pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
 		if (handler->type == data->msg.type)
-			handler->handle_pmi_message(data->dev, data->msg);
+			handler->handle_pmi_message(data->msg);
 	}
 	spin_unlock(&data->handler_spinlock);
 }
@@ -129,9 +124,14 @@
 			const struct of_device_id *match)
 {
 	struct device_node *np = dev->node;
-	struct pmi_data *data;
 	int rc;
 
+	if (data) {
+		printk(KERN_ERR "pmi: driver has already been initialized.\n");
+		rc = -EBUSY;
+		goto out;
+	}
+
 	data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL);
 	if (!data) {
 		printk(KERN_ERR "pmi: could not allocate memory.\n");
@@ -154,7 +154,6 @@
 
 	INIT_WORK(&data->work, pmi_notify_handlers);
 
-	dev->dev.driver_data = data;
 	data->dev = dev;
 
 	data->irq = irq_of_parse_and_map(np, 0);
@@ -164,7 +163,7 @@
 		goto error_cleanup_iomap;
 	}
 
-	rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data);
+	rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL);
 	if (rc) {
 		printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n",
 				data->irq, rc);
@@ -187,12 +186,9 @@
 
 static int pmi_of_remove(struct of_device *dev)
 {
-	struct pmi_data *data;
 	struct pmi_handler *handler, *tmp;
 
-	data = dev->dev.driver_data;
-
-	free_irq(data->irq, data);
+	free_irq(data->irq, NULL);
 	iounmap(data->pmi_reg);
 
 	spin_lock(&data->handler_spinlock);
@@ -202,7 +198,8 @@
 
 	spin_unlock(&data->handler_spinlock);
 
-	kfree(dev->dev.driver_data);
+	kfree(data);
+	data = NULL;
 
 	return 0;
 }
@@ -226,13 +223,13 @@
 }
 module_exit(pmi_module_exit);
 
-void pmi_send_message(struct of_device *device, pmi_message_t msg)
+int pmi_send_message(pmi_message_t msg)
 {
-	struct pmi_data *data;
 	unsigned long flags;
 	DECLARE_COMPLETION_ONSTACK(completion);
 
-	data = device->dev.driver_data;
+	if (!data)
+		return -ENODEV;
 
 	mutex_lock(&data->msg_mutex);
 
@@ -256,30 +253,26 @@
 	data->completion = NULL;
 
 	mutex_unlock(&data->msg_mutex);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_send_message);
 
-void pmi_register_handler(struct of_device *device,
-			  struct pmi_handler *handler)
+int pmi_register_handler(struct pmi_handler *handler)
 {
-	struct pmi_data *data;
-	data = device->dev.driver_data;
-
 	if (!data)
-		return;
+		return -ENODEV;
 
 	spin_lock(&data->handler_spinlock);
 	list_add_tail(&handler->node, &data->handler);
 	spin_unlock(&data->handler_spinlock);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_register_handler);
 
-void pmi_unregister_handler(struct of_device *device,
-			    struct pmi_handler *handler)
+void pmi_unregister_handler(struct pmi_handler *handler)
 {
-	struct pmi_data *data;
-	data = device->dev.driver_data;
-
 	if (!data)
 		return;
 
diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c
index 7876583..bfac84f 100644
--- a/arch/powerpc/xmon/nonstdio.c
+++ b/arch/powerpc/xmon/nonstdio.c
@@ -132,3 +132,8 @@
 	va_end(args);
 	xmon_write(xmon_outbuf, n);
 }
+
+void xmon_puts(const char *str)
+{
+	xmon_write(str, strlen(str));
+}
diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h
index 47cebbd..23dd95f 100644
--- a/arch/powerpc/xmon/nonstdio.h
+++ b/arch/powerpc/xmon/nonstdio.h
@@ -5,10 +5,11 @@
 
 extern int xmon_putchar(int c);
 extern int xmon_getchar(void);
+extern void xmon_puts(const char *);
 extern char *xmon_gets(char *, int);
 extern void xmon_printf(const char *, ...);
 extern void xmon_map_scc(void);
 extern int xmon_expect(const char *str, unsigned long timeout);
-extern int xmon_write(void *ptr, int nb);
+extern int xmon_write(const void *ptr, int nb);
 extern int xmon_readchar(void);
 extern int xmon_read_poll(void);
diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c
index 712552c..8864de2 100644
--- a/arch/powerpc/xmon/start.c
+++ b/arch/powerpc/xmon/start.c
@@ -14,7 +14,7 @@
 {
 }
 
-int xmon_write(void *ptr, int nb)
+int xmon_write(const void *ptr, int nb)
 {
 	return udbg_write(ptr, nb);
 }
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 669e656..121b04d 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -833,7 +833,7 @@
 			mdelay(2000);
 			return cmd;
 		case '?':
-			printf(help_string);
+			xmon_puts(help_string);
 			break;
 		case 'b':
 			bpt_cmds();
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
index 032f4b7..d212b1c 100644
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -14,6 +14,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/mv643xx.h>
@@ -2359,7 +2360,7 @@
 /* Export the hotswap register via sysfs for enum event monitoring */
 #define	VAL_LEN_MAX	11 /* 32-bit hex or dec stringified number + '\n' */
 
-DECLARE_MUTEX(mv64xxx_hs_lock);
+static DEFINE_MUTEX(mv64xxx_hs_lock);
 
 static ssize_t
 mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
@@ -2372,14 +2373,14 @@
 	if (count < VAL_LEN_MAX)
 		return -EINVAL;
 
-	if (down_interruptible(&mv64xxx_hs_lock))
+	if (mutex_lock_interruptible(&mv64xxx_hs_lock))
 		return -ERESTARTSYS;
 	save_exclude = mv64x60_pci_exclude_bridge;
 	mv64x60_pci_exclude_bridge = 0;
 	early_read_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
 			MV64360_PCICFG_CPCI_HOTSWAP, &v);
 	mv64x60_pci_exclude_bridge = save_exclude;
-	up(&mv64xxx_hs_lock);
+	mutex_unlock(&mv64xxx_hs_lock);
 
 	return sprintf(buf, "0x%08x\n", v);
 }
@@ -2396,14 +2397,14 @@
 		return -EINVAL;
 
 	if (sscanf(buf, "%i", &v) == 1) {
-		if (down_interruptible(&mv64xxx_hs_lock))
+		if (mutex_lock_interruptible(&mv64xxx_hs_lock))
 			return -ERESTARTSYS;
 		save_exclude = mv64x60_pci_exclude_bridge;
 		mv64x60_pci_exclude_bridge = 0;
 		early_write_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
 				MV64360_PCICFG_CPCI_HOTSWAP, v);
 		mv64x60_pci_exclude_bridge = save_exclude;
-		up(&mv64xxx_hs_lock);
+		mutex_unlock(&mv64xxx_hs_lock);
 	}
 	else
 		count = -EINVAL;
@@ -2433,10 +2434,10 @@
 	pdev = container_of(dev, struct platform_device, dev);
 	pdp = (struct mv64xxx_pdata *)pdev->dev.platform_data;
 
-	if (down_interruptible(&mv64xxx_hs_lock))
+	if (mutex_lock_interruptible(&mv64xxx_hs_lock))
 		return -ERESTARTSYS;
 	v = pdp->hs_reg_valid;
-	up(&mv64xxx_hs_lock);
+	mutex_unlock(&mv64xxx_hs_lock);
 
 	return sprintf(buf, "%i\n", v);
 }
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index d8ed667..f87f429 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -178,6 +178,9 @@
 config CPU_HAS_MASKREG_IRQ
 	bool
 
+config CPU_HAS_INTC_IRQ
+	bool
+
 config CPU_HAS_INTC2_IRQ
 	bool
 
@@ -209,6 +212,7 @@
 config SH_SOLUTION_ENGINE
 	bool "SolutionEngine"
 	select SOLUTION_ENGINE
+	select CPU_HAS_IPR_IRQ
 	depends on CPU_SUBTYPE_SH7709 || CPU_SUBTYPE_SH7750
 	help
 	  Select SolutionEngine if configuring for a Hitachi SH7709
@@ -241,6 +245,7 @@
 config SH_7751_SOLUTION_ENGINE
 	bool "SolutionEngine7751"
 	select SOLUTION_ENGINE
+	select CPU_HAS_IPR_IRQ
 	depends on CPU_SUBTYPE_SH7751
 	help
 	  Select 7751 SolutionEngine if configuring for a Hitachi SH7751
@@ -250,6 +255,7 @@
 	bool "SolutionEngine7780"
 	select SOLUTION_ENGINE
 	select SYS_SUPPORTS_PCI
+	select CPU_HAS_INTC2_IRQ
 	depends on CPU_SUBTYPE_SH7780
 	help
 	  Select 7780 SolutionEngine if configuring for a Renesas SH7780
@@ -317,6 +323,7 @@
 config SH_SH03
 	bool "Interface CTP/PCI-SH03"
 	depends on CPU_SUBTYPE_SH7751 && BROKEN
+	select CPU_HAS_IPR_IRQ
 	select SYS_SUPPORTS_PCI
 	help
 	  CTP/PCI-SH03 is a CPU module computer that is produced
@@ -326,6 +333,7 @@
 config SH_SECUREEDGE5410
 	bool "SecureEdge5410"
 	depends on CPU_SUBTYPE_SH7751R
+	select CPU_HAS_IPR_IRQ
 	select SYS_SUPPORTS_PCI
 	help
 	  Select SecureEdge5410 if configuring for a SnapGear SH board.
@@ -380,6 +388,7 @@
 config SH_TITAN
 	bool "TITAN"
 	depends on CPU_SUBTYPE_SH7751R
+	select CPU_HAS_IPR_IRQ
 	select SYS_SUPPORTS_PCI
 	help
 	  Select Titan if you are configuring for a Nimble Microsystems
@@ -388,6 +397,7 @@
 config SH_SHMIN
 	bool "SHMIN"
 	depends on CPU_SUBTYPE_SH7706
+	select CPU_HAS_IPR_IRQ
 	help
 	  Select SHMIN if configuring for the SHMIN board.
 
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 77fecc6..0016609 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -121,8 +121,7 @@
 endif
 
 # Companion chips
-core-$(CONFIG_HD64461)		+= arch/sh/cchips/hd6446x/hd64461/
-core-$(CONFIG_HD64465)		+= arch/sh/cchips/hd6446x/hd64465/
+core-$(CONFIG_HD6446X_SERIES)	+= arch/sh/cchips/hd6446x/
 core-$(CONFIG_VOYAGERGX)	+= arch/sh/cchips/voyagergx/
 
 cpuincdir-$(CONFIG_CPU_SH2)	:= cpu-sh2
diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c
index 4ed1a95..23849f7 100644
--- a/arch/sh/boards/mpc1211/pci.c
+++ b/arch/sh/boards/mpc1211/pci.c
@@ -187,7 +187,7 @@
  *  are examined.
  */
 
-void __init pcibios_fixup_bus(struct pci_bus *b)
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
 {
 	pci_read_bridge_bases(b);
 }
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index 5afb864..adb529d 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -21,6 +21,58 @@
 #include <asm/clock.h>
 #include <asm/io.h>
 
+static struct resource r8a66597_usb_host_resources[] = {
+	[0] = {
+		.name	= "r8a66597_hcd",
+		.start	= 0xA4200000,
+		.end	= 0xA42000FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "r8a66597_hcd",
+		.start	= 11,		/* irq number */
+		.end	= 11,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+	.name		= "r8a66597_hcd",
+	.id		= -1,
+	.dev = {
+		.dma_mask		= NULL,		/* don't use dma */
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(r8a66597_usb_host_resources),
+	.resource	= r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+	[0] = {
+		.name	= "m66592_udc",
+		.start	= 0xb0000000,
+		.end	= 0xb00000FF,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "m66592_udc",
+		.start	= 9,		/* irq number */
+		.end	= 9,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+	.name		= "m66592_udc",
+	.id		= -1,
+	.dev = {
+		.dma_mask		= NULL,		/* don't use dma */
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(m66592_usb_peripheral_resources),
+	.resource	= m66592_usb_peripheral_resources,
+};
+
 static struct resource cf_ide_resources[] = {
 	[0] = {
 		.start	= PA_AREA5_IO + 0x1000,
@@ -81,6 +133,8 @@
 };
 
 static struct platform_device *r7780rp_devices[] __initdata = {
+	&r8a66597_usb_host_device,
+	&m66592_usb_peripheral_device,
 	&cf_ide_device,
 	&heartbeat_device,
 };
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 656fda3..e165d85 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -86,7 +86,8 @@
 		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
 		.regshift	= 2,
 		.uartclk	= (9600 * 16),
-	}
+	},
+	{ 0 },
 };
 
 static struct platform_device uart_device = {
diff --git a/arch/sh/boards/se/7722/irq.c b/arch/sh/boards/se/7722/irq.c
index 26cff0e..0b03f3f 100644
--- a/arch/sh/boards/se/7722/irq.c
+++ b/arch/sh/boards/se/7722/irq.c
@@ -16,95 +16,61 @@
 #include <asm/io.h>
 #include <asm/se7722.h>
 
-#define INTC_INTMSK0             0xFFD00044
-#define INTC_INTMSKCLR0          0xFFD00064
-
-struct se7722_data {
-	unsigned char irq;
-	unsigned char ipr_idx;
-	unsigned char shift;
-	unsigned short priority;
-	unsigned long addr;
-};
-
-
 static void disable_se7722_irq(unsigned int irq)
 {
-	struct se7722_data *p = get_irq_chip_data(irq);
-	ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+	unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+	ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
 }
 
 static void enable_se7722_irq(unsigned int irq)
 {
-	struct se7722_data *p = get_irq_chip_data(irq);
-	ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+	unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+	ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
 }
 
 static struct irq_chip se7722_irq_chip __read_mostly = {
-	.name           = "SE7722",
+	.name           = "SE7722-FPGA",
 	.mask           = disable_se7722_irq,
 	.unmask         = enable_se7722_irq,
 	.mask_ack       = disable_se7722_irq,
 };
 
-static struct se7722_data ipr_irq_table[] = {
-	/* irq        ,idx,sft, priority     , addr   */
-	{ MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
-	{ MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
-	{ MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
-	{ MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
-	{ SMC_IRQ     , 0 , 0 , SMC_BIT     , IRQ01_MASK } ,
-	{ EXT_IRQ     , 0 , 0 , EXT_BIT     , IRQ01_MASK } ,
-};
-
-int se7722_irq_demux(int irq)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
+	unsigned short intv = ctrl_inw(IRQ01_STS);
+	struct irq_desc *ext_desc;
+	unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
 
-	if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
-		volatile unsigned short intv =
-			*(volatile unsigned short *)IRQ01_STS;
-		if (irq == IRQ0_IRQ){
-			if(intv & SMC_BIT ) {
-				return SMC_IRQ;
-			} else if(intv & USB_BIT) {
-				return USB_IRQ;
-			} else {
-				printk("intv =%04x\n", intv);
-				return SMC_IRQ;
-			}
-		} else if(irq == IRQ1_IRQ){
-			if(intv & MRSHPC_BIT0) {
-				return MRSHPC_IRQ0;
-			} else if(intv & MRSHPC_BIT1) {
-				return MRSHPC_IRQ1;
-			} else if(intv & MRSHPC_BIT2) {
-				return MRSHPC_IRQ2;
-			} else if(intv & MRSHPC_BIT3) {
-				return MRSHPC_IRQ3;
-			} else {
-				printk("BIT_EXTENTION =%04x\n", intv);
-				return EXT_IRQ;
-			}
+	intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
+
+	while (intv) {
+		if (intv & 1) {
+			ext_desc = irq_desc + ext_irq;
+			handle_level_irq(ext_irq, ext_desc);
 		}
+		intv >>= 1;
+		ext_irq++;
 	}
-	return irq;
-
 }
+
 /*
  * Initialize IRQ setting
  */
 void __init init_se7722_IRQ(void)
 {
-	int i = 0;
-	ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
-	ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0);     /* irq0 pri=3,irq1,pri=3 */
-	ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1);        /* irq0,1 low-level irq */
+	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
-		disable_irq_nosync(ipr_irq_table[i].irq);
-		set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
-			handle_level_irq, "level");
-		set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
-		disable_se7722_irq(ipr_irq_table[i].irq);
-	}
+	ctrl_outw(0, IRQ01_MASK);       /* disable all irqs */
+	ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+
+	for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
+		set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
+					      &se7722_irq_chip,
+					      handle_level_irq, "level");
+
+	set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
+	set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+	set_irq_chained_handler(IRQ1_IRQ, se7722_irq_demux);
+	set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
index 6cca6cb..495fc7e 100644
--- a/arch/sh/boards/se/7722/setup.c
+++ b/arch/sh/boards/se/7722/setup.c
@@ -77,6 +77,7 @@
 	},
 	[2] = {
 		.start  = MRSHPC_IRQ0,
+		.end    = MRSHPC_IRQ0,
 		.flags  = IORESOURCE_IRQ,
 	},
 };
@@ -140,8 +141,6 @@
 static struct sh_machine_vector mv_se7722 __initmv = {
 	.mv_name                = "Solution Engine 7722" ,
 	.mv_setup               = se7722_setup ,
-	.mv_nr_irqs		= 109 ,
+	.mv_nr_irqs		= SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
 	.mv_init_irq		= init_se7722_IRQ,
-	.mv_irq_demux           = se7722_irq_demux,
-
 };
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
new file mode 100644
index 0000000..a106dd9
--- /dev/null
+++ b/arch/sh/cchips/hd6446x/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_HD64461)	+= hd64461.o
+obj-$(CONFIG_HD64465)	+= hd64465/
diff --git a/arch/sh/cchips/hd6446x/hd64461/setup.c b/arch/sh/cchips/hd6446x/hd64461.c
similarity index 97%
rename from arch/sh/cchips/hd6446x/hd64461/setup.c
rename to arch/sh/cchips/hd6446x/hd64461.c
index 4d49b5c..97f6512 100644
--- a/arch/sh/cchips/hd6446x/hd64461/setup.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -1,5 +1,4 @@
 /*
- *	$Id: setup.c,v 1.5 2004/03/16 00:07:50 lethal Exp $
  *	Copyright (C) 2000 YAEGASHI Takeshi
  *	Hitachi HD64461 companion chip support
  */
diff --git a/arch/sh/cchips/hd6446x/hd64461/Makefile b/arch/sh/cchips/hd6446x/hd64461/Makefile
deleted file mode 100644
index bff4b92..0000000
--- a/arch/sh/cchips/hd6446x/hd64461/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the HD64461 
-#
-
-obj-y	 := setup.o io.o
-
diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
deleted file mode 100644
index 7909a1b..0000000
--- a/arch/sh/cchips/hd6446x/hd64461/io.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- *	Copyright (C) 2000 YAEGASHI Takeshi
- *	Typical I/O routines for HD64461 system.
- */
-
-#include <asm/io.h>
-#include <asm/hd64461.h>
-
-#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
-
-static __inline__ unsigned long PORT2ADDR(unsigned long port)
-{
-	/* 16550A: HD64461 internal */
-	if (0x3f8<=port && port<=0x3ff)
-		return CONFIG_HD64461_IOBASE + 0x8000 + ((port-0x3f8)<<1);
-	if (0x2f8<=port && port<=0x2ff)
-		return CONFIG_HD64461_IOBASE + 0x7000 + ((port-0x2f8)<<1);
-
-#ifdef CONFIG_HD64461_ENABLER
-	/* NE2000: HD64461 PCMCIA channel 0 (I/O) */
-	if (0x300<=port && port<=0x31f)
-		return 0xba000000 + port;
-
-	/* ide0: HD64461 PCMCIA channel 1 (memory) */
-	/* On HP690, CF in slot 1 is configured as a memory card
-	   device.  See CF+ and CompactFlash Specification for the
-	   detail of CF's memory mapped addressing. */
-	if (0x1f0<=port && port<=0x1f7)	return 0xb5000000 + port;
-	if (port == 0x3f6) return 0xb50001fe;
-	if (port == 0x3f7) return 0xb50001ff;
-
-	/* ide1 */
-	if (0x170<=port && port<=0x177)	return 0xba000000 + port;
-	if (port == 0x376) return 0xba000376;
-	if (port == 0x377) return 0xba000377;
-#endif
-
-	/* ??? */
-	if (port < 0xf000) return 0xa0000000 + port;
-	/* PCMCIA channel 0, I/O (0xba000000) */
-	if (port < 0x10000) return 0xba000000 + port - 0xf000;
-
-	/* HD64461 internal devices (0xb0000000) */
-	if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000;
-
-	/* PCMCIA channel 0, I/O (0xba000000) */
-	if (port < 0x30000) return 0xba000000 + port - 0x20000;
-
-	/* PCMCIA channel 1, memory (0xb5000000) */
-	if (port < 0x40000) return 0xb5000000 + port - 0x30000;
-
-	/* Whole physical address space (0xa0000000) */
-	return 0xa0000000 + (port & 0x1fffffff);
-}
-
-unsigned char hd64461_inb(unsigned long port)
-{
-	return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned char hd64461_inb_p(unsigned long port)
-{
-	unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
-	ctrl_delay();
-	return v;
-}
-
-unsigned short hd64461_inw(unsigned long port)
-{
-	return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int hd64461_inl(unsigned long port)
-{
-	return *(volatile unsigned long*)PORT2ADDR(port);
-}
-
-void hd64461_outb(unsigned char b, unsigned long port)
-{
-	*(volatile unsigned char*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outb_p(unsigned char b, unsigned long port)
-{
-	*(volatile unsigned char*)PORT2ADDR(port) = b;
-	ctrl_delay();
-}
-
-void hd64461_outw(unsigned short b, unsigned long port)
-{
-	*(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outl(unsigned int b, unsigned long port)
-{
-        *(volatile unsigned long*)PORT2ADDR(port) = b;
-}
-
-void hd64461_insb(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-	unsigned char *buf=buffer;
-	while(count--) *buf++=*addr;
-}
-
-void hd64461_insw(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-	unsigned short *buf=buffer;
-	while(count--) *buf++=*addr;
-}
-
-void hd64461_insl(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-	unsigned long *buf=buffer;
-	while(count--) *buf++=*addr;
-}
-
-void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-	const unsigned char *buf=buffer;
-	while(count--) *addr=*buf++;
-}
-
-void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-	const unsigned short *buf=buffer;
-	while(count--) *addr=*buf++;
-}
-
-void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-	const unsigned long *buf=buffer;
-	while(count--) *addr=*buf++;
-}
-
-unsigned short hd64461_readw(void __iomem *addr)
-{
-	return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
-}
-
-void hd64461_writew(unsigned short b, void __iomem *addr)
-{
-	ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
-}
-
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index e7f8ddb..07310fa 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -217,7 +217,7 @@
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
index be86414..fa09d68 100644
--- a/arch/sh/configs/lboxre2_defconfig
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -222,7 +222,7 @@
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
diff --git a/arch/sh/configs/r7780mp_defconfig b/arch/sh/configs/r7780mp_defconfig
index 17f7402..ac4de49 100644
--- a/arch/sh/configs/r7780mp_defconfig
+++ b/arch/sh/configs/r7780mp_defconfig
@@ -191,7 +191,7 @@
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
index 48c6a21..12cc0191 100644
--- a/arch/sh/configs/r7780rp_defconfig
+++ b/arch/sh/configs/r7780rp_defconfig
@@ -241,7 +241,7 @@
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
index a59bb78..f1e979b 100644
--- a/arch/sh/configs/rts7751r2d_defconfig
+++ b/arch/sh/configs/rts7751r2d_defconfig
@@ -155,7 +155,7 @@
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
 # CONFIG_CPU_SUBTYPE_SH7750S is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
 CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
@@ -218,7 +218,7 @@
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -280,7 +280,7 @@
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 # CONFIG_UBC_WAKEUP is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=bios"
 
 #
 # Bus options
@@ -1323,7 +1323,7 @@
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_SH_STANDARD_BIOS=y
 CONFIG_EARLY_SCIF_CONSOLE=y
 CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
 CONFIG_EARLY_PRINTK=y
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
index 764b813..8e6a6ba 100644
--- a/arch/sh/configs/se7722_defconfig
+++ b/arch/sh/configs/se7722_defconfig
@@ -200,7 +200,7 @@
 CONFIG_SH_DSP=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -565,7 +565,7 @@
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
index 4e6e77f..c60b6fd 100644
--- a/arch/sh/configs/se7750_defconfig
+++ b/arch/sh/configs/se7750_defconfig
@@ -226,7 +226,7 @@
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
index 538661e..f68743d 100644
--- a/arch/sh/configs/se7780_defconfig
+++ b/arch/sh/configs/se7780_defconfig
@@ -218,6 +218,7 @@
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 3338980..ee71143 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -5,12 +5,13 @@
 
 config SH_DMA
 	bool "SuperH on-chip DMA controller (DMAC) support"
+	depends on CPU_SH3 || CPU_SH4
 	select SH_DMA_API
 	default n
 
 config NR_ONCHIP_DMA_CHANNELS
+	int
 	depends on SH_DMA
-	int "Number of on-chip DMAC channels"
 	default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
 	default "12" if CPU_SUBTYPE_SH7780
 	default "4"
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index 23dd608..10c1828 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -78,7 +78,7 @@
 			hd->bit_pos[i] = i;
 	}
 
-	hd->base = (void __iomem *)res->start;
+	hd->base = (void __iomem *)(unsigned long)res->start;
 
 	setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
 	platform_set_drvdata(pdev, hd);
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 0e9b532..2f65ac7 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -7,6 +7,7 @@
 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= pci-st40.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751R)	+= pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)	+= pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)	+= pci-sh7780.o ops-sh4.o
 
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 54232f1..710a3b0 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -153,7 +153,7 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
 	if (!strcmp(str, "off")) {
 		pci_probe = 0;
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
index 543417f..1502a14 100644
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -328,7 +328,7 @@
 	return 1;
 }
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
 	return str;
 }
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index d439336..ccaba36 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -71,7 +71,7 @@
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 	pci_read_bridge_bases(bus);
 }
diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c
index b3d20c0..725be6d 100644
--- a/arch/sh/drivers/push-switch.c
+++ b/arch/sh/drivers/push-switch.c
@@ -138,4 +138,4 @@
 
 MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 6325154..92807ff 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -229,6 +229,22 @@
 }
 EXPORT_SYMBOL_GPL(clk_recalc_rate);
 
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (likely(clk->ops && clk->ops->round_rate)) {
+		unsigned long flags, rounded;
+
+		spin_lock_irqsave(&clock_lock, flags);
+		rounded = clk->ops->round_rate(clk, rate);
+		spin_unlock_irqrestore(&clock_lock, flags);
+
+		return rounded;
+	}
+
+	return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
 /*
  * Returns a clock. Note that we first try to use device id on the bus
  * and clock name. If this fails, we try to use clock name only.
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 1c23308..9ddb446 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -6,4 +6,5 @@
 obj-$(CONFIG_CPU_HAS_IPR_IRQ)		+= ipr.o
 obj-$(CONFIG_CPU_HAS_PINT_IRQ)		+= pint.o 
 obj-$(CONFIG_CPU_HAS_MASKREG_IRQ)	+= maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC_IRQ)		+= intc.o
 obj-$(CONFIG_CPU_HAS_INTC2_IRQ)		+= intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
new file mode 100644
index 0000000..9345a71
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -0,0 +1,405 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000  Kazumoto Kojima
+ * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#define _INTC_MK(fn, idx, bit, value) \
+	((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
+#define _INTC_FN(h) (h >> 24)
+#define _INTC_VALUE(h) ((h >> 16) & 0xff)
+#define _INTC_IDX(h) ((h >> 8) & 0xff)
+#define _INTC_BIT(h) (h & 0xff)
+
+#define _INTC_PTR(desc, member, data) \
+	(desc->member + _INTC_IDX(data))
+
+static inline struct intc_desc *get_intc_desc(unsigned int irq)
+{
+	struct irq_chip *chip = get_irq_chip(irq);
+	return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+}
+
+static inline unsigned int set_field(unsigned int value,
+				     unsigned int field_value,
+				     unsigned int width,
+				     unsigned int shift)
+{
+	value &= ~(((1 << width) - 1) << shift);
+	value |= field_value << shift;
+	return value;
+}
+
+static inline unsigned int set_prio_field(struct intc_desc *desc,
+					  unsigned int value,
+					  unsigned int priority,
+					  unsigned int data)
+{
+	unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
+
+	return set_field(value, priority, width, _INTC_BIT(data));
+}
+
+static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+	ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+}
+
+static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+	unsigned int prio = _INTC_VALUE(data);
+
+	ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+}
+
+static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+	ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+}
+
+static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+	unsigned int prio = _INTC_VALUE(data);
+
+	ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+}
+
+static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+	ctrl_outb(1 << _INTC_BIT(data),
+		  _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+	ctrl_outb(1 << _INTC_BIT(data),
+		  _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+	ctrl_outl(1 << _INTC_BIT(data),
+		  _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+	ctrl_outl(1 << _INTC_BIT(data),
+		  _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+enum {	REG_FN_ERROR=0,
+	REG_FN_MASK_8, REG_FN_MASK_32,
+	REG_FN_PRIO_16, REG_FN_PRIO_32 };
+
+static struct {
+	void (*enable)(struct intc_desc *, unsigned int);
+	void (*disable)(struct intc_desc *, unsigned int);
+} intc_reg_fns[] = {
+	[REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
+	[REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
+	[REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
+	[REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+};
+
+static void intc_enable(unsigned int irq)
+{
+	struct intc_desc *desc = get_intc_desc(irq);
+	unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+	intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+}
+
+static void intc_disable(unsigned int irq)
+{
+	struct intc_desc *desc = get_intc_desc(irq);
+	unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+	intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+}
+
+static void set_sense_16(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+	unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+	unsigned int bit = _INTC_BIT(data);
+	unsigned int value = _INTC_VALUE(data);
+
+	ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+}
+
+static void set_sense_32(struct intc_desc *desc, unsigned int data)
+{
+	unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+	unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+	unsigned int bit = _INTC_BIT(data);
+	unsigned int value = _INTC_VALUE(data);
+
+	ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+	[IRQ_TYPE_EDGE_FALLING] = VALID(0),
+	[IRQ_TYPE_EDGE_RISING] = VALID(1),
+	[IRQ_TYPE_LEVEL_LOW] = VALID(2),
+	[IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+};
+
+static int intc_set_sense(unsigned int irq, unsigned int type)
+{
+	struct intc_desc *desc = get_intc_desc(irq);
+	unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+	unsigned int i, j, data, bit;
+	intc_enum enum_id = 0;
+
+	for (i = 0; i < desc->nr_vectors; i++) {
+		struct intc_vect *vect = desc->vectors + i;
+
+		if (evt2irq(vect->vect) != irq)
+			continue;
+
+		enum_id = vect->enum_id;
+		break;
+	}
+
+	if (!enum_id || !value)
+		return -EINVAL;
+
+	value ^= VALID(0);
+
+	for (i = 0; i < desc->nr_sense_regs; i++) {
+		struct intc_sense_reg *sr = desc->sense_regs + i;
+
+		for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+			if (sr->enum_ids[j] != enum_id)
+				continue;
+
+			bit = sr->reg_width - ((j + 1) * sr->field_width);
+			data = _INTC_MK(0, i, bit, value);
+
+			switch(sr->reg_width) {
+			case 16:
+				set_sense_16(desc, data);
+				break;
+			case 32:
+				set_sense_32(desc, data);
+				break;
+			}
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int __init intc_find_mask_handler(unsigned int width)
+{
+	switch (width) {
+	case 8:
+		return REG_FN_MASK_8;
+	case 32:
+		return REG_FN_MASK_32;
+	}
+
+	BUG();
+	return REG_FN_ERROR;
+}
+
+static unsigned int __init intc_find_prio_handler(unsigned int width)
+{
+	switch (width) {
+	case 16:
+		return REG_FN_PRIO_16;
+	case 32:
+		return REG_FN_PRIO_32;
+	}
+
+	BUG();
+	return REG_FN_ERROR;
+}
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+{
+	struct intc_group *g = desc->groups;
+	unsigned int i, j;
+
+	for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
+		g = desc->groups + i;
+
+		for (j = 0; g->enum_ids[j]; j++) {
+			if (g->enum_ids[j] != enum_id)
+				continue;
+
+			return g->enum_id;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned int __init intc_prio_value(struct intc_desc *desc,
+					   intc_enum enum_id, int do_grps)
+{
+	struct intc_prio *p = desc->priorities;
+	unsigned int i;
+
+	for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
+		p = desc->priorities + i;
+
+		if (p->enum_id != enum_id)
+			continue;
+
+		return p->priority;
+	}
+
+	if (do_grps)
+		return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
+
+	/* default to the lowest priority possible if no priority is set
+	 * - this needs to be at least 2 for 5-bit priorities on 7780
+	 */
+
+	return 2;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+					  intc_enum enum_id, int do_grps)
+{
+	struct intc_mask_reg *mr = desc->mask_regs;
+	unsigned int i, j, fn;
+
+	for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
+		mr = desc->mask_regs + i;
+
+		for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+			if (mr->enum_ids[j] != enum_id)
+				continue;
+
+			fn = intc_find_mask_handler(mr->reg_width);
+			if (fn == REG_FN_ERROR)
+				return 0;
+
+			return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+		}
+	}
+
+	if (do_grps)
+		return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+
+	return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+					  intc_enum enum_id, int do_grps)
+{
+	struct intc_prio_reg *pr = desc->prio_regs;
+	unsigned int i, j, fn, bit, prio;
+
+	for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
+		pr = desc->prio_regs + i;
+
+		for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
+			if (pr->enum_ids[j] != enum_id)
+				continue;
+
+			fn = intc_find_prio_handler(pr->reg_width);
+			if (fn == REG_FN_ERROR)
+				return 0;
+
+			prio = intc_prio_value(desc, enum_id, 1);
+			bit = pr->reg_width - ((j + 1) * pr->field_width);
+
+			BUG_ON(bit < 0);
+
+			return _INTC_MK(fn, i, bit, prio);
+		}
+	}
+
+	if (do_grps)
+		return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+
+	return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+				     unsigned int irq)
+{
+	unsigned int data[2], primary;
+
+	/* Prefer single interrupt source bitmap over other combinations:
+	 * 1. bitmap, single interrupt source
+	 * 2. priority, single interrupt source
+	 * 3. bitmap, multiple interrupt sources (groups)
+	 * 4. priority, multiple interrupt sources (groups)
+	 */
+
+	data[0] = intc_mask_data(desc, enum_id, 0);
+	data[1] = intc_prio_data(desc, enum_id, 0);
+
+	primary = 0;
+	if (!data[0] && data[1])
+		primary = 1;
+
+	data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
+	data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+
+	if (!data[primary])
+		primary ^= 1;
+
+	BUG_ON(!data[primary]); /* must have primary masking method */
+
+	disable_irq_nosync(irq);
+	set_irq_chip_and_handler_name(irq, &desc->chip,
+				      handle_level_irq, "level");
+	set_irq_chip_data(irq, (void *)data[primary]);
+
+	/* enable secondary masking method if present */
+	if (data[!primary])
+		intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
+							      data[!primary]);
+
+	/* irq should be disabled by default */
+	desc->chip.mask(irq);
+}
+
+void __init register_intc_controller(struct intc_desc *desc)
+{
+	unsigned int i;
+
+	desc->chip.mask = intc_disable;
+	desc->chip.unmask = intc_enable;
+	desc->chip.mask_ack = intc_disable;
+	desc->chip.set_type = intc_set_sense;
+
+	for (i = 0; i < desc->nr_vectors; i++) {
+		struct intc_vect *vect = desc->vectors + i;
+
+		intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+	}
+}
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index 1a107fe..a979b98 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -88,7 +88,7 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index b6e3a63..deab165 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -107,7 +107,7 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index a55b8ce..ebd9d06 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -92,7 +92,7 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index d79ec0c..086f8e2 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -139,7 +139,7 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index f40e6da..1322848 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -101,7 +101,7 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index da153bc..f2286de 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -82,88 +82,213 @@
 }
 __initcall(sh7750_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-	/* IRQ, IPR-idx, shift, priority */
-	{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
-	{ 17, 0, 12, 2 }, /* TMU1 TUNI */
-	{ 18, 0,  4, 2 }, /* TMU2 TUNI */
-	{ 19, 0,  4, 2 }, /* TMU2 TIPCI */
-	{ 27, 1, 12, 2 }, /* WDT ITI */
-	{ 20, 0,  0, 2 }, /* RTC ATI (alarm) */
-	{ 21, 0,  0, 2 }, /* RTC PRI (period) */
-	{ 22, 0,  0, 2 }, /* RTC CUI (carry) */
-	{ 23, 1,  4, 3 }, /* SCI ERI */
-	{ 24, 1,  4, 3 }, /* SCI RXI */
-	{ 25, 1,  4, 3 }, /* SCI TXI */
-	{ 40, 2,  4, 3 }, /* SCIF ERI */
-	{ 41, 2,  4, 3 }, /* SCIF RXI */
-	{ 42, 2,  4, 3 }, /* SCIF BRI */
-	{ 43, 2,  4, 3 }, /* SCIF TXI */
-	{ 34, 2,  8, 7 }, /* DMAC DMTE0 */
-	{ 35, 2,  8, 7 }, /* DMAC DMTE1 */
-	{ 36, 2,  8, 7 }, /* DMAC DMTE2 */
-	{ 37, 2,  8, 7 }, /* DMAC DMTE3 */
-	{ 38, 2,  8, 7 }, /* DMAC DMAE */
+enum {
+	UNUSED = 0,
+
+	/* interrupt sources */
+	IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+	HUDI, GPIOI,
+	DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+	DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+	DMAC_DMAE,
+	PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+	PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
+	TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+	RTC_ATI, RTC_PRI, RTC_CUI,
+	SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
+	SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
+	WDT,
+	REF_RCMI, REF_ROVI,
+
+	/* interrupt groups */
+	DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
 };
 
-static unsigned long ipr_offsets[] = {
-	0xffd00004UL,	/* 0: IPRA */
-	0xffd00008UL,	/* 1: IPRB */
-	0xffd0000cUL,	/* 2: IPRC */
-	0xffd00010UL,	/* 3: IPRD */
+static struct intc_vect vectors[] = {
+	INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+	INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+	INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+	INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+	INTC_VECT(RTC_CUI, 0x4c0),
+	INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
+	INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
+	INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
+	INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+	INTC_VECT(WDT, 0x560),
+	INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
 };
 
-static struct ipr_desc ipr_irq_desc = {
-	.ipr_offsets	= ipr_offsets,
-	.nr_offsets	= ARRAY_SIZE(ipr_offsets),
-
-	.ipr_data	= ipr_irq_table,
-	.nr_irqs	= ARRAY_SIZE(ipr_irq_table),
-
-	.chip = {
-		.name	= "IPR-sh7750",
-	},
+static struct intc_group groups[] = {
+	INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+	INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
+	INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
+	INTC_GROUP(REF, REF_RCMI, REF_ROVI),
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-static struct ipr_data ipr_irq_table_sh7751[] = {
-	{ 44, 2,  8, 7 }, /* DMAC DMTE4 */
-	{ 45, 2,  8, 7 }, /* DMAC DMTE5 */
-	{ 46, 2,  8, 7 }, /* DMAC DMTE6 */
-	{ 47, 2,  8, 7 }, /* DMAC DMTE7 */
-	/* The following use INTC_INPRI00 for masking, which is a 32-bit
-	   register, not a 16-bit register like the IPRx registers, so it
-	   would need special support */
-	/*{ 72, INTPRI00,  8, ? },*/ /* TMU3 TUNI */
-	/*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */
+static struct intc_prio priorities[] = {
+	INTC_PRIO(SCIF, 3),
+	INTC_PRIO(SCI1, 3),
+	INTC_PRIO(DMAC, 7),
 };
 
-static struct ipr_desc ipr_irq_desc_sh7751 = {
-	.ipr_offsets	= ipr_offsets,
-	.nr_offsets	= ARRAY_SIZE(ipr_offsets),
-
-	.ipr_data	= ipr_irq_table_sh7751,
-	.nr_irqs	= ARRAY_SIZE(ipr_irq_table_sh7751),
-
-	.chip = {
-		.name	= "IPR-sh7751",
-	},
+static struct intc_prio_reg prio_registers[] = {
+	{ 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+	{ 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+	{ 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+	{ 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+	{ 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+					      TMU4, TMU3,
+					      PCIC1, PCIC0_PCISERR } },
 };
+
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+			 priorities, NULL, prio_registers, NULL);
+
+/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7091)
+static struct intc_vect vectors_dma4[] = {
+	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+	INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma4[] = {
+	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+		   DMAC_DMTE3, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
+			 vectors_dma4, groups_dma4,
+			 priorities, NULL, prio_registers, NULL);
 #endif
 
-void __init init_IRQ_ipr(void)
+/* SH7750R and SH7751R both have 8-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_dma8[] = {
+	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+	INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+	INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+	INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma8[] = {
+	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+		   DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+		   DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
+			 vectors_dma8, groups_dma8,
+			 priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_tmu34[] = {
+	INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+	{ 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, TMU4, TMU3,
+	    PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+	    PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
+	    PCIC1_PCIDMA3, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
+			 vectors_tmu34, NULL, priorities,
+			 mask_registers, prio_registers, NULL);
+#endif
+
+/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
+static struct intc_vect vectors_irlm[] = {
+	INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+	INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
+			 priorities, NULL, prio_registers, NULL);
+
+/* SH7751 and SH7751R both have PCI */
+#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_pci[] = {
+	INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
+	INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
+	INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
+	INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
+};
+
+static struct intc_group groups_pci[] = {
+	INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+		   PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
+};
+
+static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
+			 priorities, mask_registers, prio_registers, NULL);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+	defined(CONFIG_CPU_SUBTYPE_SH7091)
+void __init plat_irq_setup(void)
 {
-	register_ipr_controller(&ipr_irq_desc);
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-	register_ipr_controller(&ipr_irq_desc_sh7751);
-#endif
+	/*
+	 * same vectors for SH7750, SH7750S and SH7091 except for IRLM,
+	 * see below..
+	 */
+	register_intc_controller(&intc_desc);
+	register_intc_controller(&intc_desc_dma4);
 }
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R)
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+	register_intc_controller(&intc_desc_dma8);
+	register_intc_controller(&intc_desc_tmu34);
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+	register_intc_controller(&intc_desc_dma4);
+	register_intc_controller(&intc_desc_tmu34);
+	register_intc_controller(&intc_desc_pci);
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R)
+void __init plat_irq_setup(void)
+{
+	register_intc_controller(&intc_desc);
+	register_intc_controller(&intc_desc_dma8);
+	register_intc_controller(&intc_desc_tmu34);
+	register_intc_controller(&intc_desc_pci);
+}
+#endif
 
 #define INTC_ICR	0xffd00000UL
 #define INTC_ICR_IRLM   (1<<7)
 
 /* enable individual interrupt mode for external interupts */
-void ipr_irq_enable_irlm(void)
+void __init ipr_irq_enable_irlm(void)
 {
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
+	BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+#endif
+	register_intc_controller(&intc_desc_irlm);
+
 	ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
 }
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index 3df1697..47fa270 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -109,11 +109,6 @@
 	},
 };
 
-void __init init_IRQ_intc2(void)
-{
-	register_intc2_controller(&intc2_irq_desc);
-}
-
 static struct ipr_data ipr_irq_table[] = {
 	/* IRQ, IPR-idx, shift, priority */
 	{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
@@ -163,7 +158,8 @@
 	},
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
+	register_intc2_controller(&intc2_irq_desc);
 	register_ipr_controller(&ipr_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 51b386d..a0fd8bb 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -387,9 +387,24 @@
 	return err;
 }
 
+static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent_rate = clk->parent->rate;
+	int div;
+
+	/* look for multiplier/divisor pair */
+	div = sh7722_find_divisors(parent_rate, rate);
+	if (div < 0)
+		return clk->rate;
+
+	/* calculate new value of clock rate */
+	return parent_rate * 2 / div;
+}
+
 static struct clk_ops sh7722_frqcr_clk_ops = {
 	.recalc = sh7722_frqcr_recalc,
 	.set_rate = sh7722_frqcr_set_rate,
+	.round_rate = sh7722_frqcr_round_rate,
 };
 
 /*
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index a3e159e..25b913e 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -19,8 +19,21 @@
 		.mapbase	= 0xffe00000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCIF,
-		.irqs		= { 80, 81, 83, 82 },
-	}, {
+		.irqs		= { 80, 80, 80, 80 },
+	},
+	{
+		.mapbase	= 0xffe10000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 81, 81, 81, 81 },
+	},
+	{
+		.mapbase	= 0xffe20000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 82, 82, 82, 82 },
+	},
+	{
 		.flags = 0,
 	}
 };
@@ -44,46 +57,145 @@
 }
 __initcall(sh7722_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-	/* IRQ, IPR-idx, shift, prio */
-	{ 16, 0, 12, 2 }, /* TMU0 */
-	{ 17, 0,  8, 2 }, /* TMU1 */
-	{ 80, 6, 12, 3 }, /* SCIF ERI */
-	{ 81, 6, 12, 3 }, /* SCIF RXI */
-	{ 82, 6, 12, 3 }, /* SCIF BRI */
-	{ 83, 6, 12, 3 }, /* SCIF TXI */
+enum {
+	UNUSED=0,
+
+	/* interrupt sources */
+	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+	HUDI,
+	SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+	RTC_ATI, RTC_PRI, RTC_CUI,
+	DMAC0, DMAC1, DMAC2, DMAC3,
+	VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
+	VPU, TPU,
+	USB_USBI0, USB_USBI1,
+	DMAC4, DMAC5, DMAC_DADERR,
+	KEYSC,
+	SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO,
+	FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+	I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
+	SDHI0, SDHI1, SDHI2, SDHI3,
+	CMT, TSIF, SIU, TWODG,
+	TMU0, TMU1, TMU2,
+	IRDA, JPU, LCDC,
+
+	/* interrupt groups */
+
+	SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
 };
 
-static unsigned long ipr_offsets[] = {
-	0xa4080000, /*  0: IPRA */
-	0xa4080004, /*  1: IPRB */
-	0xa4080008, /*  2: IPRC */
-	0xa408000c, /*  3: IPRD */
-	0xa4080010, /*  4: IPRE */
-	0xa4080014, /*  5: IPRF */
-	0xa4080018, /*  6: IPRG */
-	0xa408001c, /*  7: IPRH */
-	0xa4080020, /*  8: IPRI */
-	0xa4080024, /*  9: IPRJ */
-	0xa4080028, /* 10: IPRK */
-	0xa408002c, /* 11: IPRL */
+static struct intc_vect vectors[] = {
+	INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+	INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+	INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+	INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
+	INTC_VECT(SIM_ERI, 0x700), INTC_VECT(SIM_RXI, 0x720),
+	INTC_VECT(SIM_TXI, 0x740), INTC_VECT(SIM_TEI, 0x760),
+	INTC_VECT(RTC_ATI, 0x780), INTC_VECT(RTC_PRI, 0x7a0),
+	INTC_VECT(RTC_CUI, 0x7c0),
+	INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
+	INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
+	INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
+	INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
+	INTC_VECT(VPU, 0x980), INTC_VECT(TPU, 0x9a0),
+	INTC_VECT(USB_USBI0, 0xa20), INTC_VECT(USB_USBI1, 0xa40),
+	INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
+	INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
+	INTC_VECT(SCIF0, 0xc00), INTC_VECT(SCIF1, 0xc20),
+	INTC_VECT(SCIF2, 0xc40), INTC_VECT(SIOF0, 0xc80),
+	INTC_VECT(SIOF1, 0xca0), INTC_VECT(SIO, 0xd00),
+	INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
+	INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
+	INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
+	INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
+	INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0),
+	INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0),
+	INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
+	INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0),
+	INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+	INTC_VECT(TMU2, 0x440), INTC_VECT(IRDA, 0x480),
+	INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
 };
 
-static struct ipr_desc ipr_irq_desc = {
-	.ipr_offsets	= ipr_offsets,
-	.nr_offsets	= ARRAY_SIZE(ipr_offsets),
-
-	.ipr_data	= ipr_irq_table,
-	.nr_irqs	= ARRAY_SIZE(ipr_irq_table),
-
-	.chip = {
-		.name	= "IPR-sh7722",
-	},
+static struct intc_group groups[] = {
+	INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+	INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
+	INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
+	INTC_GROUP(USB, USB_USBI0, USB_USBI1),
+	INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
+	INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
+		   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+	INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
+	INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
 };
 
-void __init init_IRQ_ipr(void)
+static struct intc_prio priorities[] = {
+	INTC_PRIO(SCIF0, 3),
+	INTC_PRIO(SCIF1, 3),
+	INTC_PRIO(SCIF2, 3),
+	INTC_PRIO(TMU0, 2),
+	INTC_PRIO(TMU1, 2),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+	{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+	  { } },
+	{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
+	  { VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
+	{ 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
+	  { 0, 0, 0, VPU, } },
+	{ 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
+	  { SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
+	{ 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
+	  { 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
+	{ 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
+	  { KEYSC, DMAC_DADERR, DMAC5, DMAC4, 0, SCIF2, SCIF1, SCIF0 } },
+	{ 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
+	  { 0, 0, 0, SIO, 0, 0, SIOF1, SIOF0 } },
+	{ 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
+	  { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
+	    FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
+	{ 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
+	  { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, TWODG, SIU } },
+	{ 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
+	  { 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } },
+	{ 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
+	  { } },
+	{ 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
+	  { 0, RTC_CUI, RTC_PRI, RTC_ATI, 0, TPU, 0, TSIF } },
+	{ 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
+	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg prio_registers[] = {
+	{ 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+	{ 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+	{ 0xa4080008, 16, 4, /* IPRC */ { } },
+	{ 0xa408000c, 16, 4, /* IPRD */ { } },
+	{ 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+	{ 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+	{ 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+	{ 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+	{ 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+	{ 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+	{ 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+	{ 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+	{ 0xa4140010, 32, 4, /* INTPRI00 */
+	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg sense_registers[] = {
+	{ 0xa414001c, 16, 2, /* ICR1 */
+	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
+			 mask_registers, prio_registers, sense_registers);
+
+void __init plat_irq_setup(void)
 {
-	register_ipr_controller(&ipr_irq_desc);
+	register_intc_controller(&intc_desc);
 }
 
 void __init plat_mem_setup(void)
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index b57c760..a4127ec 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -30,7 +30,7 @@
 	},
 	[3] = {
 		/* Alarm IRQ */
-		.start	= 23,
+		.start	= 20,
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -78,44 +78,205 @@
 }
 __initcall(sh7780_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-	{ 28, 0, 24, 0, 0, 2 },		/* TMU0 */
+enum {
+	UNUSED = 0,
 
-	{ 21, 1,  0, 0, 2, 2 },
-	{ 22, 1,  1, 0, 2, 2 },
-	{ 23, 1,  2, 0, 2, 2 },
+	/* interrupt sources */
 
-	{ 40, 8, 24, 0, 3, 3 },		/* SCIF0 ERI */
-	{ 41, 8, 24, 0, 3, 3 },		/* SCIF0 RXI */
-	{ 42, 8, 24, 0, 3, 3 },		/* SCIF0 BRI */
-	{ 43, 8, 24, 0, 3, 3 },		/* SCIF0 TXI */
+	IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+	IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+	IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+	IRL_HHLL, IRL_HHLH, IRL_HHHL,
 
-	{ 76, 8, 16, 0, 4, 3 },		/* SCIF1 ERI */
-	{ 77, 8, 16, 0, 4, 3 },		/* SCIF1 RXI */
-	{ 78, 8, 16, 0, 4, 3 },		/* SCIF1 BRI */
-	{ 79, 8, 16, 0, 4, 3 },		/* SCIF1 TXI */
+	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+	RTC_ATI, RTC_PRI, RTC_CUI,
+	WDT,
+	TMU0, TMU1, TMU2, TMU2_TICPI,
+	HUDI,
+	DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
+	SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+	DMAC0_DMINT4, DMAC0_DMINT5, DMAC1_DMINT6, DMAC1_DMINT7,
+	CMT, HAC,
+	PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+	PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+	SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+	SIOF, HSPI,
+	MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+	DMAC1_DMINT8, DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11,
+	TMU3, TMU4, TMU5,
+	SSI,
+	FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+	GPIOI0, GPIOI1, GPIOI2, GPIOI3,
 
-	{ 64, 0x10,  8, 0, 14, 2 },	/* PCIC0 */
-	{ 65, 0x10,  0, 0, 15, 2 },	/* PCIC1 */
-	{ 66, 0x14, 24, 0, 16, 2 },	/* PCIC2 */
-	{ 67, 0x14, 16, 0, 17, 2 },	/* PCIC3 */
-	{ 68, 0x14,  8, 0, 18, 2 },	/* PCIC4 */
+	/* interrupt groups */
+
+	RTC, TMU012, DMAC0, SCIF0, DMAC45, DMAC1,
+	PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
 };
 
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-	.prio_base	= 0xffd40000,
-	.msk_base	= 0xffd40038,
-	.mskclr_base	= 0xffd4003c,
-
-	.intc2_data	= intc2_irq_table,
-	.nr_irqs	= ARRAY_SIZE(intc2_irq_table),
-
-	.chip = {
-		.name	= "INTC2-sh7780",
-	},
+static struct intc_vect vectors[] = {
+	INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+	INTC_VECT(RTC_CUI, 0x4c0),
+	INTC_VECT(WDT, 0x560),
+	INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+	INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+	INTC_VECT(HUDI, 0x600),
+	INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+	INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
+	INTC_VECT(DMAC0_DMAE, 0x6c0),
+	INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+	INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+	INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+	INTC_VECT(DMAC1_DMINT6, 0x7c0), INTC_VECT(DMAC1_DMINT7, 0x7e0),
+	INTC_VECT(CMT, 0x900), INTC_VECT(HAC, 0x980),
+	INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+	INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+	INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+	INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+	INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+	INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
+	INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+	INTC_VECT(SIOF, 0xc00), INTC_VECT(HSPI, 0xc80),
+	INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+	INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+	INTC_VECT(DMAC1_DMINT8, 0xd80), INTC_VECT(DMAC1_DMINT9, 0xda0),
+	INTC_VECT(DMAC1_DMINT10, 0xdc0), INTC_VECT(DMAC1_DMINT11, 0xde0),
+	INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+	INTC_VECT(TMU5, 0xe40),
+	INTC_VECT(SSI, 0xe80),
+	INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+	INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+	INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+	INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
 };
 
-void __init init_IRQ_intc2(void)
+static struct intc_group groups[] = {
+	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+	INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+	INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+		   DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+	INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+	INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+		   DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+	INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+	INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+	INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+	INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+	INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+		   FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+	INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
+
+static struct intc_prio priorities[] = {
+	INTC_PRIO(SCIF0, 3),
+	INTC_PRIO(SCIF1, 3),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+	{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+	  { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
+	    SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+	    PCIINTA, PCISERR, HAC, CMT, 0, 0, DMAC1, DMAC0,
+	    HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
+};
+
+static struct intc_prio_reg prio_registers[] = {
+	{ 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
+	{ 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+	{ 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+	{ 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+	{ 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
+	{ 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+					      PCIINTD, PCIC5 } },
+	{ 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+	{ 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
+			 mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq_vectors[] = {
+	INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+	INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+	INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+	INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_mask_reg irq_mask_registers[] = {
+	{ 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] = {
+	{ 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+					    IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg irq_sense_registers[] = {
+	{ 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+					    IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
+			 NULL, NULL, irq_mask_registers, irq_prio_registers,
+			 irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect irl_vectors[] = {
+	INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+	INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+	INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+	INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+	INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+	INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+	INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+	INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] = {
+	{ 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+	  { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+	    IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+	    IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+	    IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] = {
+	{ 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	    IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+	    IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+	    IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+	    IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+			 NULL, NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+			 NULL, NULL, irl3210_mask_registers, NULL, NULL);
+
+void __init plat_irq_setup(void)
 {
-	register_intc2_controller(&intc2_irq_desc);
+	register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+	switch (mode) {
+	case IRQ_MODE_IRQ:
+		register_intc_controller(&intc_irq_desc);
+		break;
+	case IRQ_MODE_IRL7654:
+		register_intc_controller(&intc_irl7654_desc);
+		break;
+	case IRQ_MODE_IRL3210:
+		register_intc_controller(&intc_irl3210_desc);
+		break;
+	default:
+		BUG();
+	}
 }
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index ce10ec5..cf04756 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -110,7 +110,7 @@
 	},
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
 	register_intc2_controller(&intc2_irq_desc);
 }
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index 70683ea..704c064 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -79,7 +79,7 @@
 	},
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
 	register_intc2_controller(&intc2_irq_desc);
 }
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index 47abf6e..e618902 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -3,89 +3,46 @@
  *
  * cpufreq driver for the SuperH processors.
  *
- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
  * Copyright (C) 2002 M. R. Brown
  *
- * 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.
+ * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
+ *
+ *   Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
 #include <linux/types.h>
 #include <linux/cpufreq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/sched.h>	/* set_cpus_allowed() */
+#include <linux/clk.h>
 
-#include <asm/processor.h>
-#include <asm/watchdog.h>
-#include <asm/freq.h>
-#include <asm/io.h>
+static struct clk *cpuclk;
 
-/*
- * For SuperH, each policy change requires that we change the IFC, BFC, and
- * PFC at the same time.  Here we define sane values that won't trash the
- * system.
- *
- * Note the max set is computed at runtime, we use the divisors that we booted
- * with to setup our maximum operating frequencies.
- */
-struct clock_set {
-	unsigned int ifc;
-	unsigned int bfc;
-	unsigned int pfc;
-} clock_sets[] = {
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
-	{ 0, 0, 0 },	/* not implemented yet */
-#elif defined(CONFIG_CPU_SH4)
-	{ 4, 8, 8 },	/* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
-	{ 1, 2, 2 },	/* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
-#endif
-};
-
-#define MIN_CLOCK_SET	0
-#define MAX_CLOCK_SET	(ARRAY_SIZE(clock_sets) - 1)
-
-/*
- * For the time being, we only support two frequencies, which in turn are
- * aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
- * directly from the respective min/max clock sets. Technically we could
- * support a wider range of frequencies, but these vary far too much for each
- * CPU subtype (and we'd have to construct a frequency table for each subtype).
- *
- * Maybe something to implement in the future..
- */
-#define SH_FREQ_MAX	0
-#define SH_FREQ_MIN	1
-
-static struct cpufreq_frequency_table sh_freqs[] = {
-	{ SH_FREQ_MAX,	0 },
-	{ SH_FREQ_MIN,	0 },
-	{ 0,		CPUFREQ_TABLE_END },
-};
-
-static void sh_cpufreq_update_clocks(unsigned int set)
+static unsigned int sh_cpufreq_get(unsigned int cpu)
 {
-	current_cpu_data.cpu_clock = current_cpu_data.master_clock / clock_sets[set].ifc;
-	current_cpu_data.bus_clock = current_cpu_data.master_clock / clock_sets[set].bfc;
-	current_cpu_data.module_clock = current_cpu_data.master_clock / clock_sets[set].pfc;
-	current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+	return (clk_get_rate(cpuclk) + 500) / 1000;
 }
 
-/* XXX: This needs to be split out per CPU and CPU subtype. */
 /*
  * Here we notify other drivers of the proposed change and the final change.
  */
-static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+			     unsigned int target_freq,
+			     unsigned int relation)
 {
-	unsigned short frqcr = ctrl_inw(FRQCR);
+	unsigned int cpu = policy->cpu;
 	cpumask_t cpus_allowed;
 	struct cpufreq_freqs freqs;
+	long freq;
 
 	if (!cpu_online(cpu))
 		return -ENODEV;
@@ -95,125 +52,109 @@
 
 	BUG_ON(smp_processor_id() != cpu);
 
-	freqs.cpu = cpu;
-	freqs.old = current_cpu_data.cpu_clock / 1000;
-	freqs.new = (current_cpu_data.master_clock / clock_sets[set].ifc) / 1000;
+	/* Convert target_freq from kHz to Hz */
+	freq = clk_round_rate(cpuclk, target_freq * 1000);
+
+	if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
+		return -EINVAL;
+
+	pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+	freqs.cpu	= cpu;
+	freqs.old	= sh_cpufreq_get(cpu);
+	freqs.new	= (freq + 500) / 1000;
+	freqs.flags	= 0;
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#if defined(CONFIG_CPU_SH3)
-	frqcr |= (newstate & 0x4000) << 14;
-	frqcr |= (newstate & 0x000c) <<  2;
-#elif defined(CONFIG_CPU_SH4)
-	/*
-	 * FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
-	 * initializing the WDT.
-	 */
-	if (frqcr & (1 << 9)) {
-		__u8 csr;
-
-		/*
-		 * Set the overflow period to the highest available,
-		 * in this case a 1/4096 division ratio yields a 5.25ms
-		 * overflow period. See asm-sh/watchdog.h for more
-		 * information and a range of other divisors.
-		 */
-		csr = sh_wdt_read_csr();
-		csr |= WTCSR_CKS_4096;
-		sh_wdt_write_csr(csr);
-
-		sh_wdt_write_cnt(0);
-	}
-	frqcr &= 0x0e00;	/* Clear ifc, bfc, pfc */
-	frqcr |= get_ifc_value(clock_sets[set].ifc) << 6;
-	frqcr |= get_bfc_value(clock_sets[set].bfc) << 3;
-	frqcr |= get_pfc_value(clock_sets[set].pfc);
-#endif
-	ctrl_outw(frqcr, FRQCR);
-	sh_cpufreq_update_clocks(set);
-
 	set_cpus_allowed(current, cpus_allowed);
+	clk_set_rate(cpuclk, freq);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+	pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
 	return 0;
 }
 
 static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-	unsigned int min_freq, max_freq;
-	unsigned int ifc, bfc, pfc;
+	printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
 
 	if (!cpu_online(policy->cpu))
 		return -ENODEV;
 
-	/* Update our maximum clock set */
-	get_current_frequency_divisors(&ifc, &bfc, &pfc);
-	clock_sets[MAX_CLOCK_SET].ifc = ifc;
-	clock_sets[MAX_CLOCK_SET].bfc = bfc;
-	clock_sets[MAX_CLOCK_SET].pfc = pfc;
-
-	/* Convert from Hz to kHz */
-	max_freq = current_cpu_data.cpu_clock / 1000;
-	min_freq = (current_cpu_data.master_clock / clock_sets[MIN_CLOCK_SET].ifc) / 1000;
-	
-	sh_freqs[SH_FREQ_MAX].frequency = max_freq;
-	sh_freqs[SH_FREQ_MIN].frequency = min_freq;
+	cpuclk = clk_get(NULL, "cpu_clk");
+	if (IS_ERR(cpuclk)) {
+		printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+		return PTR_ERR(cpuclk);
+	}
 
 	/* cpuinfo and default policy values */
-	policy->governor                   = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+	policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-	policy->cur                        = max_freq;
 
-	return cpufreq_frequency_table_cpuinfo(policy, &sh_freqs[0]);
+	policy->governor	= CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cur		= sh_cpufreq_get(policy->cpu);
+	policy->min		= policy->cpuinfo.min_freq;
+	policy->max		= policy->cpuinfo.max_freq;
+
+
+	/*
+	 * Catch the cases where the clock framework hasn't been wired up
+	 * properly to support scaling.
+	 */
+	if (unlikely(policy->min == policy->max)) {
+		printk(KERN_ERR "cpufreq: clock framework rate rounding "
+		       "not supported on this CPU.\n");
+
+		clk_put(cpuclk);
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "cpufreq: Frequencies - Minimum %u.%03u MHz, "
+	       "Maximum %u.%03u MHz.\n",
+	       policy->min / 1000, policy->min % 1000,
+	       policy->max / 1000, policy->max % 1000);
+
+	return 0;
 }
 
 static int sh_cpufreq_verify(struct cpufreq_policy *policy)
 {
-	return cpufreq_frequency_table_verify(policy, &sh_freqs[0]);
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+				     policy->cpuinfo.max_freq);
+	return 0;
 }
 
-static int sh_cpufreq_target(struct cpufreq_policy *policy,
-			     unsigned int target_freq,
-			     unsigned int relation)
+static int sh_cpufreq_exit(struct cpufreq_policy *policy)
 {
-	unsigned int set, idx = 0;
-
-	if (cpufreq_frequency_table_target(policy, &sh_freqs[0], target_freq, relation, &idx))
-		return -EINVAL;
-
-	set = (idx == SH_FREQ_MIN) ? MIN_CLOCK_SET : MAX_CLOCK_SET;
-
-	sh_cpufreq_setstate(policy->cpu, set);
-
+	clk_put(cpuclk);
 	return 0;
 }
 
 static struct cpufreq_driver sh_cpufreq_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "SH cpufreq",
+	.name		= "sh",
 	.init		= sh_cpufreq_cpu_init,
 	.verify		= sh_cpufreq_verify,
 	.target		= sh_cpufreq_target,
+	.get		= sh_cpufreq_get,
+	.exit		= sh_cpufreq_exit,
 };
 
-static int __init sh_cpufreq_init(void)
+static int __init sh_cpufreq_module_init(void)
 {
-	if (!current_cpu_data.cpu_clock)
-		return -EINVAL;
-	if (cpufreq_register_driver(&sh_cpufreq_driver))
-		return -EINVAL;
-
-	return 0;
+	return cpufreq_register_driver(&sh_cpufreq_driver);
 }
 
-static void __exit sh_cpufreq_exit(void)
+static void __exit sh_cpufreq_module_exit(void)
 {
 	cpufreq_unregister_driver(&sh_cpufreq_driver);
 }
 
-module_init(sh_cpufreq_init);
-module_exit(sh_cpufreq_exit);
+module_init(sh_cpufreq_module_init);
+module_exit(sh_cpufreq_module_exit);
 
 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 MODULE_DESCRIPTION("cpufreq driver for SuperH");
 MODULE_LICENSE("GPL");
-
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 71a3ad7..0bccc0c 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -36,7 +36,8 @@
 1:
 	.skip	PAGE_SIZE - empty_zero_page - 1b
 
-	.text	
+	.section	.text.head, "ax"
+
 /*
  * Condition at the entry of _stext:
  *
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 2789779..0340498 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -253,14 +253,7 @@
 #ifdef CONFIG_CPU_HAS_PINT_IRQ
 	init_IRQ_pint();
 #endif
-
-#ifdef CONFIG_CPU_HAS_INTC2_IRQ
-	init_IRQ_intc2();
-#endif
-
-#ifdef CONFIG_CPU_HAS_IPR_IRQ
-	init_IRQ_ipr();
-#endif
+	plat_irq_setup();
 
 	/* Perform the machine specific initialisation */
 	if (sh_mv.mv_init_irq)
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index de8e6e2..c14a3e9 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/kexec.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -78,7 +79,11 @@
 static struct resource code_resource = { .name = "Kernel code", };
 static struct resource data_resource = { .name = "Kernel data", };
 
-unsigned long memory_start, memory_end;
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
 
 static int __init early_parse_mem(char *p)
 {
diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c
index 5b53e10..d1bcac4 100644
--- a/arch/sh/kernel/sh_bios.c
+++ b/arch/sh/kernel/sh_bios.c
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000 Greg Banks, Mitch Davis
  *
  */
-
+#include <linux/module.h>
 #include <asm/sh_bios.h>
 
 #define BIOS_CALL_CONSOLE_WRITE     	0
@@ -63,6 +63,7 @@
 {
     sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
 }
+EXPORT_SYMBOL(sh_bios_gdb_detach);
 
 void sh_bios_get_node_addr (unsigned char *node_addr)
 {
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index c968dcf..37aef0a 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -63,10 +63,43 @@
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrsi3);
+DECLARE_EXPORT(__ashlsi3);
 DECLARE_EXPORT(__ashrdi3);
 DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__ashiftrt_r4_6);
+DECLARE_EXPORT(__ashiftrt_r4_7);
+DECLARE_EXPORT(__ashiftrt_r4_8);
+DECLARE_EXPORT(__ashiftrt_r4_9);
+DECLARE_EXPORT(__ashiftrt_r4_10);
+DECLARE_EXPORT(__ashiftrt_r4_11);
+DECLARE_EXPORT(__ashiftrt_r4_12);
+DECLARE_EXPORT(__ashiftrt_r4_13);
+DECLARE_EXPORT(__ashiftrt_r4_14);
+DECLARE_EXPORT(__ashiftrt_r4_15);
+DECLARE_EXPORT(__ashiftrt_r4_20);
+DECLARE_EXPORT(__ashiftrt_r4_21);
+DECLARE_EXPORT(__ashiftrt_r4_22);
+DECLARE_EXPORT(__ashiftrt_r4_23);
+DECLARE_EXPORT(__ashiftrt_r4_24);
+DECLARE_EXPORT(__ashiftrt_r4_27);
+DECLARE_EXPORT(__ashiftrt_r4_30);
+DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstrSI8);
+DECLARE_EXPORT(__movstrSI12);
 DECLARE_EXPORT(__movstrSI16);
+DECLARE_EXPORT(__movstrSI20);
+DECLARE_EXPORT(__movstrSI24);
+DECLARE_EXPORT(__movstrSI28);
+DECLARE_EXPORT(__movstrSI32);
+DECLARE_EXPORT(__movstrSI36);
+DECLARE_EXPORT(__movstrSI40);
+DECLARE_EXPORT(__movstrSI44);
+DECLARE_EXPORT(__movstrSI48);
+DECLARE_EXPORT(__movstrSI52);
+DECLARE_EXPORT(__movstrSI56);
+DECLARE_EXPORT(__movstrSI60);
 #if __GNUC__ == 4
 DECLARE_EXPORT(__movmem);
 #else
@@ -115,7 +148,9 @@
 #endif
 
 EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
 #ifdef CONFIG_IPV6
 EXPORT_SYMBOL(csum_ipv6_magic);
 #endif
 EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(__clear_user);
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index ff5656e..91fb702 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -358,3 +358,4 @@
 	.long sys_signalfd
 	.long sys_timerfd
 	.long sys_eventfd
+	.long sys_fallocate
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 097ebd4..7aca37d 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -80,6 +80,7 @@
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 	}
 }
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 5ba2161..9cb95af 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -22,6 +22,7 @@
 	*(.empty_zero_page)
 	} = 0
   .text : {
+  	*(.text.head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 28d79a4..70da1c8 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -120,14 +120,14 @@
 config CPU_SUBTYPE_SH7750
 	bool "Support SH7750 processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 	help
 	  Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
 
 config CPU_SUBTYPE_SH7091
 	bool "Support SH7091 processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 	help
 	  Select SH7091 if you have an SH-4 based Sega device (such as
 	  the Dreamcast, Naomi, and Naomi 2).
@@ -135,17 +135,17 @@
 config CPU_SUBTYPE_SH7750R
 	bool "Support SH7750R processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7750S
 	bool "Support SH7750S processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7751
 	bool "Support SH7751 processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 	help
 	  Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
 	  or if you have a HD6417751R CPU.
@@ -153,7 +153,7 @@
 config CPU_SUBTYPE_SH7751R
 	bool "Support SH7751R processor"
 	select CPU_SH4
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7760
 	bool "Support SH7760 processor"
@@ -189,7 +189,7 @@
 config CPU_SUBTYPE_SH7780
 	bool "Support SH7780 processor"
 	select CPU_SH4A
-	select CPU_HAS_INTC2_IRQ
+	select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7785
 	bool "Support SH7785 processor"
@@ -217,7 +217,7 @@
 	bool "Support SH7722 processor"
 	select CPU_SH4AL_DSP
 	select CPU_SHX2
-	select CPU_HAS_IPR_IRQ
+	select CPU_HAS_INTC_IRQ
 	select ARCH_SPARSEMEM_ENABLE
 	select SYS_SUPPORTS_NUMA
 
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
index ed03508..7844341 100644
--- a/arch/sh64/configs/cayman_defconfig
+++ b/arch/sh64/configs/cayman_defconfig
@@ -1,11 +1,12 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc1
-# Mon May 14 08:43:31 2007
+# Linux kernel version: 2.6.22
+# Fri Jul 20 12:28:34 2007
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH64=y
 CONFIG_MMU=y
+CONFIG_QUICKLIST=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
@@ -32,7 +33,7 @@
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
@@ -66,19 +67,12 @@
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 # CONFIG_MODULES is not set
-
-#
-# Block layer
-#
 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
@@ -156,6 +150,8 @@
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -175,7 +171,6 @@
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -225,20 +220,8 @@
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -274,6 +257,7 @@
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -288,26 +272,10 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -323,18 +291,11 @@
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 # CONFIG_IDE is not set
 
 #
@@ -342,6 +303,7 @@
 #
 # 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
@@ -410,13 +372,8 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -432,30 +389,16 @@
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 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
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_STNIC is not set
@@ -464,10 +407,6 @@
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -510,7 +449,6 @@
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -524,11 +462,6 @@
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -546,15 +479,7 @@
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -562,6 +487,7 @@
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -638,10 +564,6 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -658,15 +580,10 @@
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
@@ -676,20 +593,24 @@
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -739,7 +660,6 @@
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -765,6 +685,7 @@
 #
 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=y
 # CONFIG_FONT_8x8 is not set
@@ -789,16 +710,10 @@
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -826,17 +741,9 @@
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
 #
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
 # Real Time Clock
 #
 # CONFIG_RTC_CLASS is not set
@@ -855,6 +762,11 @@
 #
 
 #
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -950,7 +862,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1001,6 +912,7 @@
 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
@@ -1017,7 +929,6 @@
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
@@ -1033,10 +944,6 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1047,6 +954,7 @@
 # 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_PLIST=y
 CONFIG_HAS_IOMEM=y
diff --git a/arch/sh64/kernel/head.S b/arch/sh64/kernel/head.S
index f3740dd..186406d 100644
--- a/arch/sh64/kernel/head.S
+++ b/arch/sh64/kernel/head.S
@@ -124,7 +124,7 @@
 fpu_in_use:	.quad	0
 
 
-	.section	.text, "ax"
+	.section	.text.head, "ax"
 	.balign L1_CACHE_BYTES
 /*
  * Condition at the entry of __stext:
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
index 3334f99..388bb71 100644
--- a/arch/sh64/kernel/pci_sh5.c
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -48,7 +48,7 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
 	return str;
 }
@@ -497,7 +497,7 @@
 
 subsys_initcall(pcibios_init);
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 	struct pci_dev *dev = bus->self;
 	int i;
diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S
index a5c680d..abb94c0 100644
--- a/arch/sh64/kernel/syscalls.S
+++ b/arch/sh64/kernel/syscalls.S
@@ -378,3 +378,4 @@
 	.long sys_signalfd
 	.long sys_timerfd		/* 350 */
 	.long sys_eventfd
+	.long sys_fallocate
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index 8ac9c7c..267b4f9 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -54,6 +54,7 @@
 	} = 0
 
   .text : C_PHYS(.text) {
+  	*(.text.head)
 	TEXT_TEXT
 	*(.text64)
         *(.text..SHmedia32)
diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
index ff26c02..9908577 100644
--- a/arch/sh64/mm/ioremap.c
+++ b/arch/sh64/mm/ioremap.c
@@ -242,7 +242,7 @@
 	release_resource(res);
 }
 
-static void *sh64_get_page(void)
+static __init_refok void *sh64_get_page(void)
 {
 	extern int after_bootmem;
 	void *page;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 603d83a..9d327ec 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -24,6 +24,9 @@
 config ARCH_NO_VIRT_TO_BUS
 	def_bool y
 
+config OF
+	def_bool y
+
 source "init/Kconfig"
 
 menu "General machine setup"
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 7bb86b9..ac352eb 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -148,6 +148,7 @@
 {
 	const struct linux_prom_registers *regs;
 	struct linux_ebus_child *child;
+	struct dev_archdata *sd;
 	const int *irqs;
 	int i, n, len;
 	unsigned long baseaddr;
@@ -234,6 +235,10 @@
 		}
 	}
 
+	sd = &dev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &dev->ofdev;
+
 	dev->ofdev.node = dp;
 	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
 	dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 831f540..eac3838 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1749,8 +1749,8 @@
 __ndelay:
 	save	%sp, -STACKFRAME_SZ, %sp
 	mov	%i0, %o0
-	call	.umul
-	 mov	0x1ad, %o1		! 2**32 / (1 000 000 000 / HZ)
+	call	.umul			! round multiplier up so large ns ok
+	 mov	0x1ae, %o1		! 2**32 / (1 000 000 000 / HZ)
 	call	.umul
 	 mov	%i1, %o1		! udelay_val
 	ba	delay_continue
@@ -1760,11 +1760,17 @@
 __udelay:
 	save	%sp, -STACKFRAME_SZ, %sp
 	mov	%i0, %o0
-	sethi	%hi(0x10c6), %o1
+	sethi	%hi(0x10c7), %o1	! round multiplier up so large us ok
 	call	.umul
-	 or	%o1, %lo(0x10c6), %o1	! 2**32 / 1 000 000
+	 or	%o1, %lo(0x10c7), %o1	! 2**32 / 1 000 000
 	call	.umul
 	 mov	%i1, %o1		! udelay_val
+	sethi	%hi(0x028f4b62), %l0	! Add in rounding constant * 2**32,
+	or	%g0, %lo(0x028f4b62), %l0
+	addcc	%o0, %l0, %o0		! 2**32 * 0.009 999
+	bcs,a	3f
+	 add	%o1, 0x01, %o1
+3:
 	call	.umul
 	 mov	HZ, %o0			! >>32 earlier for wider range
 
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index f257a67..75b2240 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -47,6 +47,8 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 #ifdef CONFIG_SMP
 #define SMP_NOP2 "nop; nop;\n\t"
 #define SMP_NOP3 "nop; nop; nop;\n\t"
@@ -268,7 +270,7 @@
 	kfree(action);
 
 	if (!sparc_irq[cpu_irq].action)
-		disable_irq(irq);
+		__disable_irq(irq);
 
 out_unlock:
 	spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -464,7 +466,7 @@
 
 	sparc_irq[cpu_irq].action = action;
 
-	enable_irq(irq);
+	__enable_irq(irq);
 
 	ret = 0;
 out_unlock:
@@ -544,7 +546,7 @@
 
 	*actionp = action;
 
-	enable_irq(irq);
+	__enable_irq(irq);
 
 	ret = 0;
 out_unlock:
@@ -555,6 +557,25 @@
 
 EXPORT_SYMBOL(request_irq);
 
+void disable_irq_nosync(unsigned int irq)
+{
+	return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq_nosync);
+
+void disable_irq(unsigned int irq)
+{
+	return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq);
+
+void enable_irq(unsigned int irq)
+{
+	return __enable_irq(irq);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
 /* We really don't need these at all on the Sparc.  We only have
  * stubs here because they are exported to modules.
  */
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
new file mode 100644
index 0000000..32ef3eb
--- /dev/null
+++ b/arch/sparc/kernel/irq.h
@@ -0,0 +1,68 @@
+#include <asm/btfixup.h>
+
+/* Dave Redman (djhr@tadpole.co.uk)
+ * changed these to function pointers.. it saves cycles and will allow
+ * the irq dependencies to be split into different files at a later date
+ * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
+ * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Changed these to btfixup entities... It saves cycles :)
+ */
+
+BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, clear_clock_irq, void)
+BTFIXUPDEF_CALL(void, clear_profile_irq, int)
+BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
+
+static inline void __disable_irq(unsigned int irq)
+{
+	BTFIXUP_CALL(disable_irq)(irq);
+}
+
+static inline void __enable_irq(unsigned int irq)
+{
+	BTFIXUP_CALL(enable_irq)(irq);
+}
+
+static inline void disable_pil_irq(unsigned int irq)
+{
+	BTFIXUP_CALL(disable_pil_irq)(irq);
+}
+
+static inline void enable_pil_irq(unsigned int irq)
+{
+	BTFIXUP_CALL(enable_pil_irq)(irq);
+}
+
+static inline void clear_clock_irq(void)
+{
+	BTFIXUP_CALL(clear_clock_irq)();
+}
+
+static inline void clear_profile_irq(int irq)
+{
+	BTFIXUP_CALL(clear_profile_irq)(irq);
+}
+
+static inline void load_profile_irq(int cpu, int limit)
+{
+	BTFIXUP_CALL(load_profile_irq)(cpu, limit);
+}
+
+extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
+
+extern void claim_ticker14(irq_handler_t irq_handler,
+			   int irq,
+			   unsigned int timeout);
+
+#ifdef CONFIG_SMP
+BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, set_irq_udt, int)
+
+#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
+#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
+#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
+#endif
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index fd7f8cb..36383f7 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -1,132 +1,13 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-					const struct of_device *dev)
-{
-	if (!dev->node)
-		return NULL;
-	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-		int match = 1;
-		if (matches->name[0])
-			match &= dev->node->name
-				&& !strcmp(matches->name, dev->node->name);
-		if (matches->type[0])
-			match &= dev->node->type
-				&& !strcmp(matches->type, dev->node->type);
-		if (matches->compatible[0])
-			match &= of_device_is_compatible(dev->node,
-							 matches->compatible);
-		if (match)
-			return matches;
-		matches++;
-	}
-	return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_device_id * matches = of_drv->match_table;
-
-	if (!matches)
-		return 0;
-
-	return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-	struct device *tmp;
-
-	if (!dev)
-		return NULL;
-	tmp = get_device(&dev->dev);
-	if (tmp)
-		return to_of_device(tmp);
-	else
-		return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-	if (dev)
-		put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-	int error = -ENODEV;
-	struct of_platform_driver *drv;
-	struct of_device *of_dev;
-	const struct of_device_id *match;
-
-	drv = to_of_platform_driver(dev->driver);
-	of_dev = to_of_device(dev);
-
-	if (!drv->probe)
-		return error;
-
-	of_dev_get(of_dev);
-
-	match = of_match_device(drv->match_table, of_dev);
-	if (match)
-		error = drv->probe(of_dev, match);
-	if (error)
-		of_dev_put(of_dev);
-
-	return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-	if (dev->driver && drv->remove)
-		drv->remove(of_dev);
-	return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->suspend)
-		error = drv->suspend(of_dev, state);
-	return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->resume)
-		error = drv->resume(of_dev);
-	return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 static int node_match(struct device *dev, void *data)
 {
@@ -138,7 +19,7 @@
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-	struct device *dev = bus_find_device(&of_bus_type, NULL,
+	struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
 					     dp, node_match);
 
 	if (dev)
@@ -149,38 +30,17 @@
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type ebus_bus_type = {
-       .name	= "ebus",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name	= "sbus",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name	= "of",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -560,11 +420,16 @@
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
 	const struct linux_prom_irqs *intr;
+	struct dev_archdata *sd;
 	int len, i;
 
 	if (!op)
 		return NULL;
 
+	sd = &op->dev.archdata;
+	sd->prom_node = dp;
+	sd->op = op;
+
 	op->node = dp;
 
 	op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -646,7 +511,7 @@
 	build_device_resources(op, parent);
 
 	op->dev.parent = parent;
-	op->dev.bus = &of_bus_type;
+	op->dev.bus = &of_platform_bus_type;
 	if (!parent)
 		strcpy(op->dev.bus_id, "root");
 	else
@@ -690,14 +555,14 @@
 {
 	int err;
 
-	err = bus_register(&of_bus_type);
+	err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
 	if (!err)
-		err = bus_register(&ebus_bus_type);
+		err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
 	if (!err)
-		err = bus_register(&sbus_bus_type);
+		err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
 	if (!err)
@@ -735,56 +600,6 @@
 	driver_unregister(&drv->driver);
 }
 
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct of_device *ofdev;
-
-	ofdev = to_of_device(dev);
-	return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-	struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-	kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-	int rc;
-
-	BUG_ON(ofdev->node == NULL);
-
-	rc = device_register(&ofdev->dev);
-	if (rc)
-		return rc;
-
-	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-	if (rc)
-		device_unregister(&ofdev->dev);
-
-	return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-	device_remove_file(&ofdev->dev, &dev_attr_devspec);
-	device_unregister(&ofdev->dev);
-}
-
 struct of_device* of_platform_device_create(struct device_node *np,
 					    const char *bus_id,
 					    struct device *parent,
@@ -810,12 +625,6 @@
 	return dev;
 }
 
-EXPORT_SYMBOL(of_match_device);
 EXPORT_SYMBOL(of_register_driver);
 EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 7917711..f2eae45 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -36,6 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
 
 /*
  * I studied different documents and many live PROMs both from 2.30
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 8c37f8f..33f7a3d 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -39,6 +39,7 @@
 #include <asm/processor.h>
 #include <asm/psr.h>
 #include <asm/elf.h>
+#include <asm/prom.h>
 #include <asm/unistd.h>
 
 /* 
@@ -150,7 +151,7 @@
 	local_irq_enable();
 	mdelay(8);
 	local_irq_disable();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	prom_halt();
 	panic("Halt failed!");
@@ -166,7 +167,7 @@
 
 	p = strchr (reboot_command, '\n');
 	if (p) *p = 0;
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (cmd)
 		prom_reboot(cmd);
@@ -179,7 +180,8 @@
 void machine_power_off(void)
 {
 #ifdef CONFIG_SUN_AUXIO
-	if (auxio_power_register && (!serial_console || scons_pwroff))
+	if (auxio_power_register &&
+	    (strcmp(of_console_device->type, "serial") || scons_pwroff))
 		*auxio_power_register |= AUXIO_POWER_OFF;
 #endif
 	machine_halt();
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index eed140b..e3a5376 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -25,73 +25,9 @@
 #include <asm/prom.h>
 #include <asm/oplib.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;	/* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-			    const char *compat)
-{
-	const char* cp;
-	int cplen, l;
-
-	cp = of_get_property(device, "compatible", &cplen);
-	if (cp == NULL)
-		return 0;
-	while (cplen > 0) {
-		if (strncmp(cp, compat, strlen(compat)) == 0)
-			return 1;
-		l = strlen(cp) + 1;
-		cp += l;
-		cplen -= l;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-	struct device_node *np;
-
-	if (!node)
-		return NULL;
-
-	np = node->parent;
-
-	return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-	struct device_node *prev)
-{
-	struct device_node *next;
-
-	next = prev ? prev->sibling : node->child;
-	for (; next != 0; next = next->sibling) {
-		break;
-	}
-
-	return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-	struct device_node *np = allnodes;
-
-	for (; np != 0; np = np->allnext) {
-		if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-			break;
-	}
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;	/* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -105,81 +41,6 @@
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != NULL; np = np->allnext)
-		if (np->name != NULL && strcmp(np->name, name) == 0)
-			break;
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext)
-		if (np->type != 0 && strcmp(np->type, type) == 0)
-			break;
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compatible)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcmp(np->type, type) == 0))
-			continue;
-		if (of_device_is_compatible(np, compatible))
-			break;
-	}
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-				  const char *name,
-				  int *lenp)
-{
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		if (strcasecmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			break;
-		}
-	}
-	return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-			    int *lenp)
-{
-	struct property *pp = of_find_property(np,name,lenp);
-	return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
 	struct property *prop;
@@ -193,36 +54,6 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-	const int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#address-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #address-cells property for the root node, default to 2 */
-	return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-	const int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#size-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #size-cells property for the root node, default to 1 */
-	return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
 	struct property **prevp;
@@ -566,6 +397,135 @@
 	return dp;
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+	char *msg = "OF stdout device is: %s\n";
+	struct device_node *dp;
+	unsigned long flags;
+	const char *type;
+	phandle node;
+	int skip, fd;
+
+	of_console_path = prom_early_alloc(256);
+
+	switch (prom_vers) {
+	case PROM_V0:
+	case PROM_SUN4:
+		skip = 0;
+		switch (*romvec->pv_stdout) {
+		case PROMDEV_SCREEN:
+			type = "display";
+			break;
+
+		case PROMDEV_TTYB:
+			skip = 1;
+			/* FALLTHRU */
+
+		case PROMDEV_TTYA:
+			type = "serial";
+			break;
+
+		default:
+			prom_printf("Invalid PROM_V0 stdout value %u\n",
+				    *romvec->pv_stdout);
+			prom_halt();
+		}
+
+		for_each_node_by_type(dp, type) {
+			if (!skip--)
+				break;
+		}
+		if (!dp) {
+			prom_printf("Cannot find PROM_V0 console node.\n");
+			prom_halt();
+		}
+		of_console_device = dp;
+
+		strcpy(of_console_path, dp->full_name);
+		if (!strcmp(type, "serial")) {
+			strcat(of_console_path,
+			       (skip ? ":b" : ":a"));
+		}
+		break;
+
+	default:
+	case PROM_V2:
+	case PROM_V3:
+		fd = *romvec->pv_v2bootargs.fd_stdout;
+
+		spin_lock_irqsave(&prom_lock, flags);
+		node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+		restore_current();
+		spin_unlock_irqrestore(&prom_lock, flags);
+
+		if (!node) {
+			prom_printf("Cannot resolve stdout node from "
+				    "instance %08x.\n", fd);
+			prom_halt();
+		}
+		dp = of_find_node_by_phandle(node);
+		type = of_get_property(dp, "device_type", NULL);
+
+		if (!type) {
+			prom_printf("Console stdout lacks "
+				    "device_type property.\n");
+			prom_halt();
+		}
+
+		if (strcmp(type, "display") && strcmp(type, "serial")) {
+			prom_printf("Console device_type is neither display "
+				    "nor serial.\n");
+			prom_halt();
+		}
+
+		of_console_device = dp;
+
+		if (prom_vers == PROM_V2) {
+			strcpy(of_console_path, dp->full_name);
+			switch (*romvec->pv_stdout) {
+			case PROMDEV_TTYA:
+				strcat(of_console_path, ":a");
+				break;
+			case PROMDEV_TTYB:
+				strcat(of_console_path, ":b");
+				break;
+			}
+		} else {
+			const char *path;
+
+			dp = of_find_node_by_path("/");
+			path = of_get_property(dp, "stdout-path", NULL);
+			if (!path) {
+				prom_printf("No stdout-path in root node.\n");
+				prom_halt();
+			}
+			strcpy(of_console_path, path);
+		}
+		break;
+	}
+
+	of_console_options = strrchr(of_console_path, ':');
+	if (of_console_options) {
+		of_console_options++;
+		if (*of_console_options == '\0')
+			of_console_options = NULL;
+	}
+
+	prom_printf(msg, of_console_path);
+	printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
 	struct device_node **nextp;
@@ -578,6 +538,8 @@
 	allnodes->child = build_tree(allnodes,
 				     prom_getchild(allnodes->node),
 				     &nextp);
+	of_console_init();
+
 	printk("PROM: Built device tree with %u bytes of memory.\n",
 	       prom_early_allocated);
 }
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 64c0ed9..f822838 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -146,31 +146,6 @@
 	}
 }
 
-static void __init process_console(char *commands)
-{
-	serial_console = 0;
-	commands += 8;
-	/* Linux-style serial */
-	if (!strncmp(commands, "ttyS", 4))
-		serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-	else if (!strncmp(commands, "tty", 3)) {
-		char c = *(commands + 3);
-		/* Solaris-style serial */
-		if (c == 'a' || c == 'b')
-			serial_console = c - 'a' + 1;
-		/* else Linux-style fbcon, not serial */
-	}
-#if defined(CONFIG_PROM_CONSOLE)
-	if (!strncmp(commands, "prom", 4)) {
-		char *p;
-
-		for (p = commands - 8; *p && *p != ' '; p++)
-			*p = ' ';
-		conswitchp = &prom_con;
-	}
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
 	while (*commands) {
@@ -187,9 +162,7 @@
 				process_switch(*commands++);
 			continue;
 		}
-		if (!strncmp(commands, "console=", 8)) {
-			process_console(commands);
-		} else if (!strncmp(commands, "mem=", 4)) {
+		if (!strncmp(commands, "mem=", 4)) {
 			/*
 			 * "mem=XXX[kKmM] overrides the PROM-reported
 			 * memory size.
@@ -341,41 +314,6 @@
 	smp_setup_cpu_possible_map();
 }
 
-static int __init set_preferred_console(void)
-{
-	int idev, odev;
-
-	/* The user has requested a console so this is already set up. */
-	if (serial_console >= 0)
-		return -EBUSY;
-
-	idev = prom_query_input_device();
-	odev = prom_query_output_device();
-	if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-	} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-		serial_console = 1;
-	} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-		serial_console = 2;
-	} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-		prom_printf("MrCoffee ttya\n");
-		serial_console = 1;
-	} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-		prom_printf("MrCoffee keyboard\n");
-	} else {
-		prom_printf("Confusing console (idev %d, odev %d)\n",
-		    idev, odev);
-		serial_console = 1;
-	}
-
-	if (serial_console)
-		return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-	return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 extern char *sparc_cpu_type;
 extern char *sparc_fpu_type;
 
@@ -461,7 +399,6 @@
 	prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
 
 static int __init topology_init(void)
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 4fea3ac..6724ab9 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -33,6 +33,8 @@
 #include <asm/tlbflush.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
+
 int smp_num_cpus = 1;
 volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
 unsigned char boot_cpu_id = 0;
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index d8e008a..55bac51 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -154,8 +154,6 @@
 #else
 EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
 #endif
-EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq));
-EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
 EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 009e891..c6ac9fc 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include "irq.h"
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -40,6 +41,20 @@
 static struct resource sun4c_intr_eb = { "sun4c_intr" };
 #endif
 
+/*
+ * Bit field defines for the interrupt registers on various
+ * Sparc machines.
+ */
+
+/* The sun4c interrupt register. */
+#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
+#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
+#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
+#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
+#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
+#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
+#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
+
 /* Pointer to the interrupt enable byte
  *
  * Dave Redman (djhr@tadpole.co.uk)
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 396797e..e0efab2 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -39,6 +39,8 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
 /* #define DISTRIBUTE_IRQS */
 
@@ -188,7 +190,7 @@
 	kfree(action);
 
 	if (!(*actionp))
-		disable_irq(irq);
+		__disable_irq(irq);
 
 out_unlock:
 	spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -346,7 +348,7 @@
 	else
 		*actionp = action;
 		
-	enable_irq(irq);
+	__enable_irq(irq);
 
 	ret = 0;
 out_unlock:
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 098c94f..89a6de9 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -36,6 +36,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
 #define IRQ_CROSS_CALL		15
 
 extern ctxd_t *srmmu_ctx_table_phys;
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 91a803e..b92d6d2 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -38,11 +38,85 @@
 #include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
+#include "irq.h"
+
+/* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+ */
+
+/* These registers are used for sending/receiving irqs from/to
+ * different cpu's.
+ */
+struct sun4m_intreg_percpu {
+	unsigned int tbt;        /* Interrupts still pending for this cpu. */
+
+	/* These next two registers are WRITE-ONLY and are only
+	 * "on bit" sensitive, "off bits" written have NO affect.
+	 */
+	unsigned int clear;  /* Clear this cpus irqs here. */
+	unsigned int set;    /* Set this cpus irqs here. */
+	unsigned char space[PAGE_SIZE - 12];
+};
+
+/*
+ * djhr
+ * Actually the clear and set fields in this struct are misleading..
+ * according to the SLAVIO manual (and the same applies for the SEC)
+ * the clear field clears bits in the mask which will ENABLE that IRQ
+ * the set field sets bits in the mask to DISABLE the IRQ.
+ *
+ * Also the undirected_xx address in the SLAVIO is defined as
+ * RESERVED and write only..
+ *
+ * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
+ *             sun4m machines, for MP the layout makes more sense.
+ */
+struct sun4m_intregs {
+	struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
+	unsigned int tbt;                /* IRQ's that are still pending. */
+	unsigned int irqs;               /* Master IRQ bits. */
+
+	/* Again, like the above, two these registers are WRITE-ONLY. */
+	unsigned int clear;              /* Clear master IRQ's by setting bits here. */
+	unsigned int set;                /* Set master IRQ's by setting bits here. */
+
+	/* This register is both READ and WRITE. */
+	unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+};
+
 static unsigned long dummy;
 
 struct sun4m_intregs *sun4m_interrupts;
 unsigned long *irq_rcvreg = &dummy;
 
+/* Dave Redman (djhr@tadpole.co.uk)
+ * The sun4m interrupt registers.
+ */
+#define SUN4M_INT_ENABLE  	0x80000000
+#define SUN4M_INT_E14     	0x00000080
+#define SUN4M_INT_E10     	0x00080000
+
+#define SUN4M_HARD_INT(x)	(0x000000001 << (x))
+#define SUN4M_SOFT_INT(x)	(0x000010000 << (x))
+
+#define	SUN4M_INT_MASKALL	0x80000000	  /* mask all interrupts */
+#define	SUN4M_INT_MODULE_ERR	0x40000000	  /* module error */
+#define	SUN4M_INT_M2S_WRITE	0x20000000	  /* write buffer error */
+#define	SUN4M_INT_ECC		0x10000000	  /* ecc memory error */
+#define	SUN4M_INT_FLOPPY	0x00400000	  /* floppy disk */
+#define	SUN4M_INT_MODULE	0x00200000	  /* module interrupt */
+#define	SUN4M_INT_VIDEO		0x00100000	  /* onboard video */
+#define	SUN4M_INT_REALTIME	0x00080000	  /* system timer */
+#define	SUN4M_INT_SCSI		0x00040000	  /* onboard scsi */
+#define	SUN4M_INT_AUDIO		0x00020000	  /* audio/isdn */
+#define	SUN4M_INT_ETHERNET	0x00010000	  /* onboard ethernet */
+#define	SUN4M_INT_SERIAL	0x00008000	  /* serial ports */
+#define	SUN4M_INT_KBDMS		0x00004000	  /* keyboard/mouse */
+#define	SUN4M_INT_SBUSBITS	0x00003F80	  /* sbus int bits */
+
+#define SUN4M_INT_SBUS(x)	(1 << (x+7))
+#define SUN4M_INT_VME(x)	(1 << (x))
+
 /* These tables only apply for interrupts greater than 15..
  * 
  * any intr value below 0x10 is considered to be a soft-int
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 63ed19b..730eb57 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -31,6 +31,8 @@
 #include <asm/oplib.h>
 #include <asm/cpudata.h>
 
+#include "irq.h"
+
 #define IRQ_RESCHEDULE		13
 #define IRQ_STOP_CPU		14
 #define IRQ_CROSS_CALL		15
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 90b52d4..5572284 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.103 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * Based upon preliminary work which is:
  *
@@ -80,7 +79,7 @@
 /*295*/	.long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/	.long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/	.long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/	.long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/	.long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
@@ -198,6 +197,6 @@
 	.long sunos_nosys, sunos_nosys, sunos_nosys
 	.long sunos_nosys
 /*310*/	.long sunos_nosys, sunos_nosys, sunos_nosys
-	.long sunos_nosys
+	.long sunos_nosys, sunos_nosys
 
 #endif
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index f1a7bd1..707bfda 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -25,6 +25,8 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 
+#include "irq.h"
+
 extern unsigned long lvl14_save[5];
 static unsigned long *linux_lvl14 = NULL;
 static unsigned long obp_lvl14[4];
@@ -62,7 +64,7 @@
 
 	/* first we copy the obp handler instructions
 	 */
-	disable_irq(irq_nr);
+	__disable_irq(irq_nr);
 	if (!handler)
 		return;
     
@@ -79,6 +81,6 @@
 			 NULL)) {
 		install_linux_ticker();
 		load_profile_irq(cpu, timeout);
-		enable_irq(irq_nr);
+		__enable_irq(irq_nr);
 	}
 }
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 7b4612d..6a25133 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -44,6 +44,8 @@
 #include <asm/of_device.h>
 #include <asm/irq_regs.h>
 
+#include "irq.h"
+
 DEFINE_SPINLOCK(rtc_lock);
 enum sparc_clock_type sp_clock_typ;
 DEFINE_SPINLOCK(mostek_lock);
@@ -354,7 +356,7 @@
 /* Probe for the mostek real time clock chip. */
 static int __init clock_init(void)
 {
-	return of_register_driver(&clock_driver, &of_bus_type);
+	return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index a532922..a1bef07 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -308,6 +308,9 @@
 extern void srmmu_paging_init(void);
 extern void device_scan(void);
 
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
 void __init paging_init(void)
 {
 	switch(sparc_cpu_model) {
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index ca26232..17b485f 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -2154,7 +2154,7 @@
 	BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
 
 	BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
-	BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED));
+	PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED);
 	BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
 	BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
 	BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index bdd835f..a57a366 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -2155,7 +2155,7 @@
 	BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE);
 
 	BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE));
-	BTFIXUPSET_INT(page_shared, pgprot_val(SUN4C_PAGE_SHARED));
+	PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED);
 	BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY));
 	BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
 	BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 4e6e41d..8d1cfb0 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -102,119 +102,3 @@
 	while(prom_nbputchar(c) == -1) ;
 	return;
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-	unsigned long flags;
-	int st_p;
-	char propb[64];
-	char *p;
-	int propl;
-
-	switch(prom_vers) {
-	case PROM_V0:
-	case PROM_V2:
-	case PROM_SUN4:
-	default:
-		switch(*romvec->pv_stdin) {
-		case PROMDEV_KBD:	return PROMDEV_IKBD;
-		case PROMDEV_TTYA:	return PROMDEV_ITTYA;
-		case PROMDEV_TTYB:	return PROMDEV_ITTYB;
-		default:
-			return PROMDEV_I_UNK;
-		};
-	case PROM_V3:
-		spin_lock_irqsave(&prom_lock, flags);
-		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
-		restore_current();
-		spin_unlock_irqrestore(&prom_lock, flags);
-		if(prom_node_has_property(st_p, "keyboard"))
-			return PROMDEV_IKBD;
-		if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
-			if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
-				return PROMDEV_IKBD;
-		}
-		if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
-		if(strncmp(propb, "serial", sizeof("serial")))
-			return PROMDEV_I_UNK;
-		}
-		propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
-		if(propl > 2) {
-			p = propb;
-			while(*p) p++; p -= 2;
-			if(p[0] == ':') {
-				if(p[1] == 'a')
-					return PROMDEV_ITTYA;
-				else if(p[1] == 'b')
-					return PROMDEV_ITTYB;
-			}
-		}
-		return PROMDEV_I_UNK;
-	}
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-	unsigned long flags;
-	int st_p;
-	char propb[64];
-	char *p;
-	int propl;
-
-	switch(prom_vers) {
-	case PROM_V0:
-	case PROM_SUN4:
-		switch(*romvec->pv_stdin) {
-		case PROMDEV_SCREEN:	return PROMDEV_OSCREEN;
-		case PROMDEV_TTYA:	return PROMDEV_OTTYA;
-		case PROMDEV_TTYB:	return PROMDEV_OTTYB;
-		};
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		spin_lock_irqsave(&prom_lock, flags);
-		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
-		restore_current();
-		spin_unlock_irqrestore(&prom_lock, flags);
-		propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-		if (propl == sizeof("display") &&
-			strncmp("display", propb, sizeof("display")) == 0)
-		{
-			return PROMDEV_OSCREEN;
-		}
-		if(prom_vers == PROM_V3) {
-			if(propl >= 0 &&
-			    strncmp("serial", propb, sizeof("serial")) != 0)
-				return PROMDEV_O_UNK;
-			propl = prom_getproperty(prom_root_node, "stdout-path",
-						 propb, sizeof(propb));
-			if(propl == CON_SIZE_JMC &&
-			    strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
-				return PROMDEV_OTTYA;
-			if(propl > 2) {
-				p = propb;
-				while(*p) p++; p-= 2;
-				if(p[0]==':') {
-					if(p[1] == 'a')
-						return PROMDEV_OTTYA;
-					else if(p[1] == 'b')
-						return PROMDEV_OTTYB;
-				}
-			}
-		} else {
-			switch(*romvec->pv_stdin) {
-			case PROMDEV_TTYA:	return PROMDEV_OTTYA;
-			case PROMDEV_TTYB:	return PROMDEV_OTTYB;
-			};
-		}
-		break;
-	default:
-		;
-	};
-	return PROMDEV_O_UNK;
-}
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
index 1942c7c..37cff5f 100644
--- a/arch/sparc/prom/misc.c
+++ b/arch/sparc/prom/misc.c
@@ -58,7 +58,7 @@
 	extern void install_linux_ticker(void);
 	unsigned long flags;
 
-	if(!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	spin_lock_irqsave(&prom_lock, flags);
 	install_obp_ticker();
@@ -69,7 +69,7 @@
 #ifdef CONFIG_SUN_AUXIO
 	set_auxio(AUXIO_LED, 0);
 #endif
-	if(!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (0);
 }
 
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index df6ee71..33dabf5 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -23,6 +23,10 @@
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config GENERIC_CLOCKEVENTS
 	bool
 	default y
@@ -65,6 +69,9 @@
 config ARCH_NO_VIRT_TO_BUS
 	def_bool y
 
+config OF
+	def_bool y
+
 choice
 	prompt "Kernel page size"
 	default SPARC64_PAGE_SIZE_8KB
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 45ebf91..10e3019 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.22
-# Tue Jul 17 01:19:52 2007
+# Thu Jul 19 21:30:37 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -16,6 +16,7 @@
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_SPARC64_PAGE_SIZE_8KB=y
 # CONFIG_SPARC64_PAGE_SIZE_64KB is not set
 # CONFIG_SPARC64_PAGE_SIZE_512KB is not set
@@ -148,7 +149,6 @@
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_SUN_AUXIO=y
@@ -317,7 +317,6 @@
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
@@ -470,10 +469,6 @@
 # CONFIG_SCSI_SUNESP is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -610,10 +605,6 @@
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 # CONFIG_PHONE is not set
 
@@ -782,6 +773,7 @@
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
@@ -808,11 +800,13 @@
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -906,6 +900,7 @@
 # CONFIG_PROM_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -1196,6 +1191,11 @@
 #
 
 #
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
 # Misc Linux/SPARC drivers
 #
 CONFIG_SUN_OPENPROMIO=m
@@ -1385,6 +1385,7 @@
 # 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
@@ -1461,6 +1462,7 @@
 CONFIG_CRC16=m
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 826118ee..7b37976 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -155,7 +155,7 @@
 
 static int __init auxio_init(void)
 {
-	return of_register_driver(&auxio_driver, &of_bus_type);
+	return of_register_driver(&auxio_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index fa1f04d..9f472a7 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -13,11 +13,11 @@
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
+#include <linux/reboot.h>
 #include <linux/cpu.h>
 
 #include <asm/ldc.h>
 #include <asm/vio.h>
-#include <asm/power.h>
 #include <asm/mdesc.h>
 #include <asm/head.h>
 #include <asm/irq.h>
@@ -124,10 +124,11 @@
 	__u64			result;
 };
 
+struct ds_info;
 struct ds_cap_state {
 	__u64			handle;
 
-	void			(*data)(struct ldc_channel *lp,
+	void			(*data)(struct ds_info *dp,
 					struct ds_cap_state *cp,
 					void *buf, int len);
 
@@ -139,27 +140,27 @@
 #define CAP_STATE_REGISTERED	0x02
 };
 
-static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
 			   void *buf, int len);
-static void domain_shutdown_data(struct ldc_channel *lp,
+static void domain_shutdown_data(struct ds_info *dp,
 				 struct ds_cap_state *cp,
 				 void *buf, int len);
-static void domain_panic_data(struct ldc_channel *lp,
+static void domain_panic_data(struct ds_info *dp,
 			      struct ds_cap_state *cp,
 			      void *buf, int len);
 #ifdef CONFIG_HOTPLUG_CPU
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
 #endif
-static void ds_pri_data(struct ldc_channel *lp,
+static void ds_pri_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
-static void ds_var_data(struct ldc_channel *lp,
+static void ds_var_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len);
 
-struct ds_cap_state ds_states[] = {
+struct ds_cap_state ds_states_template[] = {
 	{
 		.service_id	= "md-update",
 		.data		= md_update_data,
@@ -200,30 +201,38 @@
 #define DS_HS_START		0x01
 #define DS_HS_DONE		0x02
 
+	u64			id;
+
 	void			*rcv_buf;
 	int			rcv_buf_len;
+
+	struct ds_cap_state	*ds_states;
+	int			num_ds_states;
+
+	struct ds_info		*next;
 };
 
-static struct ds_info *ds_info;
+static struct ds_info *ds_info_list;
 
-static struct ds_cap_state *find_cap(u64 handle)
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
 {
 	unsigned int index = handle >> 32;
 
-	if (index >= ARRAY_SIZE(ds_states))
+	if (index >= dp->num_ds_states)
 		return NULL;
-	return &ds_states[index];
+	return &dp->ds_states[index];
 }
 
-static struct ds_cap_state *find_cap_by_string(const char *name)
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+					       const char *name)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-		if (strcmp(ds_states[i].service_id, name))
+	for (i = 0; i < dp->num_ds_states; i++) {
+		if (strcmp(dp->ds_states[i].service_id, name))
 			continue;
 
-		return &ds_states[i];
+		return &dp->ds_states[i];
 	}
 	return NULL;
 }
@@ -264,10 +273,11 @@
 	__u32				result;
 };
 
-static void md_update_data(struct ldc_channel *lp,
-			   struct ds_cap_state *dp,
+static void md_update_data(struct ds_info *dp,
+			   struct ds_cap_state *cp,
 			   void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_md_update_req *rp;
 	struct {
@@ -277,14 +287,14 @@
 
 	rp = (struct ds_md_update_req *) (dpkt + 1);
 
-	printk(KERN_INFO PFX "Machine description update.\n");
+	printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
 
 	mdesc_update();
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 
@@ -302,10 +312,11 @@
 	char				reason[1];
 };
 
-static void domain_shutdown_data(struct ldc_channel *lp,
-				 struct ds_cap_state *dp,
+static void domain_shutdown_data(struct ds_info *dp,
+				 struct ds_cap_state *cp,
 				 void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_shutdown_req *rp;
 	struct {
@@ -315,20 +326,20 @@
 
 	rp = (struct ds_shutdown_req *) (dpkt + 1);
 
-	printk(KERN_ALERT PFX "Shutdown request from "
-	       "LDOM manager received.\n");
+	printk(KERN_ALERT "ds-%lu: Shutdown request from "
+	       "LDOM manager received.\n", dp->id);
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 	pkt.res.reason[0] = 0;
 
 	ds_send(lp, &pkt, sizeof(pkt));
 
-	wake_up_powerd();
+	orderly_poweroff(true);
 }
 
 struct ds_panic_req {
@@ -341,10 +352,11 @@
 	char				reason[1];
 };
 
-static void domain_panic_data(struct ldc_channel *lp,
-			      struct ds_cap_state *dp,
+static void domain_panic_data(struct ds_info *dp,
+			      struct ds_cap_state *cp,
 			      void *buf, int len)
 {
+	struct ldc_channel *lp = dp->lp;
 	struct ds_data *dpkt = buf;
 	struct ds_panic_req *rp;
 	struct {
@@ -354,13 +366,13 @@
 
 	rp = (struct ds_panic_req *) (dpkt + 1);
 
-	printk(KERN_ALERT PFX "Panic request from "
-	       "LDOM manager received.\n");
+	printk(KERN_ALERT "ds-%lu: Panic request from "
+	       "LDOM manager received.\n", dp->id);
 
 	memset(&pkt, 0, sizeof(pkt));
 	pkt.data.tag.type = DS_DATA;
 	pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-	pkt.data.handle = dp->handle;
+	pkt.data.handle = cp->handle;
 	pkt.res.req_num = rp->req_num;
 	pkt.res.result = DS_OK;
 	pkt.res.reason[0] = 0;
@@ -403,10 +415,11 @@
 	__u32				str_off;
 };
 
-static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void __dr_cpu_send_error(struct ds_info *dp,
+				struct ds_cap_state *cp,
+				struct ds_data *data)
 {
 	struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
-	struct ds_info *dp = ds_info;
 	struct {
 		struct ds_data		data;
 		struct dr_cpu_tag	tag;
@@ -428,12 +441,14 @@
 	__ds_send(dp->lp, &pkt, msg_len);
 }
 
-static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void dr_cpu_send_error(struct ds_info *dp,
+			      struct ds_cap_state *cp,
+			      struct ds_data *data)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__dr_cpu_send_error(cp, data);
+	__dr_cpu_send_error(dp, cp, data);
 	spin_unlock_irqrestore(&ds_lock, flags);
 }
 
@@ -511,7 +526,9 @@
 	}
 }
 
-static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_configure(struct ds_info *dp,
+			    struct ds_cap_state *cp,
+			    u64 req_num,
 			    cpumask_t *mask)
 {
 	struct ds_data *resp;
@@ -533,7 +550,8 @@
 	for_each_cpu_mask(cpu, *mask) {
 		int err;
 
-		printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+		printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+		       dp->id, cpu);
 		err = cpu_up(cpu);
 		if (err) {
 			__u32 res = DR_CPU_RES_FAILURE;
@@ -548,14 +566,14 @@
 				res = DR_CPU_RES_CPU_NOT_RESPONDING;
 			}
 
-			printk(KERN_INFO PFX "CPU startup failed err=%d\n",
-			       err);
+			printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+			       dp->id, err);
 			dr_cpu_mark(resp, cpu, ncpus, res, stat);
 		}
 	}
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__ds_send(ds_info->lp, resp, resp_len);
+	__ds_send(dp->lp, resp, resp_len);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
 	kfree(resp);
@@ -566,7 +584,9 @@
 	return 0;
 }
 
-static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_unconfigure(struct ds_info *dp,
+			      struct ds_cap_state *cp,
+			      u64 req_num,
 			      cpumask_t *mask)
 {
 	struct ds_data *resp;
@@ -586,8 +606,8 @@
 	for_each_cpu_mask(cpu, *mask) {
 		int err;
 
-		printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n",
-		       smp_processor_id(), cpu);
+		printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+		       dp->id, cpu);
 		err = cpu_down(cpu);
 		if (err)
 			dr_cpu_mark(resp, cpu, ncpus,
@@ -596,7 +616,7 @@
 	}
 
 	spin_lock_irqsave(&ds_lock, flags);
-	__ds_send(ds_info->lp, resp, resp_len);
+	__ds_send(dp->lp, resp, resp_len);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
 	kfree(resp);
@@ -604,7 +624,7 @@
 	return 0;
 }
 
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
 			struct ds_cap_state *cp,
 			void *buf, int len)
 {
@@ -623,7 +643,7 @@
 		break;
 
 	default:
-		dr_cpu_send_error(cp, data);
+		dr_cpu_send_error(dp, cp, data);
 		return;
 	}
 
@@ -639,12 +659,12 @@
 	}
 
 	if (tag->type == DR_CPU_CONFIGURE)
-		err = dr_cpu_configure(cp, req_num, &mask);
+		err = dr_cpu_configure(dp, cp, req_num, &mask);
 	else
-		err = dr_cpu_unconfigure(cp, req_num, &mask);
+		err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
 
 	if (err)
-		dr_cpu_send_error(cp, data);
+		dr_cpu_send_error(dp, cp, data);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -656,8 +676,8 @@
 #define DS_PRI_UPDATE			0x02
 };
 
-static void ds_pri_data(struct ldc_channel *lp,
-			struct ds_cap_state *dp,
+static void ds_pri_data(struct ds_info *dp,
+			struct ds_cap_state *cp,
 			void *buf, int len)
 {
 	struct ds_data *dpkt = buf;
@@ -665,8 +685,8 @@
 
 	rp = (struct ds_pri_msg *) (dpkt + 1);
 
-	printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
-	       rp->req_num, rp->type, len);
+	printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+	       dp->id, rp->req_num, rp->type, len);
 }
 
 struct ds_var_hdr {
@@ -701,8 +721,8 @@
 static int ds_var_doorbell;
 static int ds_var_response;
 
-static void ds_var_data(struct ldc_channel *lp,
-			struct ds_cap_state *dp,
+static void ds_var_data(struct ds_info *dp,
+			struct ds_cap_state *cp,
 			void *buf, int len)
 {
 	struct ds_data *dpkt = buf;
@@ -721,14 +741,35 @@
 
 void ldom_set_var(const char *var, const char *value)
 {
-	struct ds_info *dp = ds_info;
 	struct ds_cap_state *cp;
+	struct ds_info *dp;
+	unsigned long flags;
 
-	cp = find_cap_by_string("var-config");
-	if (cp->state != CAP_STATE_REGISTERED)
-		cp = find_cap_by_string("var-config-backup");
+	spin_lock_irqsave(&ds_lock, flags);
+	cp = NULL;
+	for (dp = ds_info_list; dp; dp = dp->next) {
+		struct ds_cap_state *tmp;
 
-	if (cp->state == CAP_STATE_REGISTERED) {
+		tmp = find_cap_by_string(dp, "var-config");
+		if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+			cp = tmp;
+			break;
+		}
+	}
+	if (!cp) {
+		for (dp = ds_info_list; dp; dp = dp->next) {
+			struct ds_cap_state *tmp;
+
+			tmp = find_cap_by_string(dp, "var-config-backup");
+			if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+				cp = tmp;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&ds_lock, flags);
+
+	if (cp) {
 		union {
 			struct {
 				struct ds_data		data;
@@ -736,7 +777,6 @@
 			} header;
 			char			all[512];
 		} pkt;
-		unsigned long flags;
 		char  *base, *p;
 		int msg_len, loops;
 
@@ -777,9 +817,9 @@
 
 		if (ds_var_doorbell == 0 ||
 		    ds_var_response != DS_VAR_SUCCESS)
-			printk(KERN_ERR PFX "var-config [%s:%s] "
+			printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
 			       "failed, response(%d).\n",
-			       var, value,
+			       dp->id, var, value,
 			       ds_var_response);
 	} else {
 		printk(KERN_ERR PFX "var-config not registered so "
@@ -811,8 +851,8 @@
 
 static void ds_conn_reset(struct ds_info *dp)
 {
-	printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
-	       __builtin_return_address(0));
+	printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+	       dp->id, __builtin_return_address(0));
 }
 
 static int register_services(struct ds_info *dp)
@@ -820,12 +860,12 @@
 	struct ldc_channel *lp = dp->lp;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+	for (i = 0; i < dp->num_ds_states; i++) {
 		struct {
 			struct ds_reg_req req;
 			u8 id_buf[256];
 		} pbuf;
-		struct ds_cap_state *cp = &ds_states[i];
+		struct ds_cap_state *cp = &dp->ds_states[i];
 		int err, msg_len;
 		u64 new_count;
 
@@ -870,28 +910,26 @@
 
 	if (pkt->type == DS_REG_ACK) {
 		struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
-		struct ds_cap_state *cp = find_cap(ap->handle);
+		struct ds_cap_state *cp = find_cap(dp, ap->handle);
 
 		if (!cp) {
-			printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
-			       ap->handle);
+			printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+			       "handle %lx\n", dp->id, ap->handle);
 			return 0;
 		}
-		printk(KERN_INFO PFX "Registered %s service.\n",
-		       cp->service_id);
+		printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+		       dp->id, cp->service_id);
 		cp->state = CAP_STATE_REGISTERED;
 	} else if (pkt->type == DS_REG_NACK) {
 		struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
-		struct ds_cap_state *cp = find_cap(np->handle);
+		struct ds_cap_state *cp = find_cap(dp, np->handle);
 
 		if (!cp) {
-			printk(KERN_ERR PFX "REG NACK for "
+			printk(KERN_ERR "ds-%lu: REG NACK for "
 			       "unknown handle %lx\n",
-			       np->handle);
+			       dp->id, np->handle);
 			return 0;
 		}
-		printk(KERN_INFO PFX "Could not register %s service\n",
-		       cp->service_id);
 		cp->state = CAP_STATE_UNKNOWN;
 	}
 
@@ -922,6 +960,7 @@
 
 struct ds_queue_entry {
 	struct list_head		list;
+	struct ds_info			*dp;
 	int				req_len;
 	int				__pad;
 	u64				req[0];
@@ -930,7 +969,6 @@
 static void process_ds_work(void)
 {
 	struct ds_queue_entry *qp, *tmp;
-	static struct ds_info *dp;
 	unsigned long flags;
 	LIST_HEAD(todo);
 
@@ -939,22 +977,22 @@
 	INIT_LIST_HEAD(&ds_work_list);
 	spin_unlock_irqrestore(&ds_lock, flags);
 
-	dp = ds_info;
-
 	list_for_each_entry_safe(qp, tmp, &todo, list) {
 		struct ds_data *dpkt = (struct ds_data *) qp->req;
-		struct ds_cap_state *cp = find_cap(dpkt->handle);
+		struct ds_info *dp = qp->dp;
+		struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
 		int req_len = qp->req_len;
 
 		if (!cp) {
-			printk(KERN_ERR PFX "Data for unknown handle %lu\n",
-			       dpkt->handle);
+			printk(KERN_ERR "ds-%lu: Data for unknown "
+			       "handle %lu\n",
+			       dp->id, dpkt->handle);
 
 			spin_lock_irqsave(&ds_lock, flags);
 			__send_ds_nack(dp, dpkt->handle);
 			spin_unlock_irqrestore(&ds_lock, flags);
 		} else {
-			cp->data(dp->lp, cp, dpkt, req_len);
+			cp->data(dp, cp, dpkt, req_len);
 		}
 
 		list_del(&qp->list);
@@ -990,6 +1028,7 @@
 	if (!qp) {
 		__send_ds_nack(dp, dpkt->handle);
 	} else {
+		qp->dp = dp;
 		memcpy(&qp->req, pkt, len);
 		list_add_tail(&qp->list, &ds_work_list);
 		wake_up(&ds_wait);
@@ -1019,8 +1058,8 @@
 
 	dp->hs_state = 0;
 
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-		struct ds_cap_state *cp = &ds_states[i];
+	for (i = 0; i < dp->num_ds_states; i++) {
+		struct ds_cap_state *cp = &dp->ds_states[i];
 
 		cp->state = CAP_STATE_UNKNOWN;
 	}
@@ -1048,7 +1087,8 @@
 	}
 
 	if (event != LDC_EVENT_DATA_READY) {
-		printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+		printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+		       dp->id, event);
 		spin_unlock_irqrestore(&ds_lock, flags);
 		return;
 	}
@@ -1099,9 +1139,11 @@
 		.mtu		= 4096,
 		.mode		= LDC_MODE_STREAM,
 	};
+	struct mdesc_handle *hp;
 	struct ldc_channel *lp;
 	struct ds_info *dp;
-	int err;
+	const u64 *val;
+	int err, i;
 
 	if (ds_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -1111,19 +1153,37 @@
 	if (!dp)
 		goto out_err;
 
+	hp = mdesc_grab();
+	val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+	if (val)
+		dp->id = *val;
+	mdesc_release(hp);
+
 	dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
 	if (!dp->rcv_buf)
 		goto out_free_dp;
 
 	dp->rcv_buf_len = 4096;
 
+	dp->ds_states = kzalloc(sizeof(ds_states_template),
+				GFP_KERNEL);
+	if (!dp->ds_states)
+		goto out_free_rcv_buf;
+
+	memcpy(dp->ds_states, ds_states_template,
+	       sizeof(ds_states_template));
+	dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+	for (i = 0; i < dp->num_ds_states; i++)
+		dp->ds_states[i].handle = ((u64)i << 32);
+
 	ds_cfg.tx_irq = vdev->tx_irq;
 	ds_cfg.rx_irq = vdev->rx_irq;
 
 	lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
 	if (IS_ERR(lp)) {
 		err = PTR_ERR(lp);
-		goto out_free_rcv_buf;
+		goto out_free_ds_states;
 	}
 	dp->lp = lp;
 
@@ -1131,15 +1191,19 @@
 	if (err)
 		goto out_free_ldc;
 
-	ds_info = dp;
-
-	start_powerd();
+	spin_lock_irq(&ds_lock);
+	dp->next = ds_info_list;
+	ds_info_list = dp;
+	spin_unlock_irq(&ds_lock);
 
 	return err;
 
 out_free_ldc:
 	ldc_free(dp->lp);
 
+out_free_ds_states:
+	kfree(dp->ds_states);
+
 out_free_rcv_buf:
 	kfree(dp->rcv_buf);
 
@@ -1174,11 +1238,6 @@
 
 static int __init ds_init(void)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ds_states); i++)
-		ds_states[i].handle = ((u64)i << 32);
-
 	kthread_run(ds_thread, NULL, "kldomd");
 
 	return vio_register_driver(&ds_driver);
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index ad55a9b..6d29561 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -362,6 +362,7 @@
 static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
 	struct linux_ebus_child *child;
+	struct dev_archdata *sd;
 	struct of_device *op;
 	int i, len;
 
@@ -387,6 +388,10 @@
 			dev->irqs[i] = op->irqs[i];
 	}
 
+	sd = &dev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &dev->ofdev;
+
 	dev->ofdev.node = dp;
 	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
 	dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 7725952..35feacb 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -458,7 +458,6 @@
 	or	%g6, %lo(init_thread_union), %g6
 	ldx	[%g6 + TI_TASK], %g4
 	mov	%sp, %l6
-	mov	%o4, %l7
 
 	wr	%g0, ASI_P, %asi
 	mov	1, %g1
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 8cb3358..db31bf6 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -87,7 +87,11 @@
  */
 #define irq_work(__cpu)	&(trap_block[(__cpu)].irq_worklist)
 
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+	unsigned int irq;
+	unsigned int dev_handle;
+	unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
 
 static unsigned char virt_irq_alloc(unsigned int real_irq)
 {
@@ -96,7 +100,7 @@
 	BUILD_BUG_ON(NR_IRQS >= 256);
 
 	for (ent = 1; ent < NR_IRQS; ent++) {
-		if (!virt_to_real_irq_table[ent])
+		if (!virt_to_real_irq_table[ent].irq)
 			break;
 	}
 	if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@
 		return 0;
 	}
 
-	virt_to_real_irq_table[ent] = real_irq;
+	virt_to_real_irq_table[ent].irq = real_irq;
 
 	return ent;
 }
@@ -117,8 +121,8 @@
 	if (virt_irq >= NR_IRQS)
 		return;
 
-	real_irq = virt_to_real_irq_table[virt_irq];
-	virt_to_real_irq_table[virt_irq] = 0;
+	real_irq = virt_to_real_irq_table[virt_irq].irq;
+	virt_to_real_irq_table[virt_irq].irq = 0;
 
 	__bucket(real_irq)->virt_irq = 0;
 }
@@ -126,7 +130,7 @@
 
 static unsigned int virt_to_real_irq(unsigned char virt_irq)
 {
-	return virt_to_real_irq_table[virt_irq];
+	return virt_to_real_irq_table[virt_irq].irq;
 }
 
 /*
@@ -336,15 +340,15 @@
 
 		err = sun4v_intr_settarget(ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-			       ino, cpuid, err);
+			printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+			       "err(%d)\n", ino, cpuid, err);
 		err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setstate(%x): "
+			printk(KERN_ERR "sun4v_intr_setstate(%x): "
 			       "err(%d)\n", ino, err);
 		err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setenabled(%x): err(%d)\n",
+			printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
 			       ino, err);
 	}
 }
@@ -362,8 +366,8 @@
 
 		err = sun4v_intr_settarget(ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-			       ino, cpuid, err);
+			printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+			       "err(%d)\n", ino, cpuid, err);
 	}
 }
 
@@ -377,7 +381,7 @@
 
 		err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setenabled(%x): "
+			printk(KERN_ERR "sun4v_intr_setenabled(%x): "
 			       "err(%d)\n", ino, err);
 	}
 }
@@ -410,7 +414,7 @@
 
 		err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_intr_setstate(%x): "
+			printk(KERN_ERR "sun4v_intr_setstate(%x): "
 			       "err(%d)\n", ino, err);
 	}
 }
@@ -418,7 +422,6 @@
 static void sun4v_virq_enable(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long cpuid, dev_handle, dev_ino;
@@ -426,24 +429,24 @@
 
 		cpuid = irq_choose_cpu(virt_irq);
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+			printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
 			       "err(%d)\n",
 			       dev_handle, dev_ino, cpuid, err);
 		err = sun4v_vintr_set_state(dev_handle, dev_ino,
 					    HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 				"HV_INTR_STATE_IDLE): err(%d)\n",
 			       dev_handle, dev_ino, err);
 		err = sun4v_vintr_set_valid(dev_handle, dev_ino,
 					    HV_INTR_ENABLED);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 			       "HV_INTR_ENABLED): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -452,7 +455,6 @@
 static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long cpuid, dev_handle, dev_ino;
@@ -460,12 +462,12 @@
 
 		cpuid = irq_choose_cpu(virt_irq);
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+			printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
 			       "err(%d)\n",
 			       dev_handle, dev_ino, cpuid, err);
 	}
@@ -474,19 +476,18 @@
 static void sun4v_virq_disable(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 
 	if (likely(bucket)) {
 		unsigned long dev_handle, dev_ino;
 		int err;
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_valid(dev_handle, dev_ino,
 					    HV_INTR_DISABLED);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 			       "HV_INTR_DISABLED): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -495,7 +496,6 @@
 static void sun4v_virq_end(unsigned int virt_irq)
 {
 	struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-	unsigned int ino = bucket - &ivector_table[0];
 	struct irq_desc *desc = irq_desc + virt_irq;
 
 	if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
@@ -505,13 +505,13 @@
 		unsigned long dev_handle, dev_ino;
 		int err;
 
-		dev_handle = ino & IMAP_IGN;
-		dev_ino = ino & IMAP_INO;
+		dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+		dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
 		err = sun4v_vintr_set_state(dev_handle, dev_ino,
 					    HV_INTR_STATE_IDLE);
 		if (err != HV_EOK)
-			printk("sun4v_vintr_set_state(%lx,%lx,"
+			printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
 				"HV_INTR_STATE_IDLE): err(%d)\n",
 			       dev_handle, dev_ino, err);
 	}
@@ -700,11 +700,12 @@
 unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 {
 	unsigned long sysino, hv_err;
+	unsigned int virq;
 
-	BUG_ON(devhandle & ~IMAP_IGN);
-	BUG_ON(devino & ~IMAP_INO);
+	BUG_ON(devhandle & devino);
 
 	sysino = devhandle | devino;
+	BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
 
 	hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
 	if (hv_err) {
@@ -713,7 +714,12 @@
 		prom_halt();
 	}
 
-	return sun4v_build_common(sysino, &sun4v_virq);
+	virq = sun4v_build_common(sysino, &sun4v_virq);
+
+	virt_to_real_irq_table[virq].dev_handle = devhandle;
+	virt_to_real_irq_table[virq].dev_ino = devino;
+
+	return virq;
 }
 
 #ifdef CONFIG_PCI_MSI
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 6a6882e..1a1043f 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -79,6 +79,7 @@
 
 	while (dp) {
 		struct sparc_isa_device *isa_dev;
+		struct dev_archdata *sd;
 
 		isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
 		if (!isa_dev) {
@@ -86,6 +87,10 @@
 			return;
 		}
 
+		sd = &isa_dev->ofdev.dev.archdata;
+		sd->prom_node = dp;
+		sd->op = &isa_dev->ofdev;
+
 		isa_dev->ofdev.node = dp;
 		isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
 		isa_dev->ofdev.dev.bus = &isa_bus_type;
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 302ba5e..cce4d0d 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -83,7 +83,7 @@
 	hp->handle_size = handle_size;
 }
 
-static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
 {
 	struct mdesc_handle *hp;
 	unsigned int handle_size, alloc_size;
@@ -123,7 +123,7 @@
 	}
 }
 
-static struct mdesc_mem_ops bootmem_mdesc_memops = {
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
 	.alloc = mdesc_bootmem_alloc,
 	.free  = mdesc_bootmem_free,
 };
@@ -231,6 +231,25 @@
 	mutex_unlock(&mdesc_mutex);
 }
 
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+	const u64 *id;
+	u64 a;
+
+	id = NULL;
+	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+		u64 target;
+
+		target = mdesc_arc_target(hp, a);
+		id = mdesc_get_property(hp, target,
+					"cfg-handle", NULL);
+		if (id)
+			break;
+	}
+
+	return id;
+}
+
 /* Run 'func' on nodes which are in A but not in B.  */
 static void invoke_on_missing(const char *name,
 			      struct mdesc_handle *a,
@@ -240,13 +259,42 @@
 	u64 node;
 
 	mdesc_for_each_node_by_name(a, node, name) {
-		const u64 *id = mdesc_get_property(a, node, "id", NULL);
-		int found = 0;
+		int found = 0, is_vdc_port = 0;
+		const char *name_prop;
+		const u64 *id;
 		u64 fnode;
 
+		name_prop = mdesc_get_property(a, node, "name", NULL);
+		if (name_prop && !strcmp(name_prop, "vdc-port")) {
+			is_vdc_port = 1;
+			id = parent_cfg_handle(a, node);
+		} else
+			id = mdesc_get_property(a, node, "id", NULL);
+
+		if (!id) {
+			printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+			       (name_prop ? name_prop : name));
+			continue;
+		}
+
 		mdesc_for_each_node_by_name(b, fnode, name) {
-			const u64 *fid = mdesc_get_property(b, fnode,
-							    "id", NULL);
+			const u64 *fid;
+
+			if (is_vdc_port) {
+				name_prop = mdesc_get_property(b, fnode,
+							       "name", NULL);
+				if (!name_prop ||
+				    strcmp(name_prop, "vdc-port"))
+					continue;
+				fid = parent_cfg_handle(b, fnode);
+				if (!fid) {
+					printk(KERN_ERR "MD: Cannot find ID "
+					       "for vdc-port node.\n");
+					continue;
+				}
+			} else
+				fid = mdesc_get_property(b, fnode,
+							 "id", NULL);
 
 			if (*id == *fid) {
 				found = 1;
@@ -812,7 +860,7 @@
 
 	printk("MDESC: Size is %lu bytes.\n", len);
 
-	hp = mdesc_alloc(len, &bootmem_mdesc_memops);
+	hp = mdesc_alloc(len, &bootmem_mdesc_ops);
 	if (hp == NULL) {
 		prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
 		prom_halt();
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 6676b93..4cc7748 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -1,132 +1,13 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-					const struct of_device *dev)
-{
-	if (!dev->node)
-		return NULL;
-	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-		int match = 1;
-		if (matches->name[0])
-			match &= dev->node->name
-				&& !strcmp(matches->name, dev->node->name);
-		if (matches->type[0])
-			match &= dev->node->type
-				&& !strcmp(matches->type, dev->node->type);
-		if (matches->compatible[0])
-			match &= of_device_is_compatible(dev->node,
-							 matches->compatible);
-		if (match)
-			return matches;
-		matches++;
-	}
-	return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-	const struct of_device_id * matches = of_drv->match_table;
-
-	if (!matches)
-		return 0;
-
-	return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-	struct device *tmp;
-
-	if (!dev)
-		return NULL;
-	tmp = get_device(&dev->dev);
-	if (tmp)
-		return to_of_device(tmp);
-	else
-		return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-	if (dev)
-		put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-	int error = -ENODEV;
-	struct of_platform_driver *drv;
-	struct of_device *of_dev;
-	const struct of_device_id *match;
-
-	drv = to_of_platform_driver(dev->driver);
-	of_dev = to_of_device(dev);
-
-	if (!drv->probe)
-		return error;
-
-	of_dev_get(of_dev);
-
-	match = of_match_device(drv->match_table, of_dev);
-	if (match)
-		error = drv->probe(of_dev, match);
-	if (error)
-		of_dev_put(of_dev);
-
-	return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-	if (dev->driver && drv->remove)
-		drv->remove(of_dev);
-	return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->suspend)
-		error = drv->suspend(of_dev, state);
-	return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-	struct of_device * of_dev = to_of_device(dev);
-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-	int error = 0;
-
-	if (dev->driver && drv->resume)
-		error = drv->resume(of_dev);
-	return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
 {
@@ -163,7 +44,7 @@
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-	struct device *dev = bus_find_device(&of_bus_type, NULL,
+	struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
 					     dp, node_match);
 
 	if (dev)
@@ -174,48 +55,20 @@
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type isa_bus_type = {
-       .name	= "isa",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
+struct bus_type isa_bus_type;
 EXPORT_SYMBOL(isa_bus_type);
 
-struct bus_type ebus_bus_type = {
-       .name	= "ebus",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name	= "sbus",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name	= "of",
-       .match	= of_platform_bus_match,
-       .probe	= of_device_probe,
-       .remove	= of_device_remove,
-       .suspend	= of_device_suspend,
-       .resume	= of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -899,11 +752,16 @@
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
 	const unsigned int *irq;
+	struct dev_archdata *sd;
 	int len, i;
 
 	if (!op)
 		return NULL;
 
+	sd = &op->dev.archdata;
+	sd->prom_node = dp;
+	sd->op = op;
+
 	op->node = dp;
 
 	op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -933,7 +791,7 @@
 		op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
 
 	op->dev.parent = parent;
-	op->dev.bus = &of_bus_type;
+	op->dev.bus = &of_platform_bus_type;
 	if (!parent)
 		strcpy(op->dev.bus_id, "root");
 	else
@@ -977,16 +835,16 @@
 {
 	int err;
 
-	err = bus_register(&of_bus_type);
+	err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
 	if (!err)
-		err = bus_register(&isa_bus_type);
+		err = of_bus_type_init(&isa_bus_type, "isa");
 	if (!err)
-		err = bus_register(&ebus_bus_type);
+		err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
 	if (!err)
-		err = bus_register(&sbus_bus_type);
+		err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
 	if (!err)
@@ -1020,61 +878,13 @@
 	/* register with core */
 	return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL(of_register_driver);
 
 void of_unregister_driver(struct of_platform_driver *drv)
 {
 	driver_unregister(&drv->driver);
 }
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct of_device *ofdev;
-
-	ofdev = to_of_device(dev);
-	return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-	struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-	kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-	int rc;
-
-	BUG_ON(ofdev->node == NULL);
-
-	rc = device_register(&ofdev->dev);
-	if (rc)
-		return rc;
-
-	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-	if (rc)
-		device_unregister(&ofdev->dev);
-
-	return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-	device_remove_file(&ofdev->dev, &dev_attr_devspec);
-	device_unregister(&ofdev->dev);
-}
+EXPORT_SYMBOL(of_unregister_driver);
 
 struct of_device* of_platform_device_create(struct device_node *np,
 					    const char *bus_id,
@@ -1100,13 +910,4 @@
 
 	return dev;
 }
-
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 6b3fe2c..639cf06 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -1129,7 +1129,7 @@
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
 {
 	struct pci_pbm_info *pbm;
 
@@ -1163,7 +1163,7 @@
 	pci_sun4v_msi_init(pbm);
 }
 
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
 {
 	static int hvapi_negotiated = 0;
 	struct pci_controller_info *p;
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 8dd4294..881a09e 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -12,13 +12,13 @@
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/syscalls.h>
+#include <linux/reboot.h>
 
 #include <asm/system.h>
 #include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/io.h>
-#include <asm/power.h>
 #include <asm/sstate.h>
 
 #include <linux/unistd.h>
@@ -31,20 +31,9 @@
 
 static void __iomem *power_reg;
 
-static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed;
-
-void wake_up_powerd(void)
-{
-	if (button_pressed == 0) {
-		button_pressed = 1;
-		wake_up(&powerd_wait);
-	}
-}
-
 static irqreturn_t power_handler(int irq, void *dev_id)
 {
-	wake_up_powerd();
+	orderly_poweroff(true);
 
 	/* FIXME: Check registers for status... */
 	return IRQ_HANDLED;
@@ -57,7 +46,7 @@
 void machine_power_off(void)
 {
 	sstate_poweroff();
-	if (!serial_console || scons_pwroff) {
+	if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
 		if (power_reg) {
 			/* Both register bits seem to have the
 			 * same effect, so until I figure out
@@ -77,48 +66,6 @@
 void (*pm_power_off)(void) = machine_power_off;
 EXPORT_SYMBOL(pm_power_off);
 
-static int powerd(void *__unused)
-{
-	static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
-	DECLARE_WAITQUEUE(wait, current);
-
-	daemonize("powerd");
-
-	add_wait_queue(&powerd_wait, &wait);
-
-	for (;;) {
-		set_task_state(current, TASK_INTERRUPTIBLE);
-		if (button_pressed)
-			break;
-		flush_signals(current);
-		schedule();
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&powerd_wait, &wait);
-
-	/* Ok, down we go... */
-	button_pressed = 0;
-	if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
-		printk(KERN_ERR "powerd: shutdown execution failed\n");
-		machine_power_off();
-	}
-	return 0;
-}
-
-int start_powerd(void)
-{
-	int err;
-
-	err = kernel_thread(powerd, NULL, CLONE_FS);
-	if (err < 0)
-		printk(KERN_ERR "power: Failed to start power daemon.\n");
-	else
-		printk(KERN_INFO "power: powerd running.\n");
-
-	return err;
-}
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
 	if (irq == 0xffffffff)
@@ -136,20 +83,15 @@
 
 	power_reg = of_ioremap(res, 0, 0x4, "power");
 
-	printk("%s: Control reg at %lx ... ",
+	printk(KERN_INFO "%s: Control reg at %lx\n",
 	       op->node->name, res->start);
 
 	poweroff_method = machine_halt;  /* able to use the standard halt */
 
 	if (has_button_interrupt(irq, op->node)) {
-		if (start_powerd() < 0)
-			return 0;
-
 		if (request_irq(irq,
 				power_handler, 0, "power", NULL) < 0)
 			printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
-	} else {
-		printk(KERN_INFO "power: Not using powerd.\n");
 	}
 
 	return 0;
@@ -170,6 +112,6 @@
 
 void __init power_init(void)
 {
-	of_register_driver(&power_driver, &of_bus_type);
+	of_register_driver(&power_driver, &of_platform_bus_type);
 	return;
 }
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 9355750..fd7899b 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -119,7 +119,7 @@
 void machine_halt(void)
 {
 	sstate_halt();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (prom_keyboard)
 		prom_keyboard();
@@ -130,7 +130,7 @@
 void machine_alt_power_off(void)
 {
 	sstate_poweroff();
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(1);
 	if (prom_keyboard)
 		prom_keyboard();
@@ -145,7 +145,7 @@
 	sstate_reboot();
 	p = strchr (reboot_command, '\n');
 	if (p) *p = 0;
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette (1);
 	if (prom_keyboard)
 		prom_keyboard();
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5d22030..f4e0a9a 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -30,73 +30,9 @@
 #include <asm/upa.h>
 #include <asm/smp.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;	/* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-			    const char *compat)
-{
-	const char* cp;
-	int cplen, l;
-
-	cp = of_get_property(device, "compatible", &cplen);
-	if (cp == NULL)
-		return 0;
-	while (cplen > 0) {
-		if (strncmp(cp, compat, strlen(compat)) == 0)
-			return 1;
-		l = strlen(cp) + 1;
-		cp += l;
-		cplen -= l;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-	struct device_node *np;
-
-	if (!node)
-		return NULL;
-
-	np = node->parent;
-
-	return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-	struct device_node *prev)
-{
-	struct device_node *next;
-
-	next = prev ? prev->sibling : node->child;
-	for (; next != 0; next = next->sibling) {
-		break;
-	}
-
-	return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-	struct device_node *np = allnodes;
-
-	for (; np != 0; np = np->allnext) {
-		if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-			break;
-	}
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;	/* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -110,81 +46,6 @@
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != NULL; np = np->allnext)
-		if (np->name != NULL && strcmp(np->name, name) == 0)
-			break;
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext)
-		if (np->type != 0 && strcmp(np->type, type) == 0)
-			break;
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compatible)
-{
-	struct device_node *np;
-
-	np = from ? from->allnext : allnodes;
-	for (; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcmp(np->type, type) == 0))
-			continue;
-		if (of_device_is_compatible(np, compatible))
-			break;
-	}
-
-	return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-				  const char *name,
-				  int *lenp)
-{
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		if (strcasecmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			break;
-		}
-	}
-	return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-		      int *lenp)
-{
-	struct property *pp = of_find_property(np,name,lenp);
-	return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
 	struct property *prop;
@@ -198,36 +59,6 @@
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-	const int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#address-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #address-cells property for the root node, default to 2 */
-	return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-	const int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = of_get_property(np, "#size-cells", NULL);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #size-cells property for the root node, default to 1 */
-	return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
 	struct property **prevp;
@@ -1815,6 +1646,60 @@
 	smp_fill_in_sib_core_maps();
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+	char *msg = "OF stdout device is: %s\n";
+	struct device_node *dp;
+	const char *type;
+	phandle node;
+
+	of_console_path = prom_early_alloc(256);
+	if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+		prom_printf("Cannot obtain path of stdout.\n");
+		prom_halt();
+	}
+	of_console_options = strrchr(of_console_path, ':');
+	if (of_console_options) {
+		of_console_options++;
+		if (*of_console_options == '\0')
+			of_console_options = NULL;
+	}
+
+	node = prom_inst2pkg(prom_stdout);
+	if (!node) {
+		prom_printf("Cannot resolve stdout node from "
+			    "instance %08x.\n", prom_stdout);
+		prom_halt();
+	}
+
+	dp = of_find_node_by_phandle(node);
+	type = of_get_property(dp, "device_type", NULL);
+	if (!type) {
+		prom_printf("Console stdout lacks device_type property.\n");
+		prom_halt();
+	}
+
+	if (strcmp(type, "display") && strcmp(type, "serial")) {
+		prom_printf("Console device_type is neither display "
+			    "nor serial.\n");
+		prom_halt();
+	}
+
+	of_console_device = dp;
+
+	prom_printf(msg, of_console_path);
+	printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
 	struct device_node **nextp;
@@ -1827,6 +1712,8 @@
 	allnodes->child = build_tree(allnodes,
 				     prom_getchild(allnodes->node),
 				     &nextp);
+	of_console_init();
+
 	printk("PROM: Built device tree with %u bytes of memory.\n",
 	       prom_early_allocated);
 
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index aafde3d..0f5be82 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -133,33 +133,6 @@
 	}
 }
 
-static void __init process_console(char *commands)
-{
-	serial_console = 0;
-	commands += 8;
-	/* Linux-style serial */
-	if (!strncmp(commands, "ttyS", 4))
-		serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-	else if (!strncmp(commands, "tty", 3)) {
-		char c = *(commands + 3);
-		/* Solaris-style serial */
-		if (c == 'a' || c == 'b') {
-			serial_console = c - 'a' + 1;
-			prom_printf ("Using /dev/tty%c as console.\n", c);
-		}
-		/* else Linux-style fbcon, not serial */
-	}
-#if defined(CONFIG_PROM_CONSOLE)
-	if (!strncmp(commands, "prom", 4)) {
-		char *p;
-
-		for (p = commands - 8; *p && *p != ' '; p++)
-			*p = ' ';
-		conswitchp = &prom_con;
-	}
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
 	while (*commands) {
@@ -176,9 +149,7 @@
 				process_switch(*commands++);
 			continue;
 		}
-		if (!strncmp(commands, "console=", 8)) {
-			process_console(commands);
-		} else if (!strncmp(commands, "mem=", 4)) {
+		if (!strncmp(commands, "mem=", 4)) {
 			/*
 			 * "mem=XXX[kKmM]" overrides the PROM-reported
 			 * memory size.
@@ -378,44 +349,6 @@
 	paging_init();
 }
 
-static int __init set_preferred_console(void)
-{
-	int idev, odev;
-
-	/* The user has requested a console so this is already set up. */
-	if (serial_console >= 0)
-		return -EBUSY;
-
-	idev = prom_query_input_device();
-	odev = prom_query_output_device();
-	if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-		serial_console = 0;
-	} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-		serial_console = 1;
-	} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-		serial_console = 2;
-	} else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
-		serial_console = 3;
-	} else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
-		/* sunhv_console_init() doesn't check the serial_console
-		 * value anyways...
-		 */
-		serial_console = 4;
-		return add_preferred_console("ttyHV", 0, NULL);
-	} else {
-		prom_printf("Inconsistent console: "
-			    "input %d, output %d\n",
-			    idev, odev);
-		prom_halt();
-	}
-
-	if (serial_console)
-		return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-	return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 /* BUFFER is PAGE_SIZE bytes long. */
 
 extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@
 	prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 719d676..d270c2f 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -280,6 +280,7 @@
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
 EXPORT_SYMBOL(compat_sys_ioctl);
+EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sparc32_open);
 #endif
 
@@ -330,7 +331,6 @@
 
 /* for input/keybdev */
 EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index abd8312..e8dce90 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,8 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
- * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment.
@@ -1028,3 +1027,10 @@
 				   (nb_high << 32) | nb_low,
 				   flags);
 }
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+				     u32 lenhi, u32 lenlo)
+{
+	return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+			     ((loff_t)lenhi << 32) | lenlo);
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 8765e321..06d1090 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.81 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1996, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Based upon preliminary work which is:
@@ -81,7 +80,7 @@
 	.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/	.word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
 	.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/	.word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd
+/*310*/	.word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
 
 #endif /* CONFIG_COMPAT */
 
@@ -153,7 +152,7 @@
 	.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/	.word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 	.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/	.word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/	.word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -272,6 +271,6 @@
 	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_nosys
 /*310*/	.word sunos_nosys, sunos_nosys, sunos_nosys
-	.word sunos_nosys
+	.word sunos_nosys, sunos_nosys
 
 #endif
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 62e316a..49063ca 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -403,58 +403,9 @@
 
 static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
-#define TICK_SIZE (tick_nsec / 1000)
-
-#define USEC_AFTER	500000
-#define USEC_BEFORE	500000
-
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-
-static void sync_cmos_clock(unsigned long dummy)
+int update_persistent_clock(struct timespec now)
 {
-	struct timeval now, next;
-	int fail = 1;
-
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 * This code is run on a timer.  If the clock is set, that timer
-	 * may not expire at the correct time.  Thus, we adjust...
-	 */
-	if (!ntp_synced())
-		/*
-		 * Not synced, exit, do not restart a timer (if one is
-		 * running, let it run out).
-		 */
-		return;
-
-	do_gettimeofday(&now);
-	if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
-	    now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
-		fail = set_rtc_mmss(now.tv_sec);
-
-	next.tv_usec = USEC_AFTER - now.tv_usec;
-	if (next.tv_usec <= 0)
-		next.tv_usec += USEC_PER_SEC;
-
-	if (!fail)
-		next.tv_sec = 659;
-	else
-		next.tv_sec = 0;
-
-	if (next.tv_usec >= USEC_PER_SEC) {
-		next.tv_sec++;
-		next.tv_usec -= USEC_PER_SEC;
-	}
-	mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
-{
-	mod_timer(&sync_cmos_timer, jiffies + 1);
+	return set_rtc_mmss(now.tv_sec);
 }
 
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
@@ -835,7 +786,7 @@
 		return 0;
 	}
 
-	return of_register_driver(&clock_driver, &of_bus_type);
+	return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -931,6 +882,7 @@
 {
 	switch (mode) {
 	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
 		break;
 
 	case CLOCK_EVT_MODE_SHUTDOWN:
@@ -1434,6 +1386,78 @@
 
 	return 0;
 }
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+	unsigned char ctrl;
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+	rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+	ctrl = CMOS_READ(RTC_CONTROL);
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(rtc_tm->tm_sec);
+		BCD_TO_BIN(rtc_tm->tm_min);
+		BCD_TO_BIN(rtc_tm->tm_hour);
+		BCD_TO_BIN(rtc_tm->tm_mday);
+		BCD_TO_BIN(rtc_tm->tm_mon);
+		BCD_TO_BIN(rtc_tm->tm_year);
+		BCD_TO_BIN(rtc_tm->tm_wday);
+	}
+
+	if (rtc_tm->tm_year <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+	unsigned char mon, day, hrs, min, sec;
+	unsigned char save_control, save_freq_select;
+	unsigned int yrs;
+
+	yrs = rtc_tm->tm_year;
+	mon = rtc_tm->tm_mon + 1;
+	day = rtc_tm->tm_mday;
+	hrs = rtc_tm->tm_hour;
+	min = rtc_tm->tm_min;
+	sec = rtc_tm->tm_sec;
+
+	if (yrs >= 100)
+		yrs -= 100;
+
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(mon);
+		BIN_TO_BCD(yrs);
+	}
+
+	save_control = CMOS_READ(RTC_CONTROL);
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	CMOS_WRITE(yrs, RTC_YEAR);
+	CMOS_WRITE(mon, RTC_MONTH);
+	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(hrs, RTC_HOURS);
+	CMOS_WRITE(min, RTC_MINUTES);
+	CMOS_WRITE(sec, RTC_SECONDS);
+
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return 0;
+}
 #endif /* CONFIG_PCI */
 
 struct mini_rtc_ops {
@@ -1456,6 +1480,11 @@
 	.get_rtc_time = bq4802_get_rtc_time,
 	.set_rtc_time = bq4802_set_rtc_time,
 };
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+	.get_rtc_time = cmos_get_rtc_time,
+	.set_rtc_time = cmos_set_rtc_time,
+};
 #endif /* CONFIG_PCI */
 
 static struct mini_rtc_ops *mini_rtc_ops;
@@ -1583,6 +1612,8 @@
 #ifdef CONFIG_PCI
 	else if (bq4802_regs)
 		mini_rtc_ops = &bq4802_rtc_ops;
+	else if (ds1287_regs)
+		mini_rtc_ops = &cmos_rtc_ops;
 #endif /* CONFIG_PCI */
 	else
 		return -ENODEV;
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 8d3cc4f..3685daf 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -103,9 +103,9 @@
 	struct vio_dev *vdev = to_vio_dev(dev);
 	const char *str = "none";
 
-	if (!strcmp(vdev->type, "network"))
+	if (!strcmp(vdev->type, "vnet-port"))
 		str = "vnet";
-	else if (!strcmp(vdev->type, "block"))
+	else if (!strcmp(vdev->type, "vdc-port"))
 		str = "vdisk";
 
 	return sprintf(buf, "%s\n", str);
@@ -205,7 +205,8 @@
 	struct device_node *dp;
 	struct vio_dev *vdev;
 	int err, tlen, clen;
-	const u64 *id;
+	const u64 *id, *cfg_handle;
+	u64 a;
 
 	type = mdesc_get_property(hp, mp, "device-type", &tlen);
 	if (!type) {
@@ -221,6 +222,19 @@
 		return NULL;
 	}
 
+	id = mdesc_get_property(hp, mp, "id", NULL);
+
+	cfg_handle = NULL;
+	mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+		u64 target;
+
+		target = mdesc_arc_target(hp, a);
+		cfg_handle = mdesc_get_property(hp, target,
+						"cfg-handle", NULL);
+		if (cfg_handle)
+			break;
+	}
+
 	bus_id_name = type;
 	if (!strcmp(type, "domain-services-port"))
 		bus_id_name = "ds";
@@ -260,13 +274,19 @@
 
 	vio_fill_channel_info(hp, mp, vdev);
 
-	id = mdesc_get_property(hp, mp, "id", NULL);
-	if (!id)
+	if (!id) {
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
 			 bus_id_name);
-	else
+		vdev->dev_no = ~(u64)0;
+	} else if (!cfg_handle) {
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
 			 bus_id_name, *id);
+		vdev->dev_no = *id;
+	} else {
+		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+			 bus_id_name, *cfg_handle, *id);
+		vdev->dev_no = *cfg_handle;
+	}
 
 	vdev->dev.parent = parent;
 	vdev->dev.bus = &vio_bus_type;
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 7c25c54..3fafa9a 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -73,88 +73,3 @@
 			   P1275_INOUT(3,1),
 			   prom_stdout, s, P1275_SIZE(len));
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-	int st_p;
-	char propb[64];
-
-	st_p = prom_inst2pkg(prom_stdin);
-	if(prom_node_has_property(st_p, "keyboard"))
-		return PROMDEV_IKBD;
-	prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-	if(strncmp(propb, "serial", 6))
-		return PROMDEV_I_UNK;
-	/* FIXME: Is there any better way how to find out? */	
-	memset(propb, 0, sizeof(propb));
-	st_p = prom_finddevice ("/options");
-	prom_getproperty(st_p, "input-device", propb, sizeof(propb));
-
-	/*
-	 * If we get here with propb == 'keyboard', we are on ttya, as
-	 * the PROM defaulted to this due to 'no input device'.
-	 */
-	if (!strncmp(propb, "keyboard", 8))
-		return PROMDEV_ITTYA;
-
-	if (!strncmp (propb, "rsc", 3))
-		return PROMDEV_IRSC;
-
-	if (!strncmp (propb, "virtual-console", 3))
-		return PROMDEV_IVCONS;
-
-	if (strncmp (propb, "tty", 3) || !propb[3])
-		return PROMDEV_I_UNK;
-
-	switch (propb[3]) {
-		case 'a': return PROMDEV_ITTYA;
-		case 'b': return PROMDEV_ITTYB;
-		default: return PROMDEV_I_UNK;
-	}
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-	int st_p;
-	char propb[64];
-	int propl;
-
-	st_p = prom_inst2pkg(prom_stdout);
-	propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-	if (propl >= 0 && propl == sizeof("display") &&
-	    strncmp("display", propb, sizeof("display")) == 0)
-		return PROMDEV_OSCREEN;
-	if(strncmp("serial", propb, 6))
-		return PROMDEV_O_UNK;
-	/* FIXME: Is there any better way how to find out? */	
-	memset(propb, 0, sizeof(propb));
-	st_p = prom_finddevice ("/options");
-	prom_getproperty(st_p, "output-device", propb, sizeof(propb));
-
-	/*
-	 * If we get here with propb == 'screen', we are on ttya, as
-	 * the PROM defaulted to this due to 'no input device'.
-	 */
-	if (!strncmp(propb, "screen", 6))
-		return PROMDEV_OTTYA;
-
-	if (!strncmp (propb, "rsc", 3))
-		return PROMDEV_ORSC;
-
-	if (!strncmp (propb, "virtual-console", 3))
-		return PROMDEV_OVCONS;
-
-	if (strncmp (propb, "tty", 3) || !propb[3])
-		return PROMDEV_O_UNK;
-
-	switch (propb[3]) {
-		case 'a': return PROMDEV_OTTYA;
-		case 'b': return PROMDEV_OTTYB;
-		default: return PROMDEV_O_UNK;
-	}
-}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 33c5b7d..68c83ad 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -72,7 +72,7 @@
 
 	local_irq_save(flags);
 
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(1);
 
 #ifdef CONFIG_SMP
@@ -85,7 +85,7 @@
 	smp_release();
 #endif
 
-	if (!serial_console && prom_palette)
+	if (prom_palette)
 		prom_palette(0);
 
 	local_irq_restore(flags);
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index 17b7ecf..b2c5b12 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -304,3 +304,11 @@
 	if (node == -1) return 0;
 	return node;
 }
+
+int prom_ihandle2path(int handle, char *buffer, int bufsize)
+{
+	return p1275_cmd("instance-to-path",
+			 P1275_ARG(1,P1275_ARG_OUT_BUF)|
+			 P1275_INOUT(3, 1),
+			 handle, buffer, P1275_SIZE(bufsize));
+}
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 14bf8ce..45f82ae 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -32,6 +32,10 @@
 	bool
 	default y
 
+config GENERIC_CMOS_UPDATE
+	bool
+	default y
+
 config ZONE_DMA32
 	bool
 	default y
@@ -56,6 +60,14 @@
 	bool
 	default y
 
+config QUICKLIST
+	bool
+	default y
+
+config NR_QUICK
+	int
+	default 2
+
 config ISA
 	bool
 
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 29617ae..128561d 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -76,7 +76,8 @@
 libs-y 					+= arch/x86_64/lib/
 core-y					+= arch/x86_64/kernel/ \
 					   arch/x86_64/mm/ \
-					   arch/x86_64/crypto/
+					   arch/x86_64/crypto/ \
+					   arch/x86_64/vdso/
 core-$(CONFIG_IA32_EMULATION)		+= arch/x86_64/ia32/
 drivers-$(CONFIG_PCI)			+= arch/x86_64/pci/
 drivers-$(CONFIG_OPROFILE)		+= arch/x86_64/oprofile/
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
index c9f2da7..877c0bd 100644
--- a/arch/x86_64/boot/compressed/Makefile
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -3,8 +3,6 @@
 #
 # create a compressed vmlinux image from the original vmlinux
 #
-# Note all the files here are compiled/linked as 32bit executables.
-#
 
 targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
 
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 40178e5..b7c4cd0 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,19 +1,22 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:40 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
 CONFIG_X86=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CMOS_UPDATE=y
 CONFIG_ZONE_DMA32=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
+CONFIG_NR_QUICK=2
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -44,19 +47,18 @@
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS 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=18
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
+CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -86,10 +88,6 @@
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
@@ -97,12 +95,9 @@
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -165,9 +160,12 @@
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
 CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y
 CONFIG_NR_CPUS=32
+CONFIG_PHYSICAL_ALIGN=0x200000
 CONFIG_HOTPLUG_CPU=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_HPET_TIMER=y
@@ -180,7 +178,7 @@
 CONFIG_X86_MCE_AMD=y
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
-CONFIG_RELOCATABLE=y
+# CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_START=0x200000
 CONFIG_SECCOMP=y
 # CONFIG_CC_STACKPROTECTOR is not set
@@ -201,7 +199,6 @@
 CONFIG_PM=y
 # CONFIG_PM_LEGACY is not set
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 CONFIG_SOFTWARE_SUSPEND=y
 CONFIG_PM_STD_PARTITION=""
 CONFIG_SUSPEND_SMP=y
@@ -248,7 +245,7 @@
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -351,20 +348,8 @@
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -401,6 +386,7 @@
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -415,21 +401,9 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -437,10 +411,7 @@
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 CONFIG_BLK_DEV_FD=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -458,17 +429,14 @@
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_IBM_ASM is not set
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDE=y
 
@@ -539,6 +507,7 @@
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 # CONFIG_SCSI_PROC_FS is not set
@@ -590,11 +559,9 @@
 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
 # CONFIG_SCSI_AIC94XX is not set
 # CONFIG_SCSI_ARCMSR is not set
-CONFIG_MEGARAID_NEWGEN=y
-CONFIG_MEGARAID_MM=y
-CONFIG_MEGARAID_MAILBOX=y
+# CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
-CONFIG_MEGARAID_SAS=y
+# CONFIG_MEGARAID_SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -614,7 +581,6 @@
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
@@ -671,10 +637,6 @@
 # CONFIG_PATA_SIS is not set
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_DM=y
@@ -692,7 +654,7 @@
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 # CONFIG_FUSION_FC is not set
-CONFIG_FUSION_SAS=y
+# CONFIG_FUSION_SAS is not set
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
@@ -710,7 +672,10 @@
 #
 # Controllers
 #
-# CONFIG_IEEE1394_PCILYNX is not set
+
+#
+# Texas Instruments PCILynx requires I2C
+#
 CONFIG_IEEE1394_OHCI1394=y
 
 #
@@ -722,32 +687,19 @@
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
 CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_TUN=y
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
@@ -756,10 +708,6 @@
 CONFIG_NET_VENDOR_3COM=y
 CONFIG_VORTEX=y
 # CONFIG_TYPHOON is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -773,7 +721,8 @@
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
+CONFIG_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 CONFIG_B44=y
 CONFIG_FORCEDETH=y
@@ -808,7 +757,6 @@
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 CONFIG_BNX2=y
@@ -823,10 +771,6 @@
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -855,15 +799,7 @@
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -871,6 +807,7 @@
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -936,6 +873,7 @@
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_PNP=y
 CONFIG_SERIAL_8250_NR_UARTS=4
@@ -951,16 +889,11 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_INTEL=y
 CONFIG_HW_RANDOM_AMD=y
-# CONFIG_HW_RANDOM_GEODE is not set
 # CONFIG_NVRAM is not set
 CONFIG_RTC=y
 # CONFIG_R3964 is not set
@@ -979,127 +912,19 @@
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
-CONFIG_I2C=m
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=m
-
-#
-# 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_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_TINY_USB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 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_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
+# CONFIG_I2C is not set
 
 #
 # SPI support
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_AD7418 is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_K8TEMP is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-CONFIG_SENSORS_CORETEMP=y
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-CONFIG_SENSORS_SMSC47B397=m
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_HDAPS is not set
-# CONFIG_SENSORS_APPLESMC is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
 
 #
 # Multifunction device drivers
@@ -1149,15 +974,11 @@
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
@@ -1168,10 +989,7 @@
 # CONFIG_USB_HIDINPUT_POWERBOOK is not set
 # CONFIG_HID_FF is not set
 # CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1185,6 +1003,7 @@
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1194,7 +1013,6 @@
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1202,6 +1020,7 @@
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1292,15 +1111,7 @@
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
 # CONFIG_EDAC is not set
 
 #
@@ -1320,11 +1131,13 @@
 #
 # DMA Devices
 #
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
 
 #
-# Virtualization
+# Userspace I/O
 #
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
 
 #
 # Firmware Drivers
@@ -1332,6 +1145,7 @@
 # CONFIG_EDD is not set
 # CONFIG_DELL_RBU is not set
 # CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
 
 #
 # File systems
@@ -1447,7 +1261,6 @@
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1524,8 +1337,9 @@
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
@@ -1533,6 +1347,7 @@
 # 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
@@ -1541,8 +1356,6 @@
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FRAME_POINTER is not set
-CONFIG_UNWIND_INFO=y
-CONFIG_STACK_UNWIND=y
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
@@ -1557,10 +1370,6 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1571,6 +1380,7 @@
 # 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_PLIST=y
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index ed56a88..b70f3e7 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -38,6 +38,7 @@
 
 int sysctl_vsyscall32 = 1;
 
+#undef ARCH_DLINFO
 #define ARCH_DLINFO do {  \
 	if (sysctl_vsyscall32) { \
 	NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 3f66e970..9382786 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -104,7 +104,7 @@
 	pushq	%rax
 	CFI_ADJUST_CFA_OFFSET 8
 	cld
-	SAVE_ARGS 0,0,0
+	SAVE_ARGS 0,0,1
  	/* no need to do an access_ok check here because rbp has been
  	   32bit zero extended */ 
 1:	movl	(%rbp),%r9d
@@ -294,7 +294,7 @@
  */ 				
 
 ENTRY(ia32_syscall)
-	CFI_STARTPROC	simple
+	CFI_STARTPROC32	simple
 	CFI_SIGNAL_FRAME
 	CFI_DEF_CFA	rsp,SS+8-RIP
 	/*CFI_REL_OFFSET	ss,SS-RIP*/
@@ -330,6 +330,7 @@
 
 ia32_tracesys:			 
 	SAVE_REST
+	CLEAR_RREGS
 	movq $-ENOSYS,RAX(%rsp)	/* really needed? */
 	movq %rsp,%rdi        /* &pt_regs -> arg1 */
 	call syscall_trace_enter
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index a3d450d..8f681cae7 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -20,7 +20,7 @@
 #include <linux/ioport.h>
 #include <asm/e820.h>
 #include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
 #include <asm/k8.h>
@@ -214,7 +214,7 @@
 	if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
 		return;
 
-	printk("Checking aperture...\n"); 
+	printk(KERN_INFO  "Checking aperture...\n");
 
 	fix = 0;
 	for (num = 24; num < 32; num++) {		
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 1b0e07b..900ff38 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -92,8 +92,9 @@
 void enable_NMI_through_LVT0 (void * dummy)
 {
 	unsigned int v;
-	
-	v = APIC_DM_NMI;                        /* unmask and set to NMI */
+
+	/* unmask and set to NMI */
+	v = APIC_DM_NMI;
 	apic_write(APIC_LVT0, v);
 }
 
@@ -120,7 +121,7 @@
 	 * holds up an irq slot - in excessive cases (when multiple
 	 * unexpected vectors occur) that might lock up the APIC
 	 * completely.
-  	 * But don't ack when the APIC is disabled. -AK
+	 * But don't ack when the APIC is disabled. -AK
 	 */
 	if (!disable_apic)
 		ack_APIC_irq();
@@ -616,7 +617,7 @@
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
  * On AMD64 we trust the BIOS - if it says no APIC it is likely
- * not correctly set up (usually the APIC timer won't work etc.) 
+ * not correctly set up (usually the APIC timer won't work etc.)
  */
 
 static int __init detect_init_APIC (void)
@@ -789,13 +790,13 @@
 	local_irq_save(flags);
 
 	/* wait for irq slice */
- 	if (hpet_address && hpet_use_timer) {
- 		int trigger = hpet_readl(HPET_T0_CMP);
- 		while (hpet_readl(HPET_COUNTER) >= trigger)
- 			/* do nothing */ ;
- 		while (hpet_readl(HPET_COUNTER) <  trigger)
- 			/* do nothing */ ;
- 	} else {
+	if (hpet_address && hpet_use_timer) {
+		int trigger = hpet_readl(HPET_T0_CMP);
+		while (hpet_readl(HPET_COUNTER) >= trigger)
+			/* do nothing */ ;
+		while (hpet_readl(HPET_COUNTER) <  trigger)
+			/* do nothing */ ;
+	} else {
 		int c1, c2;
 		outb_p(0x00, 0x43);
 		c2 = inb_p(0x40);
@@ -881,10 +882,10 @@
 
 void __init setup_boot_APIC_clock (void)
 {
-	if (disable_apic_timer) { 
-		printk(KERN_INFO "Disabling APIC timer\n"); 
-		return; 
-	} 
+	if (disable_apic_timer) {
+		printk(KERN_INFO "Disabling APIC timer\n");
+		return;
+	}
 
 	printk(KERN_INFO "Using local APIC timer interrupts.\n");
 	using_apic_timer = 1;
@@ -990,8 +991,8 @@
 	return -EINVAL;
 }
 
-void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-			    unsigned char msg_type, unsigned char mask)
+void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+			     unsigned char msg_type, unsigned char mask)
 {
 	unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
 	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
@@ -1128,20 +1129,6 @@
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
 		ack_APIC_irq();
 
-#if 0
-	static unsigned long last_warning; 
-	static unsigned long skipped; 
-
-	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
-	if (time_before(last_warning+30*HZ,jiffies)) { 
-		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
-		       smp_processor_id(), skipped);
-		last_warning = jiffies; 
-		skipped = 0;
-	} else { 
-		skipped++; 
-	} 
-#endif 
 	irq_exit();
 }
 
@@ -1173,11 +1160,11 @@
 	   7: Illegal register address
 	*/
 	printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
-	        smp_processor_id(), v , v1);
+		smp_processor_id(), v , v1);
 	irq_exit();
 }
 
-int disable_apic; 
+int disable_apic;
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
@@ -1185,11 +1172,11 @@
  */
 int __init APIC_init_uniprocessor (void)
 {
-	if (disable_apic) { 
+	if (disable_apic) {
 		printk(KERN_INFO "Apic disabled\n");
-		return -1; 
+		return -1;
 	}
-	if (!cpu_has_apic) { 
+	if (!cpu_has_apic) {
 		disable_apic = 1;
 		printk(KERN_INFO "Apic disabled by BIOS\n");
 		return -1;
@@ -1211,8 +1198,8 @@
 	return 0;
 }
 
-static __init int setup_disableapic(char *str) 
-{ 
+static __init int setup_disableapic(char *str)
+{
 	disable_apic = 1;
 	clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
 	return 0;
@@ -1220,10 +1207,10 @@
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str) 
-{ 
+static __init int setup_nolapic(char *str)
+{
 	return setup_disableapic(str);
-} 
+}
 early_param("nolapic", setup_nolapic);
 
 static int __init parse_lapic_timer_c2_ok(char *arg)
@@ -1233,13 +1220,13 @@
 }
 early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
 
-static __init int setup_noapictimer(char *str) 
-{ 
+static __init int setup_noapictimer(char *str)
+{
 	if (str[0] != ' ' && str[0] != 0)
 		return 0;
 	disable_apic_timer = 1;
 	return 1;
-} 
+}
 
 static __init int setup_apicmaintimer(char *str)
 {
@@ -1264,5 +1251,5 @@
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer); 
+__setup("noapictimer", setup_noapictimer);
 
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 13c6c37..0f4d5e2 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -194,37 +194,6 @@
 }
 
 /*
- * Find the hole size in the range.
- */
-unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
-{
-	unsigned long ram = 0;
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		unsigned long last, addr;
-
-		if (ei->type != E820_RAM ||
-		    ei->addr+ei->size <= start ||
-		    ei->addr >= end)
-			continue;
-
-		addr = round_up(ei->addr, PAGE_SIZE);
-		if (addr < start)
-			addr = start;
-
-		last = round_down(ei->addr + ei->size, PAGE_SIZE);
-		if (last >= end)
-			last = end;
-
-		if (last > addr)
-			ram += last - addr;
-	}
-	return ((end - start) - ram);
-}
-
-/*
  * Mark e820 reserved areas as busy for the resource manager.
  */
 void __init e820_reserve_resources(void)
@@ -289,47 +258,61 @@
 	}
 }
 
+/*
+ * Finds an active region in the address range from start_pfn to end_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
+ */
+static int __init e820_find_active_region(const struct e820entry *ei,
+					  unsigned long start_pfn,
+					  unsigned long end_pfn,
+					  unsigned long *ei_startpfn,
+					  unsigned long *ei_endpfn)
+{
+	*ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
+	*ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT;
+
+	/* Skip map entries smaller than a page */
+	if (*ei_startpfn >= *ei_endpfn)
+		return 0;
+
+	/* Check if end_pfn_map should be updated */
+	if (ei->type != E820_RAM && *ei_endpfn > end_pfn_map)
+		end_pfn_map = *ei_endpfn;
+
+	/* Skip if map is outside the node */
+	if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
+				    *ei_startpfn >= end_pfn)
+		return 0;
+
+	/* Check for overlaps */
+	if (*ei_startpfn < start_pfn)
+		*ei_startpfn = start_pfn;
+	if (*ei_endpfn > end_pfn)
+		*ei_endpfn = end_pfn;
+
+	/* Obey end_user_pfn to save on memmap */
+	if (*ei_startpfn >= end_user_pfn)
+		return 0;
+	if (*ei_endpfn > end_user_pfn)
+		*ei_endpfn = end_user_pfn;
+
+	return 1;
+}
+
 /* Walk the e820 map and register active regions within a node */
 void __init
 e820_register_active_regions(int nid, unsigned long start_pfn,
 							unsigned long end_pfn)
 {
+	unsigned long ei_startpfn;
+	unsigned long ei_endpfn;
 	int i;
-	unsigned long ei_startpfn, ei_endpfn;
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
-		ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
-								>> PAGE_SHIFT;
 
-		/* Skip map entries smaller than a page */
-		if (ei_startpfn >= ei_endpfn)
-			continue;
-
-		/* Check if end_pfn_map should be updated */
-		if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
-			end_pfn_map = ei_endpfn;
-
-		/* Skip if map is outside the node */
-		if (ei->type != E820_RAM ||
-				ei_endpfn <= start_pfn ||
-				ei_startpfn >= end_pfn)
-			continue;
-
-		/* Check for overlaps */
-		if (ei_startpfn < start_pfn)
-			ei_startpfn = start_pfn;
-		if (ei_endpfn > end_pfn)
-			ei_endpfn = end_pfn;
-
-		/* Obey end_user_pfn to save on memmap */
-		if (ei_startpfn >= end_user_pfn)
-			continue;
-		if (ei_endpfn > end_user_pfn)
-			ei_endpfn = end_user_pfn;
-
-		add_active_range(nid, ei_startpfn, ei_endpfn);
-	}
+	for (i = 0; i < e820.nr_map; i++)
+		if (e820_find_active_region(&e820.map[i],
+					    start_pfn, end_pfn,
+					    &ei_startpfn, &ei_endpfn))
+			add_active_range(nid, ei_startpfn, ei_endpfn);
 }
 
 /* 
@@ -350,12 +333,35 @@
 	e820.nr_map++;
 }
 
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long end_pfn = end >> PAGE_SHIFT;
+	unsigned long ei_startpfn;
+	unsigned long ei_endpfn;
+	unsigned long ram = 0;
+	int i;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		if (e820_find_active_region(&e820.map[i],
+					    start_pfn, end_pfn,
+					    &ei_startpfn, &ei_endpfn))
+			ram += ei_endpfn - ei_startpfn;
+	}
+	return end - start - (ram << PAGE_SHIFT);
+}
+
 void __init e820_print_map(char *who)
 {
 	int i;
 
 	for (i = 0; i < e820.nr_map; i++) {
-		printk(" %s: %016Lx - %016Lx ", who,
+		printk(KERN_INFO " %s: %016Lx - %016Lx ", who,
 			(unsigned long long) e820.map[i].addr,
 			(unsigned long long) (e820.map[i].addr + e820.map[i].size));
 		switch (e820.map[i].type) {
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 990d9c2..13aa4fd 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -14,6 +14,7 @@
 #include <linux/pci_ids.h>
 #include <asm/pci-direct.h>
 #include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/dma.h>
 
 static void __init via_bugs(void)
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index a67f87b..830cfc6 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -282,7 +282,7 @@
 sysret_signal:
 	TRACE_IRQS_ON
 	sti
-	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
 	jz    1f
 
 	/* Really a signal */
@@ -375,7 +375,7 @@
 	jmp int_restore_rest
 	
 int_signal:
-	testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
+	testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
 	jz 1f
 	movq %rsp,%rdi		# &ptregs -> arg1
 	xorl %esi,%esi		# oldset -> arg2
@@ -599,7 +599,7 @@
 	jmp retint_check
 	
 retint_signal:
-	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+	testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
 	jz    retint_swapgs
 	TRACE_IRQS_ON
 	sti
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 941c84ba..e89abcd 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -25,7 +25,7 @@
  */
 
 	.text
-	.section .bootstrap.text
+	.section .text.head
 	.code64
 	.globl startup_64
 startup_64:
@@ -243,10 +243,16 @@
 	lretq
 
 	/* SMP bootup changes these two */
+#ifndef CONFIG_HOTPLUG_CPU
+	.pushsection .init.data
+#endif
 	.align	8
 	.globl	initial_code
 initial_code:
 	.quad	x86_64_start_kernel
+#ifndef CONFIG_HOTPLUG_CPU
+	.popsection
+#endif
 	.globl init_rsp
 init_rsp:
 	.quad  init_thread_union+THREAD_SIZE-8
diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c
index b828696..e2d1b91 100644
--- a/arch/x86_64/kernel/hpet.c
+++ b/arch/x86_64/kernel/hpet.c
@@ -133,7 +133,7 @@
 	.vread		= vread_hpet,
 };
 
-int hpet_arch_init(void)
+int __init hpet_arch_init(void)
 {
 	unsigned int id;
 	u64 tmp;
@@ -190,7 +190,7 @@
  */
 
 #define TICK_COUNT 100000000
-#define TICK_MIN   5000
+#define SMI_THRESHOLD 50000
 #define MAX_TRIES  5
 
 /*
@@ -205,7 +205,7 @@
 		tsc1 = get_cycles_sync();
 		hpet1 = hpet_readl(HPET_COUNTER);
 		tsc2 = get_cycles_sync();
-		if (tsc2 - tsc1 > TICK_MIN)
+		if ((tsc2 - tsc1) < SMI_THRESHOLD)
 			break;
 	}
 	*hpet = hpet1;
@@ -439,7 +439,7 @@
 	return 1;
 }
 
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
 {
 	struct rtc_time curr_time;
 	unsigned long rtc_int_flag = 0;
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 4b32665..948cae6 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -444,24 +444,6 @@
 	}
 }
 
-void apic_timer_interrupt(void);
-void spurious_interrupt(void);
-void error_interrupt(void);
-void reschedule_interrupt(void);
-void call_function_interrupt(void);
-void irq_move_cleanup_interrupt(void);
-void invalidate_interrupt0(void);
-void invalidate_interrupt1(void);
-void invalidate_interrupt2(void);
-void invalidate_interrupt3(void);
-void invalidate_interrupt4(void);
-void invalidate_interrupt5(void);
-void invalidate_interrupt6(void);
-void invalidate_interrupt7(void);
-void thermal_interrupt(void);
-void threshold_interrupt(void);
-void i8254_timer_resume(void);
-
 static void setup_timer_hardware(void)
 {
 	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 1c6c6f7..050141c 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -152,6 +152,32 @@
 	writel(value, &io_apic->data);
 }
 
+static int io_apic_level_ack_pending(unsigned int irq)
+{
+	struct irq_pin_list *entry;
+	unsigned long flags;
+	int pending = 0;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	entry = irq_2_pin + irq;
+	for (;;) {
+		unsigned int reg;
+		int pin;
+
+		pin = entry->pin;
+		if (pin == -1)
+			break;
+		reg = io_apic_read(entry->apic, 0x10 + pin*2);
+		/* Is the remote IRR bit set? */
+		pending |= (reg >> 14) & 1;
+		if (!entry->next)
+			break;
+		entry = irq_2_pin + entry->next;
+	}
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+	return pending;
+}
+
 /*
  * Synchronize the IO-APIC and the CPU by doing
  * a dummy read from the IO-APIC
@@ -1418,9 +1444,37 @@
 	ack_APIC_irq();
 
 	/* Now we can move and renable the irq */
-	move_masked_irq(irq);
-	if (unlikely(do_unmask_irq))
+	if (unlikely(do_unmask_irq)) {
+		/* Only migrate the irq if the ack has been received.
+		 *
+		 * On rare occasions the broadcast level triggered ack gets
+		 * delayed going to ioapics, and if we reprogram the
+		 * vector while Remote IRR is still set the irq will never
+		 * fire again.
+		 *
+		 * To prevent this scenario we read the Remote IRR bit
+		 * of the ioapic.  This has two effects.
+		 * - On any sane system the read of the ioapic will
+		 *   flush writes (and acks) going to the ioapic from
+		 *   this cpu.
+		 * - We get to see if the ACK has actually been delivered.
+		 *
+		 * Based on failed experiments of reprogramming the
+		 * ioapic entry from outside of irq context starting
+		 * with masking the ioapic entry and then polling until
+		 * Remote IRR was clear before reprogramming the
+		 * ioapic I don't trust the Remote IRR bit to be
+		 * completey accurate.
+		 *
+		 * However there appears to be no other way to plug
+		 * this race, so if the Remote IRR bit is not
+		 * accurate and is causing problems then it is a hardware bug
+		 * and you can go talk to the chipset vendor about it.
+		 */
+		if (!io_apic_level_ack_pending(irq))
+			move_masked_irq(irq);
 		unmask_IO_APIC_irq(irq);
+	}
 }
 
 static struct irq_chip ioapic_chip __read_mostly = {
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index d4a0d0a..a30e004 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -39,9 +39,9 @@
 #include <linux/module.h>
 #include <linux/kdebug.h>
 
-#include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
+#include <asm/alternative.h>
 
 void jprobe_return_end(void);
 static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -209,16 +209,12 @@
 
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-	*p->addr = BREAKPOINT_INSTRUCTION;
-	flush_icache_range((unsigned long) p->addr,
-			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
 }
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
-	*p->addr = p->opcode;
-	flush_icache_range((unsigned long) p->addr,
-			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	text_poke(p->addr, &p->opcode, 1);
 }
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index f3fb817..a66d607 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -18,6 +18,8 @@
 #include <linux/capability.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/poll.h>
+#include <linux/thread_info.h>
 #include <linux/ctype.h>
 #include <linux/kmod.h>
 #include <linux/kdebug.h>
@@ -26,6 +28,7 @@
 #include <asm/mce.h>
 #include <asm/uaccess.h>
 #include <asm/smp.h>
+#include <asm/idle.h>
 
 #define MISC_MCELOG_MINOR 227
 #define NR_BANKS 6
@@ -34,13 +37,17 @@
 
 static int mce_dont_init;
 
-/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
-   3: never panic or exit (for testing only) */
+/*
+ * Tolerant levels:
+ *   0: always panic on uncorrected errors, log corrected errors
+ *   1: panic or SIGBUS on uncorrected errors, log corrected errors
+ *   2: SIGBUS or log uncorrected errors (if possible), log corrected errors
+ *   3: never panic or SIGBUS, log all errors (for testing only)
+ */
 static int tolerant = 1;
 static int banks;
 static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
-static unsigned long console_logged;
-static int notify_user;
+static unsigned long notify_user;
 static int rip_msr;
 static int mce_bootlog = 1;
 static atomic_t mce_events;
@@ -48,6 +55,8 @@
 static char trigger[128];
 static char *trigger_argv[2] = { trigger, NULL };
 
+static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
+
 /*
  * Lockless MCE logging infrastructure.
  * This avoids deadlocks on printk locks without having to break locks. Also
@@ -94,8 +103,7 @@
 	mcelog.entry[entry].finished = 1;
 	wmb();
 
-	if (!test_and_set_bit(0, &console_logged))
-		notify_user = 1;
+	set_bit(0, &notify_user);
 }
 
 static void print_mce(struct mce *m)
@@ -128,6 +136,7 @@
 static void mce_panic(char *msg, struct mce *backup, unsigned long start)
 { 
 	int i;
+
 	oops_begin();
 	for (i = 0; i < MCE_LOG_LEN; i++) {
 		unsigned long tsc = mcelog.entry[i].tsc;
@@ -139,10 +148,7 @@
 	}
 	if (backup)
 		print_mce(backup);
-	if (tolerant >= 3)
-		printk("Fake panic: %s\n", msg);
-	else
-		panic(msg);
+	panic(msg);
 } 
 
 static int mce_available(struct cpuinfo_x86 *c)
@@ -167,17 +173,6 @@
 	}
 }
 
-static void do_mce_trigger(void)
-{
-	static atomic_t mce_logged;
-	int events = atomic_read(&mce_events);
-	if (events != atomic_read(&mce_logged) && trigger[0]) {
-		/* Small race window, but should be harmless.  */
-		atomic_set(&mce_logged, events);
-		call_usermodehelper(trigger, trigger_argv, NULL, UMH_NO_WAIT);
-	}
-}
-
 /* 
  * The actual machine check handler
  */
@@ -185,11 +180,19 @@
 void do_machine_check(struct pt_regs * regs, long error_code)
 {
 	struct mce m, panicm;
-	int nowayout = (tolerant < 1); 
-	int kill_it = 0;
 	u64 mcestart = 0;
 	int i;
 	int panicm_found = 0;
+	/*
+	 * If no_way_out gets set, there is no safe way to recover from this
+	 * MCE.  If tolerant is cranked up, we'll try anyway.
+	 */
+	int no_way_out = 0;
+	/*
+	 * If kill_it gets set, there might be a way to recover from this
+	 * error.
+	 */
+	int kill_it = 0;
 
 	atomic_inc(&mce_entry);
 
@@ -201,8 +204,9 @@
 	memset(&m, 0, sizeof(struct mce));
 	m.cpu = smp_processor_id();
 	rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+	/* if the restart IP is not valid, we're done for */
 	if (!(m.mcgstatus & MCG_STATUS_RIPV))
-		kill_it = 1;
+		no_way_out = 1;
 	
 	rdtscll(mcestart);
 	barrier();
@@ -221,10 +225,18 @@
 			continue;
 
 		if (m.status & MCI_STATUS_EN) {
-			/* In theory _OVER could be a nowayout too, but
-			   assume any overflowed errors were no fatal. */
-			nowayout |= !!(m.status & MCI_STATUS_PCC);
-			kill_it |= !!(m.status & MCI_STATUS_UC);
+			/* if PCC was set, there's no way out */
+			no_way_out |= !!(m.status & MCI_STATUS_PCC);
+			/*
+			 * If this error was uncorrectable and there was
+			 * an overflow, we're in trouble.  If no overflow,
+			 * we might get away with just killing a task.
+			 */
+			if (m.status & MCI_STATUS_UC) {
+				if (tolerant < 1 || m.status & MCI_STATUS_OVER)
+					no_way_out = 1;
+				kill_it = 1;
+			}
 		}
 
 		if (m.status & MCI_STATUS_MISCV)
@@ -235,7 +247,6 @@
 		mce_get_rip(&m, regs);
 		if (error_code >= 0)
 			rdtscll(m.tsc);
-		wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
 		if (error_code != -2)
 			mce_log(&m);
 
@@ -251,45 +262,59 @@
 	}
 
 	/* Never do anything final in the polling timer */
-	if (!regs) {
-		/* Normal interrupt context here. Call trigger for any new
-		   events. */
-		do_mce_trigger();
+	if (!regs)
 		goto out;
-	}
 
 	/* If we didn't find an uncorrectable error, pick
 	   the last one (shouldn't happen, just being safe). */
 	if (!panicm_found)
 		panicm = m;
-	if (nowayout)
+
+	/*
+	 * If we have decided that we just CAN'T continue, and the user
+	 *  has not set tolerant to an insane level, give up and die.
+	 */
+	if (no_way_out && tolerant < 3)
 		mce_panic("Machine check", &panicm, mcestart);
-	if (kill_it) {
+
+	/*
+	 * If the error seems to be unrecoverable, something should be
+	 * done.  Try to kill as little as possible.  If we can kill just
+	 * one task, do that.  If the user has set the tolerance very
+	 * high, don't try to do anything at all.
+	 */
+	if (kill_it && tolerant < 3) {
 		int user_space = 0;
 
-		if (m.mcgstatus & MCG_STATUS_RIPV)
+		/*
+		 * If the EIPV bit is set, it means the saved IP is the
+		 * instruction which caused the MCE.
+		 */
+		if (m.mcgstatus & MCG_STATUS_EIPV)
 			user_space = panicm.rip && (panicm.cs & 3);
-		
-		/* When the machine was in user space and the CPU didn't get
-		   confused it's normally not necessary to panic, unless you 
-		   are paranoid (tolerant == 0)
 
-		   RED-PEN could be more tolerant for MCEs in idle,
-		   but most likely they occur at boot anyways, where
-		   it is best to just halt the machine. */
-		if ((!user_space && (panic_on_oops || tolerant < 2)) ||
-		    (unsigned)current->pid <= 1)
-			mce_panic("Uncorrected machine check", &panicm, mcestart);
-
-		/* do_exit takes an awful lot of locks and has as
-		   slight risk of deadlocking. If you don't want that
-		   don't set tolerant >= 2 */
-		if (tolerant < 3)
+		/*
+		 * If we know that the error was in user space, send a
+		 * SIGBUS.  Otherwise, panic if tolerance is low.
+		 *
+		 * do_exit() takes an awful lot of locks and has a slight
+		 * risk of deadlocking.
+		 */
+		if (user_space) {
 			do_exit(SIGBUS);
+		} else if (panic_on_oops || tolerant < 2) {
+			mce_panic("Uncorrected machine check",
+				&panicm, mcestart);
+		}
 	}
 
+	/* notify userspace ASAP */
+	set_thread_flag(TIF_MCE_NOTIFY);
+
  out:
-	/* Last thing done in the machine check exception to clear state. */
+	/* the last thing we do is clear state */
+	for (i = 0; i < banks; i++)
+		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
 	wrmsrl(MSR_IA32_MCG_STATUS, 0);
  out2:
 	atomic_dec(&mce_entry);
@@ -344,37 +369,69 @@
 	on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
 
 	/*
-	 * It's ok to read stale data here for notify_user and
-	 * console_logged as we'll simply get the updated versions
-	 * on the next mcheck_timer execution and atomic operations
-	 * on console_logged act as synchronization for notify_user
-	 * writes.
+	 * Alert userspace if needed.  If we logged an MCE, reduce the
+	 * polling interval, otherwise increase the polling interval.
 	 */
-	if (notify_user && console_logged) {
-		static unsigned long last_print;
-		unsigned long now = jiffies;
-
-		/* if we logged an MCE, reduce the polling interval */
+	if (mce_notify_user()) {
 		next_interval = max(next_interval/2, HZ/100);
-		notify_user = 0;
-		clear_bit(0, &console_logged);
-		if (time_after_eq(now, last_print + (check_interval*HZ))) {
-			last_print = now;
-			printk(KERN_INFO "Machine check events logged\n");
-		}
 	} else {
-		next_interval = min(next_interval*2, check_interval*HZ);
+		next_interval = min(next_interval*2,
+				(int)round_jiffies_relative(check_interval*HZ));
 	}
 
 	schedule_delayed_work(&mcheck_work, next_interval);
 }
 
+/*
+ * This is only called from process context.  This is where we do
+ * anything we need to alert userspace about new MCEs.  This is called
+ * directly from the poller and also from entry.S and idle, thanks to
+ * TIF_MCE_NOTIFY.
+ */
+int mce_notify_user(void)
+{
+	clear_thread_flag(TIF_MCE_NOTIFY);
+	if (test_and_clear_bit(0, &notify_user)) {
+		static unsigned long last_print;
+		unsigned long now = jiffies;
+
+		wake_up_interruptible(&mce_wait);
+		if (trigger[0])
+			call_usermodehelper(trigger, trigger_argv, NULL,
+						UMH_NO_WAIT);
+
+		if (time_after_eq(now, last_print + (check_interval*HZ))) {
+			last_print = now;
+			printk(KERN_INFO "Machine check events logged\n");
+		}
+
+		return 1;
+	}
+	return 0;
+}
+
+/* see if the idle task needs to notify userspace */
+static int
+mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk)
+{
+	/* IDLE_END should be safe - interrupts are back on */
+	if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY))
+		mce_notify_user();
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mce_idle_notifier = {
+	.notifier_call = mce_idle_callback,
+};
 
 static __init int periodic_mcheck_init(void)
 { 
 	next_interval = check_interval * HZ;
 	if (next_interval)
-		schedule_delayed_work(&mcheck_work, next_interval);
+		schedule_delayed_work(&mcheck_work,
+				      round_jiffies_relative(next_interval));
+	idle_notifier_register(&mce_idle_notifier);
 	return 0;
 } 
 __initcall(periodic_mcheck_init);
@@ -465,6 +522,40 @@
  * Character device to read and clear the MCE log.
  */
 
+static DEFINE_SPINLOCK(mce_state_lock);
+static int open_count;	/* #times opened */
+static int open_exclu;	/* already open exclusive? */
+
+static int mce_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&mce_state_lock);
+
+	if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
+		spin_unlock(&mce_state_lock);
+		return -EBUSY;
+	}
+
+	if (file->f_flags & O_EXCL)
+		open_exclu = 1;
+	open_count++;
+
+	spin_unlock(&mce_state_lock);
+
+	return nonseekable_open(inode, file);
+}
+
+static int mce_release(struct inode *inode, struct file *file)
+{
+	spin_lock(&mce_state_lock);
+
+	open_count--;
+	open_exclu = 0;
+
+	spin_unlock(&mce_state_lock);
+
+	return 0;
+}
+
 static void collect_tscs(void *data) 
 { 
 	unsigned long *cpu_tsc = (unsigned long *)data;
@@ -532,6 +623,14 @@
 	return err ? -EFAULT : buf - ubuf; 
 }
 
+static unsigned int mce_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &mce_wait, wait);
+	if (rcu_dereference(mcelog.next))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
 static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg)
 {
 	int __user *p = (int __user *)arg;
@@ -555,7 +654,10 @@
 }
 
 static const struct file_operations mce_chrdev_ops = {
+	.open = mce_open,
+	.release = mce_release,
 	.read = mce_read,
+	.poll = mce_poll,
 	.ioctl = mce_ioctl,
 };
 
@@ -565,6 +667,20 @@
 	&mce_chrdev_ops,
 };
 
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+	old_cr4 = read_cr4();
+	clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+	if (old_cr4 & X86_CR4_MCE)
+		set_in_cr4(X86_CR4_MCE);
+}
+
 /* 
  * Old style boot options parsing. Only for compatibility. 
  */
@@ -620,7 +736,8 @@
 	on_each_cpu(mce_init, NULL, 1, 1);       
 	next_interval = check_interval * HZ;
 	if (next_interval)
-		schedule_delayed_work(&mcheck_work, next_interval);
+		schedule_delayed_work(&mcheck_work,
+				      round_jiffies_relative(next_interval));
 }
 
 static struct sysdev_class mce_sysclass = {
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
index 03356e6..2f8a7f1 100644
--- a/arch/x86_64/kernel/mce_amd.c
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -157,9 +157,9 @@
 			high |= K8_APIC_EXT_LVT_ENTRY_THRESHOLD << 20;
 			wrmsr(address, low, high);
 
-			setup_APIC_extened_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
-					       THRESHOLD_APIC_VECTOR,
-					       K8_APIC_EXT_INT_MSG_FIX, 0);
+			setup_APIC_extended_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
+						THRESHOLD_APIC_VECTOR,
+						K8_APIC_EXT_INT_MSG_FIX, 0);
 
 			threshold_defaults.address = address;
 			threshold_restart_bank(&threshold_defaults, 0, 0);
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 61ae57e..8bf0ca0 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -32,7 +32,6 @@
 
 /* Have we found an MP table */
 int smp_found_config;
-unsigned int __initdata maxcpus = NR_CPUS;
 
 /*
  * Various Linux-internal data structures created from the
@@ -649,6 +648,20 @@
 	return -1;
 }
 
+static u8 uniq_ioapic_id(u8 id)
+{
+	int i;
+	DECLARE_BITMAP(used, 256);
+	bitmap_zero(used, 256);
+	for (i = 0; i < nr_ioapics; i++) {
+		struct mpc_config_ioapic *ia = &mp_ioapics[i];
+		__set_bit(ia->mpc_apicid, used);
+	}
+	if (!test_bit(id, used))
+		return id;
+	return find_first_zero_bit(used, 256);
+}
+
 void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
 {
 	int idx = 0;
@@ -656,14 +669,14 @@
 	if (bad_ioapic(address))
 		return;
 
-	idx = nr_ioapics++;
+	idx = nr_ioapics;
 
 	mp_ioapics[idx].mpc_type = MP_IOAPIC;
 	mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
 	mp_ioapics[idx].mpc_apicaddr = address;
 
 	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-	mp_ioapics[idx].mpc_apicid = id;
+	mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
 	mp_ioapics[idx].mpc_apicver = 0;
 	
 	/* 
@@ -680,6 +693,8 @@
 		mp_ioapics[idx].mpc_apicaddr,
 		mp_ioapic_routing[idx].gsi_start,
 		mp_ioapic_routing[idx].gsi_end);
+
+	nr_ioapics++;
 }
 
 void __init
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index edbbc59..cb8ee9d 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -384,11 +384,14 @@
 	return rc;
 }
 
+static unsigned ignore_nmis;
+
 asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
 {
 	nmi_enter();
 	add_pda(__nmi_count,1);
-	default_do_nmi(regs);
+	if (!ignore_nmis)
+		default_do_nmi(regs);
 	nmi_exit();
 }
 
@@ -401,6 +404,18 @@
 	return 0;
 }
 
+void stop_nmi(void)
+{
+	acpi_nmi_disable();
+	ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+	ignore_nmis--;
+	acpi_nmi_enable();
+}
+
 #ifdef CONFIG_SYSCTL
 
 static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 5bd20b5..ba16c96 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1,7 +1,7 @@
 /*
  * Derived from arch/powerpc/kernel/iommu.c
  *
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
  * Copyright (C) 2006  Jon Mason <jdmason@kudzu.us>
  *
  * Author: Jon Mason <jdmason@kudzu.us>
@@ -35,7 +35,7 @@
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/calgary.h>
 #include <asm/tce.h>
 #include <asm/pci-direct.h>
@@ -50,13 +50,7 @@
 #endif /* CONFIG_CALGARY_DEFAULT_ENABLED */
 
 #define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
-#define PCI_VENDOR_DEVICE_ID_CALGARY \
-	(PCI_VENDOR_ID_IBM | PCI_DEVICE_ID_IBM_CALGARY << 16)
-
-/* we need these for register space address calculation */
-#define START_ADDRESS           0xfe000000
-#define CHASSIS_BASE            0
-#define ONE_BASED_CHASSIS_NUM   1
+#define PCI_DEVICE_ID_IBM_CALIOC2 0x0308
 
 /* register offsets inside the host bridge space */
 #define CALGARY_CONFIG_REG	0x0108
@@ -80,6 +74,12 @@
 #define PHB_MEM_2_SIZE_LOW	0x02E0
 #define PHB_DOSHOLE_OFFSET	0x08E0
 
+/* CalIOC2 specific */
+#define PHB_SAVIOR_L2		0x0DB0
+#define PHB_PAGE_MIG_CTRL	0x0DA8
+#define PHB_PAGE_MIG_DEBUG	0x0DA0
+#define PHB_ROOT_COMPLEX_STATUS 0x0CB0
+
 /* PHB_CONFIG_RW */
 #define PHB_TCE_ENABLE		0x20000000
 #define PHB_SLOT_DISABLE	0x1C000000
@@ -92,7 +92,11 @@
 /* CSR (Channel/DMA Status Register) */
 #define CSR_AGENT_MASK		0xffe0ffff
 /* CCR (Calgary Configuration Register) */
-#define CCR_2SEC_TIMEOUT        0x000000000000000EUL
+#define CCR_2SEC_TIMEOUT	0x000000000000000EUL
+/* PMCR/PMDR (Page Migration Control/Debug Registers */
+#define PMR_SOFTSTOP		0x80000000
+#define PMR_SOFTSTOPFAULT	0x40000000
+#define PMR_HARDSTOP		0x20000000
 
 #define MAX_NUM_OF_PHBS		8 /* how many PHBs in total? */
 #define MAX_NUM_CHASSIS		8 /* max number of chassis */
@@ -155,9 +159,26 @@
 	void __iomem *bbar;
 };
 
-static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calgary_tce_cache_blast(struct iommu_table *tbl);
+static void calgary_dump_error_regs(struct iommu_table *tbl);
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calioc2_tce_cache_blast(struct iommu_table *tbl);
+static void calioc2_dump_error_regs(struct iommu_table *tbl);
 
-static void tce_cache_blast(struct iommu_table *tbl);
+static struct cal_chipset_ops calgary_chip_ops = {
+	.handle_quirks = calgary_handle_quirks,
+	.tce_cache_blast = calgary_tce_cache_blast,
+	.dump_error_regs = calgary_dump_error_regs
+};
+
+static struct cal_chipset_ops calioc2_chip_ops = {
+	.handle_quirks = calioc2_handle_quirks,
+	.tce_cache_blast = calioc2_tce_cache_blast,
+	.dump_error_regs = calioc2_dump_error_regs
+};
+
+static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
 
 /* enable this to stress test the chip's TCE cache */
 #ifdef CONFIG_IOMMU_DEBUG
@@ -187,6 +208,7 @@
 {
 	return ~0UL;
 }
+
 #endif /* CONFIG_IOMMU_DEBUG */
 
 static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
@@ -206,11 +228,12 @@
 }
 
 static void iommu_range_reserve(struct iommu_table *tbl,
-        unsigned long start_addr, unsigned int npages)
+	unsigned long start_addr, unsigned int npages)
 {
 	unsigned long index;
 	unsigned long end;
 	unsigned long badbit;
+	unsigned long flags;
 
 	index = start_addr >> PAGE_SHIFT;
 
@@ -222,6 +245,8 @@
 	if (end > tbl->it_size) /* don't go off the table */
 		end = tbl->it_size;
 
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
 	badbit = verify_bit_range(tbl->it_map, 0, index, end);
 	if (badbit != ~0UL) {
 		if (printk_ratelimit())
@@ -231,23 +256,29 @@
 	}
 
 	set_bit_string(tbl->it_map, index, npages);
+
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
 
 static unsigned long iommu_range_alloc(struct iommu_table *tbl,
 	unsigned int npages)
 {
+	unsigned long flags;
 	unsigned long offset;
 
 	BUG_ON(npages == 0);
 
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
 	offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
 				       tbl->it_size, npages);
 	if (offset == ~0UL) {
-		tce_cache_blast(tbl);
+		tbl->chip_ops->tce_cache_blast(tbl);
 		offset = find_next_zero_string(tbl->it_map, 0,
 					       tbl->it_size, npages);
 		if (offset == ~0UL) {
 			printk(KERN_WARNING "Calgary: IOMMU full.\n");
+			spin_unlock_irqrestore(&tbl->it_lock, flags);
 			if (panic_on_overflow)
 				panic("Calgary: fix the allocator.\n");
 			else
@@ -259,17 +290,17 @@
 	tbl->it_hint = offset + npages;
 	BUG_ON(tbl->it_hint > tbl->it_size);
 
+	spin_unlock_irqrestore(&tbl->it_lock, flags);
+
 	return offset;
 }
 
 static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
 	unsigned int npages, int direction)
 {
-	unsigned long entry, flags;
+	unsigned long entry;
 	dma_addr_t ret = bad_dma_address;
 
-	spin_lock_irqsave(&tbl->it_lock, flags);
-
 	entry = iommu_range_alloc(tbl, npages);
 
 	if (unlikely(entry == bad_dma_address))
@@ -282,23 +313,21 @@
 	tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK,
 		  direction);
 
-	spin_unlock_irqrestore(&tbl->it_lock, flags);
-
 	return ret;
 
 error:
-	spin_unlock_irqrestore(&tbl->it_lock, flags);
 	printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
 	       "iommu %p\n", npages, tbl);
 	return bad_dma_address;
 }
 
-static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 	unsigned int npages)
 {
 	unsigned long entry;
 	unsigned long badbit;
 	unsigned long badend;
+	unsigned long flags;
 
 	/* were we called with bad_dma_address? */
 	badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE);
@@ -315,6 +344,8 @@
 
 	tce_free(tbl, entry, npages);
 
+	spin_lock_irqsave(&tbl->it_lock, flags);
+
 	badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages);
 	if (badbit != ~0UL) {
 		if (printk_ratelimit())
@@ -324,23 +355,40 @@
 	}
 
 	__clear_bit_string(tbl->it_map, entry, npages);
-}
-
-static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
-	unsigned int npages)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&tbl->it_lock, flags);
-
-	__iommu_free(tbl, dma_addr, npages);
 
 	spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
 
-static void __calgary_unmap_sg(struct iommu_table *tbl,
+static inline struct iommu_table *find_iommu_table(struct device *dev)
+{
+	struct pci_dev *pdev;
+	struct pci_bus *pbus;
+	struct iommu_table *tbl;
+
+	pdev = to_pci_dev(dev);
+
+	/* is the device behind a bridge? */
+	if (unlikely(pdev->bus->parent))
+		pbus = pdev->bus->parent;
+	else
+		pbus = pdev->bus;
+
+	tbl = pci_iommu(pbus);
+
+	BUG_ON(pdev->bus->parent &&
+	       (tbl->it_busno != pdev->bus->parent->number));
+
+	return tbl;
+}
+
+static void calgary_unmap_sg(struct device *dev,
 	struct scatterlist *sglist, int nelems, int direction)
 {
+	struct iommu_table *tbl = find_iommu_table(dev);
+
+	if (!translate_phb(to_pci_dev(dev)))
+		return;
+
 	while (nelems--) {
 		unsigned int npages;
 		dma_addr_t dma = sglist->dma_address;
@@ -350,33 +398,17 @@
 			break;
 
 		npages = num_dma_pages(dma, dmalen);
-		__iommu_free(tbl, dma, npages);
+		iommu_free(tbl, dma, npages);
 		sglist++;
 	}
 }
 
-void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
-		      int nelems, int direction)
-{
-	unsigned long flags;
-	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
-
-	if (!translate_phb(to_pci_dev(dev)))
-		return;
-
-	spin_lock_irqsave(&tbl->it_lock, flags);
-
-	__calgary_unmap_sg(tbl, sglist, nelems, direction);
-
-	spin_unlock_irqrestore(&tbl->it_lock, flags);
-}
-
 static int calgary_nontranslate_map_sg(struct device* dev,
 	struct scatterlist *sg, int nelems, int direction)
 {
 	int i;
 
- 	for (i = 0; i < nelems; i++ ) {
+	for (i = 0; i < nelems; i++ ) {
 		struct scatterlist *s = &sg[i];
 		BUG_ON(!s->page);
 		s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
@@ -385,11 +417,10 @@
 	return nelems;
 }
 
-int calgary_map_sg(struct device *dev, struct scatterlist *sg,
+static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
 	int nelems, int direction)
 {
-	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
-	unsigned long flags;
+	struct iommu_table *tbl = find_iommu_table(dev);
 	unsigned long vaddr;
 	unsigned int npages;
 	unsigned long entry;
@@ -398,8 +429,6 @@
 	if (!translate_phb(to_pci_dev(dev)))
 		return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
 
-	spin_lock_irqsave(&tbl->it_lock, flags);
-
 	for (i = 0; i < nelems; i++ ) {
 		struct scatterlist *s = &sg[i];
 		BUG_ON(!s->page);
@@ -423,26 +452,23 @@
 		s->dma_length = s->length;
 	}
 
-	spin_unlock_irqrestore(&tbl->it_lock, flags);
-
 	return nelems;
 error:
-	__calgary_unmap_sg(tbl, sg, nelems, direction);
+	calgary_unmap_sg(dev, sg, nelems, direction);
 	for (i = 0; i < nelems; i++) {
 		sg[i].dma_address = bad_dma_address;
 		sg[i].dma_length = 0;
 	}
-	spin_unlock_irqrestore(&tbl->it_lock, flags);
 	return 0;
 }
 
-dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
+static dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
 	size_t size, int direction)
 {
 	dma_addr_t dma_handle = bad_dma_address;
 	unsigned long uaddr;
 	unsigned int npages;
-	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+	struct iommu_table *tbl = find_iommu_table(dev);
 
 	uaddr = (unsigned long)vaddr;
 	npages = num_dma_pages(uaddr, size);
@@ -455,10 +481,10 @@
 	return dma_handle;
 }
 
-void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
+static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
 	size_t size, int direction)
 {
-	struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+	struct iommu_table *tbl = find_iommu_table(dev);
 	unsigned int npages;
 
 	if (!translate_phb(to_pci_dev(dev)))
@@ -468,15 +494,13 @@
 	iommu_free(tbl, dma_handle, npages);
 }
 
-void* calgary_alloc_coherent(struct device *dev, size_t size,
+static void* calgary_alloc_coherent(struct device *dev, size_t size,
 	dma_addr_t *dma_handle, gfp_t flag)
 {
 	void *ret = NULL;
 	dma_addr_t mapping;
 	unsigned int npages, order;
-	struct iommu_table *tbl;
-
-	tbl = to_pci_dev(dev)->bus->self->sysdata;
+	struct iommu_table *tbl = find_iommu_table(dev);
 
 	size = PAGE_ALIGN(size); /* size rounded up to full pages */
 	npages = size >> PAGE_SHIFT;
@@ -552,7 +576,22 @@
 	return (void __iomem*)target;
 }
 
-static void tce_cache_blast(struct iommu_table *tbl)
+static inline int is_calioc2(unsigned short device)
+{
+	return (device == PCI_DEVICE_ID_IBM_CALIOC2);
+}
+
+static inline int is_calgary(unsigned short device)
+{
+	return (device == PCI_DEVICE_ID_IBM_CALGARY);
+}
+
+static inline int is_cal_pci_dev(unsigned short device)
+{
+	return (is_calgary(device) || is_calioc2(device));
+}
+
+static void calgary_tce_cache_blast(struct iommu_table *tbl)
 {
 	u64 val;
 	u32 aer;
@@ -589,6 +628,85 @@
 	(void)readl(target); /* flush */
 }
 
+static void calioc2_tce_cache_blast(struct iommu_table *tbl)
+{
+	void __iomem *bbar = tbl->bbar;
+	void __iomem *target;
+	u64 val64;
+	u32 val;
+	int i = 0;
+	int count = 1;
+	unsigned char bus = tbl->it_busno;
+
+begin:
+	printk(KERN_DEBUG "Calgary: CalIOC2 bus 0x%x entering tce cache blast "
+	       "sequence - count %d\n", bus, count);
+
+	/* 1. using the Page Migration Control reg set SoftStop */
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "1a. read 0x%x [LE] from %p\n", val, target);
+	val |= PMR_SOFTSTOP;
+	printk(KERN_DEBUG "1b. writing 0x%x [LE] to %p\n", val, target);
+	writel(cpu_to_be32(val), target);
+
+	/* 2. poll split queues until all DMA activity is done */
+	printk(KERN_DEBUG "2a. starting to poll split queues\n");
+	target = calgary_reg(bbar, split_queue_offset(bus));
+	do {
+		val64 = readq(target);
+		i++;
+	} while ((val64 & 0xff) != 0xff && i < 100);
+	if (i == 100)
+		printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
+		       "continuing anyway\n");
+
+	/* 3. poll Page Migration DEBUG for SoftStopFault */
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "3. read 0x%x [LE] from %p\n", val, target);
+
+	/* 4. if SoftStopFault - goto (1) */
+	if (val & PMR_SOFTSTOPFAULT) {
+		if (++count < 100)
+			goto begin;
+		else {
+			printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
+			       "aborting TCE cache flush sequence!\n");
+			return; /* pray for the best */
+		}
+	}
+
+	/* 5. Slam into HardStop by reading PHB_PAGE_MIG_CTRL */
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+	printk(KERN_DEBUG "5a. slamming into HardStop by reading %p\n", target);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "5b. read 0x%x [LE] from %p\n", val, target);
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "5c. read 0x%x [LE] from %p (debug)\n", val, target);
+
+	/* 6. invalidate TCE cache */
+	printk(KERN_DEBUG "6. invalidating TCE cache\n");
+	target = calgary_reg(bbar, tar_offset(bus));
+	writeq(tbl->tar_val, target);
+
+	/* 7. Re-read PMCR */
+	printk(KERN_DEBUG "7a. Re-reading PMCR\n");
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "7b. read 0x%x [LE] from %p\n", val, target);
+
+	/* 8. Remove HardStop */
+	printk(KERN_DEBUG "8a. removing HardStop from PMCR\n");
+	target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+	val = 0;
+	printk(KERN_DEBUG "8b. writing 0x%x [LE] to %p\n", val, target);
+	writel(cpu_to_be32(val), target);
+	val = be32_to_cpu(readl(target));
+	printk(KERN_DEBUG "8c. read 0x%x [LE] from %p\n", val, target);
+}
+
 static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
 	u64 limit)
 {
@@ -598,7 +716,7 @@
 	limit++;
 
 	numpages = ((limit - start) >> PAGE_SHIFT);
-	iommu_range_reserve(dev->sysdata, start, numpages);
+	iommu_range_reserve(pci_iommu(dev->bus), start, numpages);
 }
 
 static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
@@ -606,7 +724,7 @@
 	void __iomem *target;
 	u64 low, high, sizelow;
 	u64 start, limit;
-	struct iommu_table *tbl = dev->sysdata;
+	struct iommu_table *tbl = pci_iommu(dev->bus);
 	unsigned char busnum = dev->bus->number;
 	void __iomem *bbar = tbl->bbar;
 
@@ -630,7 +748,7 @@
 	u32 val32;
 	u64 low, high, sizelow, sizehigh;
 	u64 start, limit;
-	struct iommu_table *tbl = dev->sysdata;
+	struct iommu_table *tbl = pci_iommu(dev->bus);
 	unsigned char busnum = dev->bus->number;
 	void __iomem *bbar = tbl->bbar;
 
@@ -666,14 +784,20 @@
 {
 	unsigned int npages;
 	u64 start;
-	struct iommu_table *tbl = dev->sysdata;
+	struct iommu_table *tbl = pci_iommu(dev->bus);
 
 	/* reserve EMERGENCY_PAGES from bad_dma_address and up */
 	iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);
 
 	/* avoid the BIOS/VGA first 640KB-1MB region */
-	start = (640 * 1024);
-	npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+	/* for CalIOC2 - avoid the entire first MB */
+	if (is_calgary(dev->device)) {
+		start = (640 * 1024);
+		npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+	} else { /* calioc2 */
+		start = 0;
+		npages = (1 * 1024 * 1024) >> PAGE_SHIFT;
+	}
 	iommu_range_reserve(tbl, start, npages);
 
 	/* reserve the two PCI peripheral memory regions in IO space */
@@ -694,10 +818,17 @@
 	if (ret)
 		return ret;
 
-	tbl = dev->sysdata;
+	tbl = pci_iommu(dev->bus);
 	tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
 	tce_free(tbl, 0, tbl->it_size);
 
+	if (is_calgary(dev->device))
+		tbl->chip_ops = &calgary_chip_ops;
+	else if (is_calioc2(dev->device))
+		tbl->chip_ops = &calioc2_chip_ops;
+	else
+		BUG();
+
 	calgary_reserve_regions(dev);
 
 	/* set TARs for each PHB */
@@ -706,15 +837,15 @@
 
 	/* zero out all TAR bits under sw control */
 	val64 &= ~TAR_SW_BITS;
-
-	tbl = dev->sysdata;
 	table_phys = (u64)__pa(tbl->it_base);
+
 	val64 |= table_phys;
 
 	BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
 	val64 |= (u64) specified_table_size;
 
 	tbl->tar_val = cpu_to_be64(val64);
+
 	writeq(tbl->tar_val, target);
 	readq(target); /* flush */
 
@@ -724,7 +855,7 @@
 static void __init calgary_free_bus(struct pci_dev *dev)
 {
 	u64 val64;
-	struct iommu_table *tbl = dev->sysdata;
+	struct iommu_table *tbl = pci_iommu(dev->bus);
 	void __iomem *target;
 	unsigned int bitmapsz;
 
@@ -739,16 +870,81 @@
 	tbl->it_map = NULL;
 
 	kfree(tbl);
-	dev->sysdata = NULL;
+	
+	set_pci_iommu(dev->bus, NULL);
 
 	/* Can't free bootmem allocated memory after system is up :-( */
 	bus_info[dev->bus->number].tce_space = NULL;
 }
 
+static void calgary_dump_error_regs(struct iommu_table *tbl)
+{
+	void __iomem *bbar = tbl->bbar;
+	void __iomem *target;
+	u32 csr, plssr;
+
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
+	csr = be32_to_cpu(readl(target));
+
+	target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_PLSSR_OFFSET);
+	plssr = be32_to_cpu(readl(target));
+
+	/* If no error, the agent ID in the CSR is not valid */
+	printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
+	       "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
+}
+
+static void calioc2_dump_error_regs(struct iommu_table *tbl)
+{
+	void __iomem *bbar = tbl->bbar;
+	u32 csr, csmr, plssr, mck, rcstat;
+	void __iomem *target;
+	unsigned long phboff = phb_offset(tbl->it_busno);
+	unsigned long erroff;
+	u32 errregs[7];
+	int i;
+
+	/* dump CSR */
+	target = calgary_reg(bbar, phboff | PHB_CSR_OFFSET);
+	csr = be32_to_cpu(readl(target));
+	/* dump PLSSR */
+	target = calgary_reg(bbar, phboff | PHB_PLSSR_OFFSET);
+	plssr = be32_to_cpu(readl(target));
+	/* dump CSMR */
+	target = calgary_reg(bbar, phboff | 0x290);
+	csmr = be32_to_cpu(readl(target));
+	/* dump mck */
+	target = calgary_reg(bbar, phboff | 0x800);
+	mck = be32_to_cpu(readl(target));
+
+	printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
+	       tbl->it_busno);
+
+	printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+	       csr, plssr, csmr, mck);
+
+	/* dump rest of error regs */
+	printk(KERN_EMERG "Calgary: ");
+	for (i = 0; i < ARRAY_SIZE(errregs); i++) {
+		/* err regs are at 0x810 - 0x870 */
+		erroff = (0x810 + (i * 0x10));
+		target = calgary_reg(bbar, phboff | erroff);
+		errregs[i] = be32_to_cpu(readl(target));
+		printk("0x%08x@0x%lx ", errregs[i], erroff);
+	}
+	printk("\n");
+
+	/* root complex status */
+	target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
+	rcstat = be32_to_cpu(readl(target));
+	printk(KERN_EMERG "Calgary: 0x%08x@0x%x\n", rcstat,
+	       PHB_ROOT_COMPLEX_STATUS);
+}
+
 static void calgary_watchdog(unsigned long data)
 {
 	struct pci_dev *dev = (struct pci_dev *)data;
-	struct iommu_table *tbl = dev->sysdata;
+	struct iommu_table *tbl = pci_iommu(dev->bus);
 	void __iomem *bbar = tbl->bbar;
 	u32 val32;
 	void __iomem *target;
@@ -758,13 +954,14 @@
 
 	/* If no error, the agent ID in the CSR is not valid */
 	if (val32 & CSR_AGENT_MASK) {
-		printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, "
-				  "CSR = %#x\n", dev->bus->number, val32);
+		tbl->chip_ops->dump_error_regs(tbl);
+
+		/* reset error */
 		writel(0, target);
 
 		/* Disable bus that caused the error */
 		target = calgary_reg(bbar, phb_offset(tbl->it_busno) |
-					   PHB_CONFIG_RW_OFFSET);
+				     PHB_CONFIG_RW_OFFSET);
 		val32 = be32_to_cpu(readl(target));
 		val32 |= PHB_SLOT_DISABLE;
 		writel(cpu_to_be32(val32), target);
@@ -775,8 +972,8 @@
 	}
 }
 
-static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
-	unsigned char busnum)
+static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
+	unsigned char busnum, unsigned long timeout)
 {
 	u64 val64;
 	void __iomem *target;
@@ -802,11 +999,40 @@
 	/* zero out this PHB's timer bits */
 	mask = ~(0xFUL << phb_shift);
 	val64 &= mask;
-	val64 |= (CCR_2SEC_TIMEOUT << phb_shift);
+	val64 |= (timeout << phb_shift);
 	writeq(cpu_to_be64(val64), target);
 	readq(target); /* flush */
 }
 
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+	unsigned char busnum = dev->bus->number;
+	void __iomem *bbar = tbl->bbar;
+	void __iomem *target;
+	u32 val;
+
+	/*
+	 * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
+	 */
+	target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
+	val = cpu_to_be32(readl(target));
+	val |= 0x00800000;
+	writel(cpu_to_be32(val), target);
+}
+
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+	unsigned char busnum = dev->bus->number;
+
+	/*
+	 * Give split completion a longer timeout on bus 1 for aic94xx
+	 * http://bugzilla.kernel.org/show_bug.cgi?id=7180
+	 */
+	if (is_calgary(dev->device) && (busnum == 1))
+		calgary_set_split_completion_timeout(tbl->bbar, busnum,
+						     CCR_2SEC_TIMEOUT);
+}
+
 static void __init calgary_enable_translation(struct pci_dev *dev)
 {
 	u32 val32;
@@ -816,7 +1042,7 @@
 	struct iommu_table *tbl;
 
 	busnum = dev->bus->number;
-	tbl = dev->sysdata;
+	tbl = pci_iommu(dev->bus);
 	bbar = tbl->bbar;
 
 	/* enable TCE in PHB Config Register */
@@ -824,20 +1050,15 @@
 	val32 = be32_to_cpu(readl(target));
 	val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
 
-	printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
+	printk(KERN_INFO "Calgary: enabling translation on %s PHB %#x\n",
+	       (dev->device == PCI_DEVICE_ID_IBM_CALGARY) ?
+	       "Calgary" : "CalIOC2", busnum);
 	printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
 	       "bus.\n");
 
 	writel(cpu_to_be32(val32), target);
 	readl(target); /* flush */
 
-	/*
-	 * Give split completion a longer timeout on bus 1 for aic94xx
-	 * http://bugzilla.kernel.org/show_bug.cgi?id=7180
-	 */
-	if (busnum == 1)
-		calgary_increase_split_completion_timeout(bbar, busnum);
-
 	init_timer(&tbl->watchdog_timer);
 	tbl->watchdog_timer.function = &calgary_watchdog;
 	tbl->watchdog_timer.data = (unsigned long)dev;
@@ -853,7 +1074,7 @@
 	struct iommu_table *tbl;
 
 	busnum = dev->bus->number;
-	tbl = dev->sysdata;
+	tbl = pci_iommu(dev->bus);
 	bbar = tbl->bbar;
 
 	/* disable TCE in PHB Config Register */
@@ -871,13 +1092,19 @@
 static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
 {
 	pci_dev_get(dev);
-	dev->sysdata = NULL;
-	dev->bus->self = dev;
+	set_pci_iommu(dev->bus, NULL);
+
+	/* is the device behind a bridge? */
+	if (dev->bus->parent)
+		dev->bus->parent->self = dev;
+	else
+		dev->bus->self = dev;
 }
 
 static int __init calgary_init_one(struct pci_dev *dev)
 {
 	void __iomem *bbar;
+	struct iommu_table *tbl;
 	int ret;
 
 	BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
@@ -888,7 +1115,18 @@
 		goto done;
 
 	pci_dev_get(dev);
-	dev->bus->self = dev;
+
+	if (dev->bus->parent) {
+		if (dev->bus->parent->self)
+			printk(KERN_WARNING "Calgary: IEEEE, dev %p has "
+			       "bus->parent->self!\n", dev);
+		dev->bus->parent->self = dev;
+	} else
+		dev->bus->self = dev;
+
+	tbl = pci_iommu(dev->bus);
+	tbl->chip_ops->handle_quirks(tbl, dev);
+
 	calgary_enable_translation(dev);
 
 	return 0;
@@ -924,11 +1162,18 @@
 			target = calgary_reg(bbar, offset);
 
 			val = be32_to_cpu(readl(target));
+
 			start_bus = (u8)((val & 0x00FF0000) >> 16);
 			end_bus = (u8)((val & 0x0000FF00) >> 8);
-			for (bus = start_bus; bus <= end_bus; bus++) {
-				bus_info[bus].bbar = bbar;
-				bus_info[bus].phbid = phb;
+
+			if (end_bus) {
+				for (bus = start_bus; bus <= end_bus; bus++) {
+					bus_info[bus].bbar = bbar;
+					bus_info[bus].phbid = phb;
+				}
+			} else {
+				bus_info[start_bus].bbar = bbar;
+				bus_info[start_bus].phbid = phb;
 			}
 		}
 	}
@@ -948,22 +1193,24 @@
 {
 	int ret;
 	struct pci_dev *dev = NULL;
+	void *tce_space;
 
 	ret = calgary_locate_bbars();
 	if (ret)
 		return ret;
 
 	do {
-		dev = pci_get_device(PCI_VENDOR_ID_IBM,
-				     PCI_DEVICE_ID_IBM_CALGARY,
-				     dev);
+		dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
 		if (!dev)
 			break;
+		if (!is_cal_pci_dev(dev->device))
+			continue;
 		if (!translate_phb(dev)) {
 			calgary_init_one_nontraslated(dev);
 			continue;
 		}
-		if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+		tce_space = bus_info[dev->bus->number].tce_space;
+		if (!tce_space && !translate_empty_slots)
 			continue;
 
 		ret = calgary_init_one(dev);
@@ -976,10 +1223,11 @@
 error:
 	do {
 		dev = pci_get_device_reverse(PCI_VENDOR_ID_IBM,
-					      PCI_DEVICE_ID_IBM_CALGARY,
-					      dev);
+					     PCI_ANY_ID, dev);
 		if (!dev)
 			break;
+		if (!is_cal_pci_dev(dev->device))
+			continue;
 		if (!translate_phb(dev)) {
 			pci_dev_put(dev);
 			continue;
@@ -1057,9 +1305,29 @@
 	return 0;
 }
 
+static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
+{
+	int dev;
+	u32 val;
+
+	if (pci_dev == PCI_DEVICE_ID_IBM_CALIOC2) {
+		/*
+		 * FIXME: properly scan for devices accross the
+		 * PCI-to-PCI bridge on every CalIOC2 port.
+		 */
+		return 1;
+	}
+
+	for (dev = 1; dev < 8; dev++) {
+		val = read_pci_config(bus, dev, 0, 0);
+		if (val != 0xffffffff)
+			break;
+	}
+	return (val != 0xffffffff);
+}
+
 void __init detect_calgary(void)
 {
-	u32 val;
 	int bus;
 	void *tbl;
 	int calgary_found = 0;
@@ -1116,29 +1384,26 @@
 	specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
 
 	for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
-		int dev;
 		struct calgary_bus_info *info = &bus_info[bus];
+		unsigned short pci_device;
+		u32 val;
 
-		if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+		val = read_pci_config(bus, 0, 0, 0);
+		pci_device = (val & 0xFFFF0000) >> 16;
+
+		if (!is_cal_pci_dev(pci_device))
 			continue;
 
 		if (info->translation_disabled)
 			continue;
 
-		/*
-		 * Scan the slots of the PCI bus to see if there is a device present.
-		 * The parent bus will be the zero-ith device, so start at 1.
-		 */
-		for (dev = 1; dev < 8; dev++) {
-			val = read_pci_config(bus, dev, 0, 0);
-			if (val != 0xffffffff || translate_empty_slots) {
-				tbl = alloc_tce_table();
-				if (!tbl)
-					goto cleanup;
-				info->tce_space = tbl;
-				calgary_found = 1;
-				break;
-			}
+		if (calgary_bus_has_devices(bus, pci_device) ||
+		    translate_empty_slots) {
+			tbl = alloc_tce_table();
+			if (!tbl)
+				goto cleanup;
+			info->tce_space = tbl;
+			calgary_found = 1;
 		}
 	}
 
@@ -1249,3 +1514,66 @@
 	return 1;
 }
 __setup("calgary=", calgary_parse_options);
+
+static void __init calgary_fixup_one_tce_space(struct pci_dev *dev)
+{
+	struct iommu_table *tbl;
+	unsigned int npages;
+	int i;
+
+	tbl = pci_iommu(dev->bus);
+
+	for (i = 0; i < 4; i++) {
+		struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i];
+
+		/* Don't give out TCEs that map MEM resources */
+		if (!(r->flags & IORESOURCE_MEM))
+			continue;
+
+		/* 0-based? we reserve the whole 1st MB anyway */
+		if (!r->start)
+			continue;
+
+		/* cover the whole region */
+		npages = (r->end - r->start) >> PAGE_SHIFT;
+		npages++;
+
+		iommu_range_reserve(tbl, r->start, npages);
+	}
+}
+
+static int __init calgary_fixup_tce_spaces(void)
+{
+	struct pci_dev *dev = NULL;
+	void *tce_space;
+
+	if (no_iommu || swiotlb || !calgary_detected)
+		return -ENODEV;
+
+	printk(KERN_DEBUG "Calgary: fixing up tce spaces\n");
+
+	do {
+		dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
+		if (!dev)
+			break;
+		if (!is_cal_pci_dev(dev->device))
+			continue;
+		if (!translate_phb(dev))
+			continue;
+
+		tce_space = bus_info[dev->bus->number].tce_space;
+		if (!tce_space)
+			continue;
+
+		calgary_fixup_one_tce_space(dev);
+
+	} while (1);
+
+	return 0;
+}
+
+/*
+ * We need to be call after pcibios_assign_resources (fs_initcall level)
+ * and before device_initcall.
+ */
+rootfs_initcall(calgary_fixup_tce_spaces);
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index 90f6315..05d745e 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -8,7 +8,7 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/calgary.h>
 
 int iommu_merge __read_mostly = 0;
@@ -321,6 +321,11 @@
 	return 0;
 }
 
+void pci_iommu_shutdown(void)
+{
+	gart_iommu_shutdown();
+}
+
 #ifdef CONFIG_PCI
 /* Many VIA bridges seem to corrupt data for DAC. Disable it here */
 
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index ae091cd..4918c57 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -28,6 +28,7 @@
 #include <asm/mtrr.h>
 #include <asm/pgtable.h>
 #include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/cacheflush.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
@@ -235,7 +236,7 @@
 }
 
 /* Map a single area into the IOMMU */
-dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
+static dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
 {
 	unsigned long phys_mem, bus;
 
@@ -253,7 +254,7 @@
 /*
  * Free a DMA mapping.
  */
-void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
+static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
 		      size_t size, int direction)
 {
 	unsigned long iommu_page;
@@ -275,7 +276,7 @@
 /*
  * Wrapper for pci_unmap_single working with scatterlists.
  */
-void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
 {
 	int i;
 
@@ -571,6 +572,26 @@
 	.unmap_sg = gart_unmap_sg,
 };
 
+void gart_iommu_shutdown(void)
+{
+	struct pci_dev *dev;
+	int i;
+
+	if (no_agp && (dma_ops != &gart_dma_ops))
+		return;
+
+        for (i = 0; i < num_k8_northbridges; i++) {
+                u32 ctl;
+
+                dev = k8_northbridges[i];
+                pci_read_config_dword(dev, 0x90, &ctl);
+
+                ctl &= ~1;
+
+                pci_write_config_dword(dev, 0x90, ctl);
+        }
+}
+
 void __init gart_iommu_init(void)
 { 
 	struct agp_kern_info info;
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index 6dade0c..2a34c6c 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -6,7 +6,7 @@
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/processor.h>
 #include <asm/dma.h>
 
@@ -34,7 +34,7 @@
 	return bus;
 }
 
-void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
+static void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
 			int direction)
 {
 }
@@ -54,7 +54,7 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
+static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
 	       int nents, int direction)
 {
 	int i;
@@ -74,7 +74,7 @@
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
+static void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
 		  int nents, int dir)
 {
 }
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 4b4569a..b2f405e 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/proto.h>
+#include <asm/iommu.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
 
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 5909039..e7ac629 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -207,6 +207,7 @@
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 
+			check_pgt_cache();
 			rmb();
 			idle = pm_idle;
 			if (!idle)
@@ -278,7 +279,7 @@
 		 */
 		if (!pm_idle) {
 			if (!printed) {
-				printk("using mwait in idle threads.\n");
+				printk(KERN_INFO "using mwait in idle threads.\n");
 				printed = 1;
 			}
 			pm_idle = mwait_idle;
@@ -305,6 +306,7 @@
 void __show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
+	unsigned long d0, d1, d2, d3, d6, d7;
 	unsigned int fsindex,gsindex;
 	unsigned int ds,cs,es; 
 
@@ -340,15 +342,24 @@
 	rdmsrl(MSR_GS_BASE, gs); 
 	rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); 
 
-	asm("movq %%cr0, %0": "=r" (cr0));
-	asm("movq %%cr2, %0": "=r" (cr2));
-	asm("movq %%cr3, %0": "=r" (cr3));
-	asm("movq %%cr4, %0": "=r" (cr4));
+	cr0 = read_cr0();
+	cr2 = read_cr2();
+	cr3 = read_cr3();
+	cr4 = read_cr4();
 
 	printk("FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", 
 	       fs,fsindex,gs,gsindex,shadowgs); 
 	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
 	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+	get_debugreg(d0, 0);
+	get_debugreg(d1, 1);
+	get_debugreg(d2, 2);
+	printk("DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
+	get_debugreg(d3, 3);
+	get_debugreg(d6, 6);
+	get_debugreg(d7, 7);
+	printk("DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
 }
 
 void show_regs(struct pt_regs *regs)
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 7503068..368db2b 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -16,6 +16,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/apic.h>
+#include <asm/iommu.h>
 
 /*
  * Power off function, if any
@@ -81,6 +82,7 @@
 void machine_shutdown(void)
 {
 	unsigned long flags;
+
 	/* Stop the cpus and apics */
 #ifdef CONFIG_SMP
 	int reboot_cpu_id;
@@ -111,6 +113,8 @@
 	disable_IO_APIC();
 
 	local_irq_restore(flags);
+
+	pci_iommu_shutdown();
 }
 
 void machine_emergency_restart(void)
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 33ef718..af838f6 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -575,6 +575,8 @@
 	level = cpuid_eax(1);
 	if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
 		set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
+	if (c->x86 == 0x10)
+		set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
 
 	/* Enable workaround for FXSAVE leak */
 	if (c->x86 >= 6)
@@ -600,8 +602,14 @@
 	if (c->extended_cpuid_level >= 0x80000008)
 		amd_detect_cmp(c);
 
-	/* Fix cpuid4 emulation for more */
-	num_cache_leaves = 3;
+	if (c->extended_cpuid_level >= 0x80000006 &&
+		(cpuid_edx(0x80000006) & 0xf000))
+		num_cache_leaves = 4;
+	else
+		num_cache_leaves = 3;
+
+	if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
+		set_bit(X86_FEATURE_K8, &c->x86_capability);
 
 	/* RDTSC can be speculated around */
 	clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 290f5d8..739175b 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -26,6 +26,7 @@
 #include <asm/i387.h>
 #include <asm/proto.h>
 #include <asm/ia32_unistd.h>
+#include <asm/mce.h>
 
 /* #define DEBUG_SIG 1 */
 
@@ -472,6 +473,12 @@
 		clear_thread_flag(TIF_SINGLESTEP);
 	}
 
+#ifdef CONFIG_X86_MCE
+	/* notify userspace of pending MCEs */
+	if (thread_info_flags & _TIF_MCE_NOTIFY)
+		mce_notify_user();
+#endif /* CONFIG_X86_MCE */
+
 	/* deal with pending signal delivery */
 	if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
 		do_signal(regs);
@@ -480,7 +487,7 @@
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 { 
 	struct task_struct *me = current; 
-	if (exception_trace)
+	if (show_unhandled_signals && printk_ratelimit())
 		printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
 	       me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax); 
 
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 0694940..673a300 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -241,7 +241,7 @@
 	}
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-
+	check_pgt_cache();
 	preempt_enable();
 }
 EXPORT_SYMBOL(flush_tlb_mm);
@@ -386,9 +386,9 @@
 		return 0;
 	}
 
-	spin_lock_bh(&call_lock);
+	spin_lock(&call_lock);
 	__smp_call_function_single(cpu, func, info, nonatomic, wait);
-	spin_unlock_bh(&call_lock);
+	spin_unlock(&call_lock);
 	put_cpu();
 	return 0;
 }
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 6a5a98f..ea83a9f 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -55,11 +55,11 @@
 	 * control registers 
 	 */
 	rdmsrl(MSR_EFER, ctxt->efer);
-	asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
-	asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
-	asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
-	asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4));
-	asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8));
+	ctxt->cr0 = read_cr0();
+	ctxt->cr2 = read_cr2();
+	ctxt->cr3 = read_cr3();
+	ctxt->cr4 = read_cr4();
+	ctxt->cr8 = read_cr8();
 }
 
 void save_processor_state(void)
@@ -81,11 +81,11 @@
 	 * control registers
 	 */
 	wrmsrl(MSR_EFER, ctxt->efer);
-	asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
-	asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
-	asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
-	asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2));
-	asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0));
+	write_cr8(ctxt->cr8);
+	write_cr4(ctxt->cr4);
+	write_cr3(ctxt->cr3);
+	write_cr2(ctxt->cr2);
+	write_cr0(ctxt->cr0);
 
 	/*
 	 * now restore the descriptor tables to their proper values
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
index f61fb8e..3aeae2f 100644
--- a/arch/x86_64/kernel/tce.c
+++ b/arch/x86_64/kernel/tce.c
@@ -136,9 +136,9 @@
 	struct iommu_table *tbl;
 	int ret;
 
-	if (dev->sysdata) {
-		printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
-		       dev, dev->sysdata);
+	if (pci_iommu(dev->bus)) {
+		printk(KERN_ERR "Calgary: dev %p has sysdata->iommu %p\n",
+		       dev, pci_iommu(dev->bus));
 		BUG();
 	}
 
@@ -155,11 +155,7 @@
 
 	tbl->bbar = bbar;
 
-	/*
-	 * NUMA is already using the bus's sysdata pointer, so we use
-	 * the bus's pci_dev's sysdata instead.
-	 */
-	dev->sysdata = tbl;
+	set_pci_iommu(dev->bus, tbl);
 
 	return 0;
 
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 4a0895b..6d48a4e 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -33,6 +33,7 @@
 #include <acpi/acpi_bus.h>
 #endif
 #include <asm/8253pit.h>
+#include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
 #include <asm/timex.h>
@@ -44,12 +45,14 @@
 #include <asm/hpet.h>
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
+#include <asm/vgtod.h>
 
 static char *timename = NULL;
 
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
@@ -79,8 +82,9 @@
  * sheet for details.
  */
 
-static void set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long nowtime)
 {
+	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char control, freq_select;
 
@@ -120,6 +124,7 @@
 	if (abs(real_minutes - cmos_minutes) >= 30) {
 		printk(KERN_WARNING "time.c: can't update CMOS clock "
 		       "from %d to %d\n", cmos_minutes, real_minutes);
+		retval = -1;
 	} else {
 		BIN_TO_BCD(real_seconds);
 		BIN_TO_BCD(real_minutes);
@@ -139,12 +144,17 @@
 	CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
 
 	spin_unlock(&rtc_lock);
+
+	return retval;
 }
 
+int update_persistent_clock(struct timespec now)
+{
+	return set_rtc_mmss(now.tv_sec);
+}
 
 void main_timer_handler(void)
 {
-	static unsigned long rtc_update = 0;
 /*
  * Here we are in the timer irq handler. We have irqs locally disabled (so we
  * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
@@ -172,20 +182,6 @@
 	if (!using_apic_timer)
 		smp_local_timer_interrupt();
 
-/*
- * If we have an externally synchronized Linux clock, then update CMOS clock
- * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
- * closest to exactly 500 ms before the next second. If the update fails, we
- * don't care, as it'll be updated on the next turn, and the problem (time way
- * off) isn't likely to go away much sooner anyway.
- */
-
-	if (ntp_synced() && xtime.tv_sec > rtc_update &&
-		abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
-		set_rtc_mmss(xtime.tv_sec);
-		rtc_update = xtime.tv_sec + 660;
-	}
- 
 	write_sequnlock(&xtime_lock);
 }
 
@@ -199,7 +195,7 @@
 	return IRQ_HANDLED;
 }
 
-static unsigned long get_cmos_time(void)
+unsigned long read_persistent_clock(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	unsigned long flags;
@@ -226,7 +222,7 @@
 	/*
 	 * We know that x86-64 always uses BCD format, no need to check the
 	 * config register.
- 	 */
+	 */
 
 	BCD_TO_BIN(sec);
 	BCD_TO_BIN(min);
@@ -239,11 +235,11 @@
 		BCD_TO_BIN(century);
 		year += century * 100;
 		printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
-	} else { 
+	} else {
 		/*
 		 * x86-64 systems only exists since 2002.
 		 * This will work up to Dec 31, 2100
-	 	 */
+		 */
 		year += 2000;
 	}
 
@@ -255,45 +251,45 @@
 #define TICK_COUNT 100000000
 static unsigned int __init tsc_calibrate_cpu_khz(void)
 {
-       int tsc_start, tsc_now;
-       int i, no_ctr_free;
-       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
-       unsigned long flags;
+	int tsc_start, tsc_now;
+	int i, no_ctr_free;
+	unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+	unsigned long flags;
 
-       for (i = 0; i < 4; i++)
-               if (avail_to_resrv_perfctr_nmi_bit(i))
-                       break;
-       no_ctr_free = (i == 4);
-       if (no_ctr_free) {
-               i = 3;
-               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               rdmsrl(MSR_K7_PERFCTR3, pmc3);
-       } else {
-               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-       local_irq_save(flags);
-       /* start meauring cycles, incrementing from 0 */
-       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
-       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
-       rdtscl(tsc_start);
-       do {
-               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
-               tsc_now = get_cycles_sync();
-       } while ((tsc_now - tsc_start) < TICK_COUNT);
+	for (i = 0; i < 4; i++)
+		if (avail_to_resrv_perfctr_nmi_bit(i))
+			break;
+	no_ctr_free = (i == 4);
+	if (no_ctr_free) {
+		i = 3;
+		rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+		wrmsrl(MSR_K7_EVNTSEL3, 0);
+		rdmsrl(MSR_K7_PERFCTR3, pmc3);
+	} else {
+		reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+		reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+	}
+	local_irq_save(flags);
+	/* start meauring cycles, incrementing from 0 */
+	wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+	wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+	rdtscl(tsc_start);
+	do {
+		rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+		tsc_now = get_cycles_sync();
+	} while ((tsc_now - tsc_start) < TICK_COUNT);
 
-       local_irq_restore(flags);
-       if (no_ctr_free) {
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               wrmsrl(MSR_K7_PERFCTR3, pmc3);
-               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
-       } else {
-               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
+	local_irq_restore(flags);
+	if (no_ctr_free) {
+		wrmsrl(MSR_K7_EVNTSEL3, 0);
+		wrmsrl(MSR_K7_PERFCTR3, pmc3);
+		wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+	} else {
+		release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+		release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+	}
 
-       return pmc_now * tsc_khz / (tsc_now - tsc_start);
+	return pmc_now * tsc_khz / (tsc_now - tsc_start);
 }
 
 /*
@@ -321,7 +317,7 @@
 	end = get_cycles_sync();
 
 	spin_unlock_irqrestore(&i8253_lock, flags);
-	
+
 	return (end - start) / 50;
 }
 
@@ -366,25 +362,20 @@
 	.handler	= timer_interrupt,
 	.flags		= IRQF_DISABLED | IRQF_IRQPOLL,
 	.mask		= CPU_MASK_NONE,
-	.name 		= "timer"
+	.name		= "timer"
 };
 
 void __init time_init(void)
 {
 	if (nohpet)
 		hpet_address = 0;
-	xtime.tv_sec = get_cmos_time();
-	xtime.tv_nsec = 0;
-
-	set_normalized_timespec(&wall_to_monotonic,
-	                        -xtime.tv_sec, -xtime.tv_nsec);
 
 	if (hpet_arch_init())
 		hpet_address = 0;
 
 	if (hpet_use_timer) {
 		/* set tick_nsec to use the proper rate for HPET */
-	  	tick_nsec = TICK_NSEC_HPET;
+		tick_nsec = TICK_NSEC_HPET;
 		tsc_khz = hpet_calibrate_tsc();
 		timename = "HPET";
 	} else {
@@ -415,54 +406,21 @@
 	setup_irq(0, &irq0);
 }
 
-
-static long clock_cmos_diff;
-static unsigned long sleep_start;
-
 /*
  * sysfs support for the timer.
  */
 
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
-	/*
-	 * Estimate time zone so that set_time can update the clock
-	 */
-	long cmos_time =  get_cmos_time();
-
-	clock_cmos_diff = -cmos_time;
-	clock_cmos_diff += get_seconds();
-	sleep_start = cmos_time;
 	return 0;
 }
 
 static int timer_resume(struct sys_device *dev)
 {
-	unsigned long flags;
-	unsigned long sec;
-	unsigned long ctime = get_cmos_time();
-	long sleep_length = (ctime - sleep_start) * HZ;
-
-	if (sleep_length < 0) {
-		printk(KERN_WARNING "Time skew detected in timer resume!\n");
-		/* The time after the resume must not be earlier than the time
-		 * before the suspend or some nasty things will happen
-		 */
-		sleep_length = 0;
-		ctime = sleep_start;
-	}
 	if (hpet_address)
 		hpet_reenable();
 	else
 		i8254_timer_resume();
-
-	sec = ctime + clock_cmos_diff;
-	write_seqlock_irqsave(&xtime_lock,flags);
-	xtime.tv_sec = sec;
-	xtime.tv_nsec = 0;
-	jiffies += sleep_length;
-	write_sequnlock_irqrestore(&xtime_lock,flags);
-	touch_softlockup_watchdog();
 	return 0;
 }
 
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 8713ad4..0388842 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -584,7 +584,8 @@
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = trapnr;
 
-		if (exception_trace && unhandled_signal(tsk, signr))
+		if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+		    printk_ratelimit())
 			printk(KERN_INFO
 			       "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
 			       tsk->comm, tsk->pid, str,
@@ -688,7 +689,8 @@
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 13;
 
-		if (exception_trace && unhandled_signal(tsk, SIGSEGV))
+		if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+		    printk_ratelimit())
 			printk(KERN_INFO
 		       "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
 			       tsk->comm, tsk->pid,
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index e850aa0..9b76b03 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -61,25 +61,9 @@
  * first tick after the change will be slightly wrong.
  */
 
-#include <linux/workqueue.h>
-
-static unsigned int cpufreq_delayed_issched = 0;
-static unsigned int cpufreq_init = 0;
-static struct work_struct cpufreq_delayed_get_work;
-
-static void handle_cpufreq_delayed_get(struct work_struct *v)
-{
-	unsigned int cpu;
-	for_each_online_cpu(cpu) {
-		cpufreq_get(cpu);
-	}
-	cpufreq_delayed_issched = 0;
-}
-
-static unsigned int  ref_freq = 0;
-static unsigned long loops_per_jiffy_ref = 0;
-
-static unsigned long tsc_khz_ref = 0;
+static unsigned int  ref_freq;
+static unsigned long loops_per_jiffy_ref;
+static unsigned long tsc_khz_ref;
 
 static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 				 void *data)
@@ -125,10 +109,8 @@
 
 static int __init cpufreq_tsc(void)
 {
-	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get);
-	if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
-				       CPUFREQ_TRANSITION_NOTIFIER))
-		cpufreq_init = 1;
+	cpufreq_register_notifier(&time_cpufreq_notifier_block,
+				  CPUFREQ_TRANSITION_NOTIFIER);
 	return 0;
 }
 
@@ -153,17 +135,18 @@
 #endif
 	/* Most intel systems have synchronized TSCs except for
 	   multi node systems */
- 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
 #ifdef CONFIG_ACPI
 		/* But TSC doesn't tick in C3 so don't use it there */
-		if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
+		if (acpi_gbl_FADT.header.length > 0 &&
+		    acpi_gbl_FADT.C3latency < 1000)
 			return 1;
 #endif
- 		return 0;
+		return 0;
 	}
 
- 	/* Assume multi socket systems are not synchronized */
- 	return num_present_cpus() > 1;
+	/* Assume multi socket systems are not synchronized */
+	return num_present_cpus() > 1;
 }
 
 int __init notsc_setup(char *s)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 5c57ea4..ba8ea97 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -28,7 +28,7 @@
   _text = .;			/* Text and read-only data */
   .text :  AT(ADDR(.text) - LOAD_OFFSET) {
 	/* First the code that has to be first for bootstrapping */
-	*(.bootstrap.text)
+	*(.text.head)
 	_stext = .;
 	/* Then the rest */
 	TEXT_TEXT
@@ -54,6 +54,13 @@
 
   RODATA
 
+  . = ALIGN(4);
+  .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
+  	__tracedata_start = .;
+	*(.tracedata)
+  	__tracedata_end = .;
+  }
+
   . = ALIGN(PAGE_SIZE);        /* Align data segment to page size boundary */
 				/* Data */
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -93,6 +100,9 @@
   .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
 		{ *(.vsyscall_gtod_data) }
   vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
+  .vsyscall_clock : AT(VLOAD(.vsyscall_clock))
+		{ *(.vsyscall_clock) }
+  vsyscall_clock = VVIRT(.vsyscall_clock);
 
 
   .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
@@ -133,20 +143,11 @@
   /* might get freed after init */
   . = ALIGN(4096);
   __smp_alt_begin = .;
-  __smp_alt_instructions = .;
-  .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
-	*(.smp_altinstructions)
-  }
-  __smp_alt_instructions_end = .;
-  . = ALIGN(8);
   __smp_locks = .;
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
 	*(.smp_locks)
   }
   __smp_locks_end = .;
-  .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
-	*(.smp_altinstr_replacement)
-  }
   . = ALIGN(4096);
   __smp_alt_end = .;
 
@@ -189,6 +190,12 @@
   .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
   .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
 
+/* vdso blob that is mapped into user space */
+  vdso_start = . ;
+  .vdso  : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) }
+  . = ALIGN(4096);
+  vdso_end = .;
+
 #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(4096);
   __initramfs_start = .;
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 57660d5..06c3494 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -42,6 +42,7 @@
 #include <asm/segment.h>
 #include <asm/desc.h>
 #include <asm/topology.h>
+#include <asm/vgtod.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","rcx","memory"
@@ -57,26 +58,9 @@
  * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
  * Try to keep this structure as small as possible to avoid cache line ping pongs
  */
-struct vsyscall_gtod_data_t {
-	seqlock_t	lock;
-
-	/* open coded 'struct timespec' */
-	time_t		wall_time_sec;
-	u32		wall_time_nsec;
-
-	int		sysctl_enabled;
-	struct timezone sys_tz;
-	struct { /* extract of a clocksource struct */
-		cycle_t (*vread)(void);
-		cycle_t	cycle_last;
-		cycle_t	mask;
-		u32	mult;
-		u32	shift;
-	} clock;
-};
 int __vgetcpu_mode __section_vgetcpu_mode;
 
-struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
+struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
 {
 	.lock = SEQLOCK_UNLOCKED,
 	.sysctl_enabled = 1,
@@ -96,6 +80,8 @@
 	vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
 	vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
 	vsyscall_gtod_data.sys_tz = sys_tz;
+	vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
+	vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
 	write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
 }
 
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 84f1172..327c9f2 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -159,7 +159,7 @@
 	pmd_t *pmd;
 	pte_t *pte;
 
-	asm("movq %%cr3,%0" : "=r" (pgd));
+	pgd = (pgd_t *)read_cr3();
 
 	pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); 
 	pgd += pgd_index(address);
@@ -221,16 +221,6 @@
 	return 0;
 } 
 
-int unhandled_signal(struct task_struct *tsk, int sig)
-{
-	if (is_init(tsk))
-		return 1;
-	if (tsk->ptrace & PT_PTRACED)
-		return 0;
-	return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
-		(tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
-}
-
 static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
 				 unsigned long error_code)
 {
@@ -301,8 +291,8 @@
 	return 0;
 }
 
-int page_fault_trace = 0;
-int exception_trace = 1;
+static int page_fault_trace;
+int show_unhandled_signals = 1;
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -326,7 +316,7 @@
 	prefetchw(&mm->mmap_sem);
 
 	/* get the address */
-	__asm__("movq %%cr2,%0":"=r" (address));
+	address = read_cr2();
 
 	info.si_code = SEGV_MAPERR;
 
@@ -494,7 +484,8 @@
 		    (address >> 32))
 			return;
 
-		if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
+		if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+		    printk_ratelimit()) {
 			printk(
 		       "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
 					tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
@@ -568,7 +559,7 @@
 	}
 	printk("VM: killing process %s\n", tsk->comm);
 	if (error_code & 4)
-		do_exit(SIGKILL);
+		do_group_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 9a0e98a..38f5d63 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -383,7 +383,7 @@
 	} 
 
 	if (!after_bootmem)
-		asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+		mmu_cr4_features = read_cr4();
 	__flush_tlb_all();
 }
 
@@ -600,16 +600,6 @@
 {
 	unsigned long start = (unsigned long)_stext, end;
 
-#ifdef CONFIG_HOTPLUG_CPU
-	/* It must still be possible to apply SMP alternatives. */
-	if (num_possible_cpus() > 1)
-		start = (unsigned long)_etext;
-#endif
-
-#ifdef CONFIG_KPROBES
-	start = (unsigned long)__start_rodata;
-#endif
-	
 	end = (unsigned long)__end_rodata;
 	start = (start + PAGE_SIZE - 1) & PAGE_MASK;
 	end &= PAGE_MASK;
@@ -697,41 +687,6 @@
 	return pfn_valid(pte_pfn(*pte));
 }
 
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-
-extern int exception_trace, page_fault_trace;
-
-static ctl_table debug_table2[] = {
-	{
-		.ctl_name	= 99,
-		.procname	= "exception-trace",
-		.data		= &exception_trace,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{}
-}; 
-
-static ctl_table debug_root_table2[] = { 
-	{
-		.ctl_name = CTL_DEBUG,
-		.procname = "debug",
-		.mode = 0555,
-		.child = debug_table2
-	},
-	{}
-}; 
-
-static __init int x8664_sysctl_init(void)
-{ 
-	register_sysctl_table(debug_root_table2);
-	return 0;
-}
-__initcall(x8664_sysctl_init);
-#endif
-
 /* A pseudo VMA to allow ptrace access for the vsyscall page.  This only
    covers the 64bit vsyscall page now. 32bit has a real VMA now and does
    not need special handling anymore. */
@@ -769,8 +724,17 @@
 	return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
 
-void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
+void * __init alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
 {
 	return __alloc_bootmem_core(pgdat->bdata, size,
 			SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0);
 }
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+		return "[vdso]";
+	if (vma == &gate_vma)
+		return "[vsyscall]";
+	return NULL;
+}
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index f983c75..a96006f 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -44,12 +44,12 @@
 { 
 	unsigned long prevbase;
 	struct bootnode nodes[8];
-	int nodeid, i, nb; 
+	int nodeid, i, j, nb;
 	unsigned char nodeids[8];
 	int found = 0;
 	u32 reg;
 	unsigned numnodes;
-	unsigned dualcore = 0;
+	unsigned num_cores;
 
 	if (!early_pci_allowed())
 		return -1;
@@ -60,6 +60,9 @@
 
 	printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); 
 
+	num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+	printk(KERN_INFO "CPU has %d num_cores\n", num_cores);
+
 	reg = read_pci_config(0, nb, 0, 0x60); 
 	numnodes = ((reg >> 4) & 0xF) + 1;
 	if (numnodes <= 1)
@@ -73,8 +76,6 @@
 		unsigned long base,limit; 
 		u32 nodeid;
 		
-		/* Undefined before E stepping, but hopefully 0 */
-		dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1;
 		base = read_pci_config(0, nb, 1, 0x40 + i*8);
 		limit = read_pci_config(0, nb, 1, 0x44 + i*8);
 
@@ -170,8 +171,8 @@
 	for (i = 0; i < 8; i++) {
 		if (nodes[i].start != nodes[i].end) { 
 			nodeid = nodeids[i];
-			apicid_to_node[nodeid << dualcore] = i;
-			apicid_to_node[(nodeid << dualcore) + dualcore] = i;
+			for (j = 0; j < num_cores; j++)
+				apicid_to_node[(nodeid * num_cores) + j] = i;
 			setup_node_bootmem(i, nodes[i].start, nodes[i].end); 
 		} 
 	}
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 5154894..6da2355 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -273,9 +273,6 @@
 
 #ifdef CONFIG_NUMA_EMU
 /* Numa emulation */
-#define E820_ADDR_HOLE_SIZE(start, end)					\
-	(e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) <<	\
-	PAGE_SHIFT)
 char *cmdline __initdata;
 
 /*
@@ -319,7 +316,7 @@
 		return -1;
 	if (num_nodes > MAX_NUMNODES)
 		num_nodes = MAX_NUMNODES;
-	size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) /
+	size = (max_addr - *addr - e820_hole_size(*addr, max_addr)) /
 	       num_nodes;
 	/*
 	 * Calculate the number of big nodes that can be allocated as a result
@@ -347,7 +344,7 @@
 		if (i == num_nodes + node_start - 1)
 			end = max_addr;
 		else
-			while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) <
+			while (end - *addr - e820_hole_size(*addr, end) <
 			       size) {
 				end += FAKE_NODE_MIN_SIZE;
 				if (end > max_addr) {
@@ -476,18 +473,22 @@
 
 	/*
 	 * We need to vacate all active ranges that may have been registered by
-	 * SRAT.
+	 * SRAT and set acpi_numa to -1 so that srat_disabled() always returns
+	 * true.  NUMA emulation has succeeded so we will not scan ACPI nodes.
 	 */
 	remove_all_active_ranges();
+#ifdef CONFIG_ACPI_NUMA
+	acpi_numa = -1;
+#endif
 	for_each_node_mask(i, node_possible_map) {
 		e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
 						nodes[i].end >> PAGE_SHIFT);
  		setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 	}
+	acpi_fake_nodes(nodes, num_nodes);
  	numa_init_array();
  	return 0;
 }
-#undef E820_ADDR_HOLE_SIZE
 #endif /* CONFIG_NUMA_EMU */
 
 void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
index 9148f4a..7e161c6 100644
--- a/arch/x86_64/mm/pageattr.c
+++ b/arch/x86_64/mm/pageattr.c
@@ -13,7 +13,7 @@
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 
-static inline pte_t *lookup_address(unsigned long address) 
+pte_t *lookup_address(unsigned long address)
 { 
 	pgd_t *pgd = pgd_offset_k(address);
 	pud_t *pud;
@@ -74,14 +74,12 @@
 	struct page *pg;
 
 	/* When clflush is available always use it because it is
-	   much cheaper than WBINVD. Disable clflush for now because
-	   the high level code is not ready yet */
-	if (1 || !cpu_has_clflush)
+	   much cheaper than WBINVD. */
+	if (!cpu_has_clflush)
 		asm volatile("wbinvd" ::: "memory");
 	else list_for_each_entry(pg, l, lru) {
 		void *adr = page_address(pg);
-		if (cpu_has_clflush)
-			cache_flush_page(adr);
+		cache_flush_page(adr);
 	}
 	__flush_tlb_all();
 }
@@ -95,7 +93,8 @@
 
 static inline void save_page(struct page *fpage)
 {
-	list_add(&fpage->lru, &deferred_pages);
+	if (!test_and_set_bit(PG_arch_1, &fpage->flags))
+		list_add(&fpage->lru, &deferred_pages);
 }
 
 /* 
@@ -129,9 +128,12 @@
 	pte_t *kpte; 
 	struct page *kpte_page;
 	pgprot_t ref_prot2;
+
 	kpte = lookup_address(address);
 	if (!kpte) return 0;
 	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+	BUG_ON(PageLRU(kpte_page));
+	BUG_ON(PageCompound(kpte_page));
 	if (pgprot_val(prot) != pgprot_val(ref_prot)) { 
 		if (!pte_huge(*kpte)) {
 			set_pte(kpte, pfn_pte(pfn, prot));
@@ -159,10 +161,9 @@
 	/* on x86-64 the direct mapping set at boot is not using 4k pages */
  	BUG_ON(PageReserved(kpte_page));
 
-	if (page_private(kpte_page) == 0) {
-		save_page(kpte_page);
+	save_page(kpte_page);
+	if (page_private(kpte_page) == 0)
 		revert_page(address, ref_prot);
- 	}
 	return 0;
 } 
 
@@ -234,6 +235,10 @@
 	flush_map(&l);
 
 	list_for_each_entry_safe(pg, next, &l, lru) {
+		list_del(&pg->lru);
+		clear_bit(PG_arch_1, &pg->flags);
+		if (page_private(pg) != 0)
+			continue;
 		ClearPagePrivate(pg);
 		__free_page(pg);
 	} 
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 1e76bb0..acdf03e1 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -106,9 +106,9 @@
 		for (j = 0; j < d; j++)  {
 			u8 val = slit->entry[d*i + j];
 			if (i == j) {
-				if (val != 10)
+				if (val != LOCAL_DISTANCE)
 					return 0;
-			} else if (val <= 10)
+			} else if (val <= LOCAL_DISTANCE)
 				return 0;
 		}
 	}
@@ -350,7 +350,7 @@
 
 /* Sanity check to catch more bad SRATs (they are amazingly common).
    Make sure the PXMs cover all memory. */
-static int nodes_cover_memory(void)
+static int __init nodes_cover_memory(const struct bootnode *nodes)
 {
 	int i;
 	unsigned long pxmram, e820ram;
@@ -394,6 +394,9 @@
 {
 	int i;
 
+	if (acpi_numa <= 0)
+		return -1;
+
 	/* First clean up the node list */
 	for (i = 0; i < MAX_NUMNODES; i++) {
 		cutoff_node(i, start, end);
@@ -403,10 +406,7 @@
 		}
 	}
 
-	if (acpi_numa <= 0)
-		return -1;
-
-	if (!nodes_cover_memory()) {
+	if (!nodes_cover_memory(nodes)) {
 		bad_srat();
 		return -1;
 	}
@@ -440,6 +440,86 @@
 	return 0;
 }
 
+#ifdef CONFIG_NUMA_EMU
+static int __init find_node_by_addr(unsigned long addr)
+{
+	int ret = NUMA_NO_NODE;
+	int i;
+
+	for_each_node_mask(i, nodes_parsed) {
+		/*
+		 * Find the real node that this emulated node appears on.  For
+		 * the sake of simplicity, we only use a real node's starting
+		 * address to determine which emulated node it appears on.
+		 */
+		if (addr >= nodes[i].start && addr < nodes[i].end) {
+			ret = i;
+			break;
+		}
+	}
+	return i;
+}
+
+/*
+ * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
+ * mappings that respect the real ACPI topology but reflect our emulated
+ * environment.  For each emulated node, we find which real node it appears on
+ * and create PXM to NID mappings for those fake nodes which mirror that
+ * locality.  SLIT will now represent the correct distances between emulated
+ * nodes as a result of the real topology.
+ */
+void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
+{
+	int i, j;
+	int fake_node_to_pxm_map[MAX_NUMNODES] = {
+		[0 ... MAX_NUMNODES-1] = PXM_INVAL
+	};
+	unsigned char fake_apicid_to_node[MAX_LOCAL_APIC] = {
+		[0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+	};
+
+	printk(KERN_INFO "Faking PXM affinity for fake nodes on real "
+			 "topology.\n");
+	for (i = 0; i < num_nodes; i++) {
+		int nid, pxm;
+
+		nid = find_node_by_addr(fake_nodes[i].start);
+		if (nid == NUMA_NO_NODE)
+			continue;
+		pxm = node_to_pxm(nid);
+		if (pxm == PXM_INVAL)
+			continue;
+		fake_node_to_pxm_map[i] = pxm;
+		/*
+		 * For each apicid_to_node mapping that exists for this real
+		 * node, it must now point to the fake node ID.
+		 */
+		for (j = 0; j < MAX_LOCAL_APIC; j++)
+			if (apicid_to_node[j] == nid)
+				fake_apicid_to_node[j] = i;
+	}
+	for (i = 0; i < num_nodes; i++)
+		__acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
+	memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
+
+	nodes_clear(nodes_parsed);
+	for (i = 0; i < num_nodes; i++)
+		if (fake_nodes[i].start != fake_nodes[i].end)
+			node_set(i, nodes_parsed);
+	WARN_ON(!nodes_cover_memory(fake_nodes));
+}
+
+static int null_slit_node_compare(int a, int b)
+{
+	return node_to_pxm(a) == node_to_pxm(b);
+}
+#else
+static int null_slit_node_compare(int a, int b)
+{
+	return a == b;
+}
+#endif /* CONFIG_NUMA_EMU */
+
 void __init srat_reserve_add_area(int nodeid)
 {
 	if (found_add_area && nodes_add[nodeid].end) {
@@ -464,7 +544,8 @@
 	int index;
 
 	if (!acpi_slit)
-		return a == b ? 10 : 20;
+		return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
+						      REMOTE_DISTANCE;
 	index = acpi_slit->locality_count * node_to_pxm(a);
 	return acpi_slit->entry[index + node_to_pxm(b)];
 }
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index 3acf60d..9cc813e 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -59,6 +59,8 @@
 				     j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
 				     j++) { 
 					struct pci_bus *bus;
+					struct pci_sysdata *sd;
+
 					long node = NODE_ID(nid);
 					/* Algorithm a bit dumb, but
  					   it shouldn't matter here */
@@ -67,7 +69,9 @@
 						continue;
 					if (!node_online(node))
 						node = 0;
-					bus->sysdata = (void *)node;
+
+					sd = bus->sysdata;
+					sd->node = node;
 				}		
 			}
 		}
diff --git a/arch/x86_64/vdso/Makefile b/arch/x86_64/vdso/Makefile
new file mode 100644
index 0000000..faaa72f
--- /dev/null
+++ b/arch/x86_64/vdso/Makefile
@@ -0,0 +1,49 @@
+#
+# x86-64 vDSO.
+#
+
+# files to link into the vdso
+# vdso-start.o has to be first
+vobjs-y := vdso-start.o vdso-note.o vclock_gettime.o vgetcpu.o vvar.o
+
+# files to link into kernel
+obj-y := vma.o vdso.o vdso-syms.o
+
+vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
+
+$(obj)/vdso.o: $(obj)/vdso.so
+
+targets += vdso.so vdso.lds $(vobjs-y) vdso-syms.o
+
+# The DSO images are built using a special linker script.
+quiet_cmd_syscall = SYSCALL $@
+      cmd_syscall = $(CC) -m elf_x86_64 -nostdlib $(SYSCFLAGS_$(@F)) \
+		          -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+export CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+vdso-flags = -fPIC -shared -Wl,-soname=linux-vdso.so.1 \
+		 $(call ld-option, -Wl$(comma)--hash-style=sysv) \
+		-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+SYSCFLAGS_vdso.so = $(vdso-flags)
+
+$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
+
+$(obj)/vdso.so: $(src)/vdso.lds $(vobjs) FORCE
+	$(call if_changed,syscall)
+
+CF := $(PROFILING) -mcmodel=small -fPIC -g0 -O2 -fasynchronous-unwind-tables -m64
+
+$(obj)/vclock_gettime.o: CFLAGS = $(CF)
+$(obj)/vgetcpu.o: CFLAGS = $(CF)
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO.  With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vdso-syms.o
+$(obj)/built-in.o: $(obj)/vdso-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o
+
+SYSCFLAGS_vdso-syms.o = -r -d
+$(obj)/vdso-syms.o: $(src)/vdso.lds $(vobjs) FORCE
+	$(call if_changed,syscall)
diff --git a/arch/x86_64/vdso/vclock_gettime.c b/arch/x86_64/vdso/vclock_gettime.c
new file mode 100644
index 0000000..17f6a00
--- /dev/null
+++ b/arch/x86_64/vdso/vclock_gettime.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of clock_gettime and gettimeofday.
+ *
+ * The code should have no internal unresolved relocations.
+ * Check with readelf after changing.
+ * Also alternative() doesn't work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/posix-timers.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/timex.h>
+#include <asm/hpet.h>
+#include <asm/unistd.h>
+#include <asm/io.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+#define gtod vdso_vsyscall_gtod_data
+
+static long vdso_fallback_gettime(long clock, struct timespec *ts)
+{
+	long ret;
+	asm("syscall" : "=a" (ret) :
+	    "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
+	return ret;
+}
+
+static inline long vgetns(void)
+{
+	cycles_t (*vread)(void);
+	vread = gtod->clock.vread;
+	return ((vread() - gtod->clock.cycle_last) * gtod->clock.mult) >>
+		gtod->clock.shift;
+}
+
+static noinline int do_realtime(struct timespec *ts)
+{
+	unsigned long seq, ns;
+	do {
+		seq = read_seqbegin(&gtod->lock);
+		ts->tv_sec = gtod->wall_time_sec;
+		ts->tv_nsec = gtod->wall_time_nsec;
+		ns = vgetns();
+	} while (unlikely(read_seqretry(&gtod->lock, seq)));
+	timespec_add_ns(ts, ns);
+	return 0;
+}
+
+/* Copy of the version in kernel/time.c which we cannot directly access */
+static void vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
+{
+	while (nsec >= NSEC_PER_SEC) {
+		nsec -= NSEC_PER_SEC;
+		++sec;
+	}
+	while (nsec < 0) {
+		nsec += NSEC_PER_SEC;
+		--sec;
+	}
+	ts->tv_sec = sec;
+	ts->tv_nsec = nsec;
+}
+
+static noinline int do_monotonic(struct timespec *ts)
+{
+	unsigned long seq, ns, secs;
+	do {
+		seq = read_seqbegin(&gtod->lock);
+		secs = gtod->wall_time_sec;
+		ns = gtod->wall_time_nsec + vgetns();
+		secs += gtod->wall_to_monotonic.tv_sec;
+		ns += gtod->wall_to_monotonic.tv_nsec;
+	} while (unlikely(read_seqretry(&gtod->lock, seq)));
+	vset_normalized_timespec(ts, secs, ns);
+	return 0;
+}
+
+int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
+{
+	if (likely(gtod->sysctl_enabled && gtod->clock.vread))
+		switch (clock) {
+		case CLOCK_REALTIME:
+			return do_realtime(ts);
+		case CLOCK_MONOTONIC:
+			return do_monotonic(ts);
+		}
+	return vdso_fallback_gettime(clock, ts);
+}
+int clock_gettime(clockid_t, struct timespec *)
+	__attribute__((weak, alias("__vdso_clock_gettime")));
+
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	long ret;
+	if (likely(gtod->sysctl_enabled && gtod->clock.vread)) {
+		BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
+			     offsetof(struct timespec, tv_nsec) ||
+			     sizeof(*tv) != sizeof(struct timespec));
+		do_realtime((struct timespec *)tv);
+		tv->tv_usec /= 1000;
+		if (unlikely(tz != NULL)) {
+			/* This relies on gcc inlining the memcpy. We'll notice
+			   if it ever fails to do so. */
+			memcpy(tz, &gtod->sys_tz, sizeof(struct timezone));
+		}
+		return 0;
+	}
+	asm("syscall" : "=a" (ret) :
+	    "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+	return ret;
+}
+int gettimeofday(struct timeval *, struct timezone *)
+	__attribute__((weak, alias("__vdso_gettimeofday")));
diff --git a/arch/x86_64/vdso/vdso-note.S b/arch/x86_64/vdso/vdso-note.S
new file mode 100644
index 0000000..79a071e
--- /dev/null
+++ b/arch/x86_64/vdso/vdso-note.S
@@ -0,0 +1,12 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+	.long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/x86_64/vdso/vdso-start.S b/arch/x86_64/vdso/vdso-start.S
new file mode 100644
index 0000000..2dc2cdb
--- /dev/null
+++ b/arch/x86_64/vdso/vdso-start.S
@@ -0,0 +1,2 @@
+	.globl vdso_kernel_start
+vdso_kernel_start:
diff --git a/arch/x86_64/vdso/vdso.S b/arch/x86_64/vdso/vdso.S
new file mode 100644
index 0000000..92e80c1
--- /dev/null
+++ b/arch/x86_64/vdso/vdso.S
@@ -0,0 +1,2 @@
+	.section ".vdso","a"
+	.incbin "arch/x86_64/vdso/vdso.so"
diff --git a/arch/x86_64/vdso/vdso.lds.S b/arch/x86_64/vdso/vdso.lds.S
new file mode 100644
index 0000000..b9a60e6
--- /dev/null
+++ b/arch/x86_64/vdso/vdso.lds.S
@@ -0,0 +1,77 @@
+/*
+ * Linker script for vsyscall DSO.  The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page).  This script controls its layout.
+ */
+#include <asm/asm-offsets.h>
+#include "voffset.h"
+
+#define VDSO_PRELINK 0xffffffffff700000
+
+SECTIONS
+{
+  . = VDSO_PRELINK + SIZEOF_HEADERS;
+
+  .hash           : { *(.hash) }		:text
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+
+  /* This linker script is used both with -r and with -shared.
+     For the layouts to match, we need to skip more than enough
+     space for the dynamic symbol table et al.  If this amount
+     is insufficient, ld -shared will barf.  Just increase it here.  */
+  . = VDSO_PRELINK + VDSO_TEXT_OFFSET;
+
+  .text           : { *(.text) }		:text
+  .text.ptr       : { *(.text.ptr) }		:text
+  . = VDSO_PRELINK + 0x900;
+  .data           : { *(.data) }		:text
+  .bss            : { *(.bss) }			:text
+
+  .altinstructions : { *(.altinstructions) }			:text
+  .altinstr_replacement  : { *(.altinstr_replacement) }	:text
+
+  .note		  : { *(.note.*) }		:text :note
+  .eh_frame_hdr   : { *(.eh_frame_hdr) }	:text :eh_frame_hdr
+  .eh_frame       : { KEEP (*(.eh_frame)) }	:text
+  .dynamic        : { *(.dynamic) }		:text :dynamic
+  .useless        : {
+  	*(.got.plt) *(.got)
+	*(.gnu.linkonce.d.*)
+	*(.dynbss)
+	*(.gnu.linkonce.b.*)
+  }						:text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+  dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  note PT_NOTE FLAGS(4); /* PF_R */
+  eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+  LINUX_2.6 {
+    global:
+	clock_gettime;
+	__vdso_clock_gettime;
+	gettimeofday;
+	__vdso_gettimeofday;
+	getcpu;
+	__vdso_getcpu;
+    local: *;
+  };
+}
diff --git a/arch/x86_64/vdso/vextern.h b/arch/x86_64/vdso/vextern.h
new file mode 100644
index 0000000..1683ba2
--- /dev/null
+++ b/arch/x86_64/vdso/vextern.h
@@ -0,0 +1,16 @@
+#ifndef VEXTERN
+#include <asm/vsyscall.h>
+#define VEXTERN(x) \
+	extern typeof(x) *vdso_ ## x __attribute__((visibility("hidden")));
+#endif
+
+#define VMAGIC 0xfeedbabeabcdefabUL
+
+/* Any kernel variables used in the vDSO must be exported in the main
+   kernel's vmlinux.lds.S/vsyscall.h/proper __section and
+   put into vextern.h and be referenced as a pointer with vdso prefix.
+   The main kernel later fills in the values.   */
+
+VEXTERN(jiffies)
+VEXTERN(vgetcpu_mode)
+VEXTERN(vsyscall_gtod_data)
diff --git a/arch/x86_64/vdso/vgetcpu.c b/arch/x86_64/vdso/vgetcpu.c
new file mode 100644
index 0000000..91f6e85
--- /dev/null
+++ b/arch/x86_64/vdso/vgetcpu.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of getcpu()
+ */
+
+#include <linux/kernel.h>
+#include <linux/getcpu.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+{
+	unsigned int dummy, p;
+	unsigned long j = 0;
+
+	/* Fast cache - only recompute value once per jiffies and avoid
+	   relatively costly rdtscp/cpuid otherwise.
+	   This works because the scheduler usually keeps the process
+	   on the same CPU and this syscall doesn't guarantee its
+	   results anyways.
+	   We do this here because otherwise user space would do it on
+	   its own in a likely inferior way (no access to jiffies).
+	   If you don't like it pass NULL. */
+	if (tcache && tcache->blob[0] == (j = *vdso_jiffies)) {
+		p = tcache->blob[1];
+	} else if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
+		/* Load per CPU data from RDTSCP */
+		rdtscp(dummy, dummy, p);
+	} else {
+		/* Load per CPU data from GDT */
+		asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+	}
+	if (tcache) {
+		tcache->blob[0] = j;
+		tcache->blob[1] = p;
+	}
+	if (cpu)
+		*cpu = p & 0xfff;
+	if (node)
+		*node = p >> 12;
+	return 0;
+}
+
+long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+	__attribute__((weak, alias("__vdso_getcpu")));
diff --git a/arch/x86_64/vdso/vma.c b/arch/x86_64/vdso/vma.c
new file mode 100644
index 0000000..d4cb83a
--- /dev/null
+++ b/arch/x86_64/vdso/vma.c
@@ -0,0 +1,139 @@
+/*
+ * Set up the VMAs to tell the VM about the vDSO.
+ * Copyright 2007 Andi Kleen, SUSE Labs.
+ * Subject to the GPL, v.2
+ */
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/proto.h>
+#include "voffset.h"
+
+int vdso_enabled = 1;
+
+#define VEXTERN(x) extern typeof(__ ## x) *vdso_ ## x;
+#include "vextern.h"
+#undef VEXTERN
+
+extern char vdso_kernel_start[], vdso_start[], vdso_end[];
+extern unsigned short vdso_sync_cpuid;
+
+struct page **vdso_pages;
+
+static inline void *var_ref(void *vbase, char *var, char *name)
+{
+	unsigned offset = var - &vdso_kernel_start[0] + VDSO_TEXT_OFFSET;
+	void *p = vbase + offset;
+	if (*(void **)p != (void *)VMAGIC) {
+		printk("VDSO: variable %s broken\n", name);
+		vdso_enabled = 0;
+	}
+	return p;
+}
+
+static int __init init_vdso_vars(void)
+{
+	int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
+	int i;
+	char *vbase;
+
+	vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
+	if (!vdso_pages)
+		goto oom;
+	for (i = 0; i < npages; i++) {
+		struct page *p;
+		p = alloc_page(GFP_KERNEL);
+		if (!p)
+			goto oom;
+		vdso_pages[i] = p;
+		copy_page(page_address(p), vdso_start + i*PAGE_SIZE);
+	}
+
+	vbase = vmap(vdso_pages, npages, 0, PAGE_KERNEL);
+	if (!vbase)
+		goto oom;
+
+	if (memcmp(vbase, "\177ELF", 4)) {
+		printk("VDSO: I'm broken; not ELF\n");
+		vdso_enabled = 0;
+	}
+
+#define V(x) *(typeof(x) *) var_ref(vbase, (char *)RELOC_HIDE(&x, 0), #x)
+#define VEXTERN(x) \
+	V(vdso_ ## x) = &__ ## x;
+#include "vextern.h"
+#undef VEXTERN
+	return 0;
+
+ oom:
+	printk("Cannot allocate vdso\n");
+	vdso_enabled = 0;
+	return -ENOMEM;
+}
+__initcall(init_vdso_vars);
+
+struct linux_binprm;
+
+/* Put the vdso above the (randomized) stack with another randomized offset.
+   This way there is no hole in the middle of address space.
+   To save memory make sure it is still in the same PTE as the stack top.
+   This doesn't give that many random bits */
+static unsigned long vdso_addr(unsigned long start, unsigned len)
+{
+	unsigned long addr, end;
+	unsigned offset;
+	end = (start + PMD_SIZE - 1) & PMD_MASK;
+	if (end >= TASK_SIZE64)
+		end = TASK_SIZE64;
+	end -= len;
+	/* This loses some more bits than a modulo, but is cheaper */
+	offset = get_random_int() & (PTRS_PER_PTE - 1);
+	addr = start + (offset << PAGE_SHIFT);
+	if (addr >= end)
+		addr = end;
+	return addr;
+}
+
+/* Setup a VMA at program startup for the vsyscall page.
+   Not called for compat tasks */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr;
+	int ret;
+	unsigned len = round_up(vdso_end - vdso_start, PAGE_SIZE);
+
+	if (!vdso_enabled)
+		return 0;
+
+	down_write(&mm->mmap_sem);
+	addr = vdso_addr(mm->start_stack, len);
+	addr = get_unmapped_area(NULL, addr, len, 0, 0);
+	if (IS_ERR_VALUE(addr)) {
+		ret = addr;
+		goto up_fail;
+	}
+
+	ret = install_special_mapping(mm, addr, len,
+				      VM_READ|VM_EXEC|
+				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+				      VM_ALWAYSDUMP,
+				      vdso_pages);
+	if (ret)
+		goto up_fail;
+
+	current->mm->context.vdso = (void *)addr;
+up_fail:
+	up_write(&mm->mmap_sem);
+	return ret;
+}
+
+static __init int vdso_setup(char *s)
+{
+	vdso_enabled = simple_strtoul(s, NULL, 0);
+	return 0;
+}
+__setup("vdso=", vdso_setup);
diff --git a/arch/x86_64/vdso/voffset.h b/arch/x86_64/vdso/voffset.h
new file mode 100644
index 0000000..5304204
--- /dev/null
+++ b/arch/x86_64/vdso/voffset.h
@@ -0,0 +1 @@
+#define VDSO_TEXT_OFFSET 0x500
diff --git a/arch/x86_64/vdso/vvar.c b/arch/x86_64/vdso/vvar.c
new file mode 100644
index 0000000..6fc2221
--- /dev/null
+++ b/arch/x86_64/vdso/vvar.c
@@ -0,0 +1,12 @@
+/* Define pointer to external vDSO variables.
+   These are part of the vDSO. The kernel fills in the real addresses
+   at boot time. This is done because when the vdso is linked the
+   kernel isn't yet and we don't know the final addresses. */
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/timex.h>
+#include <asm/vgtod.h>
+
+#define VEXTERN(x) typeof (__ ## x) *vdso_ ## x = (void *)VMAGIC;
+#include "vextern.h"
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 9755a3c..d148ccb 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -92,7 +92,11 @@
 	struct cfq_queue *active_queue;
 	struct cfq_io_context *active_cic;
 
-	struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
+	/*
+	 * async queue for each priority case
+	 */
+	struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
+	struct cfq_queue *async_idle_cfqq;
 
 	struct timer_list idle_class_timer;
 
@@ -111,9 +115,6 @@
 	unsigned int cfq_slice_idle;
 
 	struct list_head cic_list;
-
-	sector_t new_seek_mean;
-	u64 new_seek_total;
 };
 
 /*
@@ -153,8 +154,6 @@
 
 	/* various state flags, see below */
 	unsigned int flags;
-
-	sector_t last_request_pos;
 };
 
 enum cfqq_state_flags {
@@ -1414,24 +1413,44 @@
 	return cfqq;
 }
 
+static struct cfq_queue **
+cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+{
+	switch(ioprio_class) {
+	case IOPRIO_CLASS_RT:
+		return &cfqd->async_cfqq[0][ioprio];
+	case IOPRIO_CLASS_BE:
+		return &cfqd->async_cfqq[1][ioprio];
+	case IOPRIO_CLASS_IDLE:
+		return &cfqd->async_idle_cfqq;
+	default:
+		BUG();
+	}
+}
+
 static struct cfq_queue *
 cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
 	      gfp_t gfp_mask)
 {
 	const int ioprio = task_ioprio(tsk);
+	const int ioprio_class = task_ioprio_class(tsk);
+	struct cfq_queue **async_cfqq = NULL;
 	struct cfq_queue *cfqq = NULL;
 
-	if (!is_sync)
-		cfqq = cfqd->async_cfqq[ioprio];
+	if (!is_sync) {
+		async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
+		cfqq = *async_cfqq;
+	}
+
 	if (!cfqq)
 		cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
 
 	/*
 	 * pin the queue now that it's allocated, scheduler exit will prune it
 	 */
-	if (!is_sync && !cfqd->async_cfqq[ioprio]) {
+	if (!is_sync && !(*async_cfqq)) {
 		atomic_inc(&cfqq->ref);
-		cfqd->async_cfqq[ioprio] = cfqq;
+		*async_cfqq = cfqq;
 	}
 
 	atomic_inc(&cfqq->ref);
@@ -1597,11 +1616,6 @@
 	else
 		sdist = cic->last_request_pos - rq->sector;
 
-	if (!cic->seek_samples) {
-		cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
-		cfqd->new_seek_mean = cfqd->new_seek_total / 256;
-	}
-
 	/*
 	 * Don't allow the seek distance to get too large from the
 	 * odd fragment, pagein, etc
@@ -1737,7 +1751,6 @@
 	cfq_update_idle_window(cfqd, cfqq, cic);
 
 	cic->last_request_pos = rq->sector + rq->nr_sectors;
-	cfqq->last_request_pos = cic->last_request_pos;
 
 	if (cfqq == cfqd->active_queue) {
 		/*
@@ -2042,11 +2055,24 @@
 	blk_sync_queue(cfqd->queue);
 }
 
+static void cfq_put_async_queues(struct cfq_data *cfqd)
+{
+	int i;
+
+	for (i = 0; i < IOPRIO_BE_NR; i++) {
+		if (cfqd->async_cfqq[0][i])
+			cfq_put_queue(cfqd->async_cfqq[0][i]);
+		if (cfqd->async_cfqq[1][i])
+			cfq_put_queue(cfqd->async_cfqq[1][i]);
+		if (cfqd->async_idle_cfqq)
+			cfq_put_queue(cfqd->async_idle_cfqq);
+	}
+}
+
 static void cfq_exit_queue(elevator_t *e)
 {
 	struct cfq_data *cfqd = e->elevator_data;
 	request_queue_t *q = cfqd->queue;
-	int i;
 
 	cfq_shutdown_timer_wq(cfqd);
 
@@ -2063,12 +2089,7 @@
 		__cfq_exit_single_io_context(cfqd, cic);
 	}
 
-	/*
-	 * Put the async queues
-	 */
-	for (i = 0; i < IOPRIO_BE_NR; i++)
-		if (cfqd->async_cfqq[i])	
-			cfq_put_queue(cfqd->async_cfqq[i]);
+	cfq_put_async_queues(cfqd);
 
 	spin_unlock_irq(q->queue_lock);
 
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
index a973f4e..047e533 100644
--- a/crypto/async_tx/async_memcpy.c
+++ b/crypto/async_tx/async_memcpy.c
@@ -36,7 +36,6 @@
  * @offset: offset in pages to start transaction
  * @len: length in bytes
  * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
- *	ASYNC_TX_KMAP_SRC, ASYNC_TX_KMAP_DST
  * @depend_tx: memcpy depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -88,23 +87,13 @@
 					__FUNCTION__);
 		}
 
-		if (flags & ASYNC_TX_KMAP_DST)
-			dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
-		else
-			dest_buf = page_address(dest) + dest_offset;
-
-		if (flags & ASYNC_TX_KMAP_SRC)
-			src_buf = kmap_atomic(src, KM_USER0) + src_offset;
-		else
-			src_buf = page_address(src) + src_offset;
+		dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
+		src_buf = kmap_atomic(src, KM_USER1) + src_offset;
 
 		memcpy(dest_buf, src_buf, len);
 
-		if (flags & ASYNC_TX_KMAP_DST)
-			kunmap_atomic(dest_buf, KM_USER0);
-
-		if (flags & ASYNC_TX_KMAP_SRC)
-			kunmap_atomic(src_buf, KM_USER0);
+		kunmap_atomic(dest_buf, KM_USER0);
+		kunmap_atomic(src_buf, KM_USER1);
 
 		async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
 	}
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 707650a..3e1c442 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -8,6 +8,8 @@
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/of/Kconfig"
+
 source "drivers/parport/Kconfig"
 
 source "drivers/pnp/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 0ea8e32..a9e4c5f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -86,3 +86,4 @@
 obj-$(CONFIG_DMA_ENGINE)	+= dma/
 obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_OF)		+= of/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 139f41f..408b451 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -2,16 +2,12 @@
 # ACPI Configuration
 #
 
-menu "ACPI (Advanced Configuration and Power Interface) Support"
+menuconfig ACPI
+	bool "ACPI Support (Advanced Configuration and Power Interface) Support"
 	depends on !X86_NUMAQ
 	depends on !X86_VISWS
 	depends on !IA64_HP_SIM
 	depends on IA64 || X86
-	depends on PM
-
-config ACPI
-	bool "ACPI Support"
-	depends on IA64 || X86
 	depends on PCI
 	depends on PM
 	select PNP
@@ -49,7 +45,6 @@
 config ACPI_SLEEP
 	bool "Sleep States"
 	depends on X86 && (!SMP || SUSPEND_SMP)
-	depends on PM
 	default y
 	---help---
 	  This option adds support for ACPI suspend states. 
@@ -82,7 +77,6 @@
 
 config ACPI_PROCFS
 	bool "Procfs interface (deprecated)"
-	depends on ACPI
 	default y
 	---help---
 	  The Procfs interface for ACPI is made optional for backward compatibility.
@@ -124,7 +118,7 @@
 
 config ACPI_VIDEO
 	tristate "Video"
-	depends on X86 && BACKLIGHT_CLASS_DEVICE
+	depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
 	help
 	  This driver implement the ACPI Extensions For Display Adapters
 	  for integrated graphics devices on motherboard, as specified in
@@ -280,6 +274,14 @@
 	  of verbosity. Saying Y enables these statements. This will increase
 	  your kernel size by around 50K.
 
+config ACPI_DEBUG_FUNC_TRACE
+	bool "Additionally enable ACPI function tracing"
+	default n
+	depends on ACPI_DEBUG
+	help
+	  ACPI Debug Statements slow down ACPI processing. Function trace
+	  is about half of the penalty and is rarely useful.
+
 config ACPI_EC
 	bool
 	default y
@@ -330,7 +332,6 @@
 
 config ACPI_HOTPLUG_MEMORY
 	tristate "Memory Hotplug"
-	depends on ACPI
 	depends on MEMORY_HOTPLUG
 	default n
 	help
@@ -359,5 +360,3 @@
 	  to today's ACPI "Control Method" battery.
 
 endif	# ACPI
-
-endmenu
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e64c76c..cad932d 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -43,21 +43,30 @@
 #define ACPI_BATTERY_CLASS		"battery"
 #define ACPI_BATTERY_HID		"PNP0C0A"
 #define ACPI_BATTERY_DEVICE_NAME	"Battery"
-#define ACPI_BATTERY_FILE_INFO		"info"
-#define ACPI_BATTERY_FILE_STATUS	"state"
-#define ACPI_BATTERY_FILE_ALARM		"alarm"
 #define ACPI_BATTERY_NOTIFY_STATUS	0x80
 #define ACPI_BATTERY_NOTIFY_INFO	0x81
 #define ACPI_BATTERY_UNITS_WATTS	"mW"
 #define ACPI_BATTERY_UNITS_AMPS		"mA"
 
 #define _COMPONENT		ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME	0
+
+#define ACPI_BATTERY_NONE_UPDATE	0
+#define ACPI_BATTERY_EASY_UPDATE	1
+#define ACPI_BATTERY_INIT_UPDATE	2
+
 ACPI_MODULE_NAME("battery");
 
 MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Battery Driver");
 MODULE_LICENSE("GPL");
 
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
 extern struct proc_dir_entry *acpi_lock_battery_dir(void);
 extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
@@ -76,7 +85,7 @@
 		},
 };
 
-struct acpi_battery_status {
+struct acpi_battery_state {
 	acpi_integer state;
 	acpi_integer present_rate;
 	acpi_integer remaining_capacity;
@@ -99,33 +108,111 @@
 	acpi_string oem_info;
 };
 
-struct acpi_battery_flags {
-	u8 present:1;		/* Bay occupied? */
-	u8 power_unit:1;	/* 0=watts, 1=apms */
-	u8 alarm:1;		/* _BTP present? */
-	u8 reserved:5;
+enum acpi_battery_files{
+	ACPI_BATTERY_INFO = 0,
+	ACPI_BATTERY_STATE,
+	ACPI_BATTERY_ALARM,
+	ACPI_BATTERY_NUMFILES,
 };
 
-struct acpi_battery_trips {
-	unsigned long warning;
-	unsigned long low;
+struct acpi_battery_flags {
+	u8 battery_present_prev;
+	u8 alarm_present;
+	u8 init_update;
+	u8 update[ACPI_BATTERY_NUMFILES];
+	u8 power_unit;
 };
 
 struct acpi_battery {
-	struct acpi_device * device;
+	struct mutex mutex;
+	struct acpi_device *device;
 	struct acpi_battery_flags flags;
-	struct acpi_battery_trips trips;
+	struct acpi_buffer bif_data;
+	struct acpi_buffer bst_data;
 	unsigned long alarm;
-	struct acpi_battery_info *info;
+	unsigned long update_time[ACPI_BATTERY_NUMFILES];
 };
 
+inline int acpi_battery_present(struct acpi_battery *battery)
+{
+	return battery->device->status.battery_present;
+}
+inline char *acpi_battery_power_units(struct acpi_battery *battery)
+{
+	if (battery->flags.power_unit)
+		return ACPI_BATTERY_UNITS_AMPS;
+	else
+		return ACPI_BATTERY_UNITS_WATTS;
+}
+
+inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+{
+	return battery->device->handle;
+}
+
 /* --------------------------------------------------------------------------
                                Battery Management
    -------------------------------------------------------------------------- */
 
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
-		      struct acpi_battery_info **bif)
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+	if (!battery)
+		return;
+
+	if (result) {
+		battery->flags.init_update = 1;
+	}
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+					union acpi_object *package,
+					struct acpi_buffer *format,
+					struct acpi_buffer *data,
+					char *package_name)
+{
+	acpi_status status = AE_OK;
+	struct acpi_buffer data_null = { 0, NULL };
+
+	status = acpi_extract_package(package, format, &data_null);
+	if (status != AE_BUFFER_OVERFLOW) {
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+				package_name));
+		return -ENODEV;
+	}
+
+	if (data_null.length != data->length) {
+		kfree(data->pointer);
+		data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+		if (!data->pointer) {
+			ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+			return -ENOMEM;
+		}
+		data->length = data_null.length;
+	}
+
+	status = acpi_extract_package(package, format, data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+				package_name));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+	int result = 0;
+
+	result = acpi_bus_get_status(battery->device);
+	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+		return -ENODEV;
+	}
+	return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = 0;
@@ -133,16 +220,20 @@
 	struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
 		ACPI_BATTERY_FORMAT_BIF
 	};
-	struct acpi_buffer data = { 0, NULL };
 	union acpi_object *package = NULL;
+	struct acpi_buffer *data = NULL;
+	struct acpi_battery_info *bif = NULL;
 
+	battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
 
-	if (!battery || !bif)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return 0;
 
-	/* Evalute _BIF */
+	/* Evaluate _BIF */
 
-	status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+				 &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
 		return -ENODEV;
@@ -150,41 +241,29 @@
 
 	package = buffer.pointer;
 
+	data = &battery->bif_data;
+
 	/* Extract Package Data */
 
-	status = acpi_extract_package(package, &format, &data);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-		result = -ENODEV;
+	result =
+	    acpi_battery_extract_package(battery, package, &format, data,
+					 "_BIF");
+	if (result)
 		goto end;
-	}
-
-	data.pointer = kzalloc(data.length, GFP_KERNEL);
-	if (!data.pointer) {
-		result = -ENOMEM;
-		goto end;
-	}
-
-	status = acpi_extract_package(package, &format, &data);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-		kfree(data.pointer);
-		result = -ENODEV;
-		goto end;
-	}
 
       end:
+
 	kfree(buffer.pointer);
 
-	if (!result)
-		(*bif) = data.pointer;
+	if (!result) {
+		bif = data->pointer;
+		battery->flags.power_unit = bif->power_unit;
+	}
 
 	return result;
 }
 
-static int
-acpi_battery_get_status(struct acpi_battery *battery,
-			struct acpi_battery_status **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = 0;
@@ -192,16 +271,19 @@
 	struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
 		ACPI_BATTERY_FORMAT_BST
 	};
-	struct acpi_buffer data = { 0, NULL };
 	union acpi_object *package = NULL;
+	struct acpi_buffer *data = NULL;
 
+	battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
 
-	if (!battery || !bst)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return 0;
 
-	/* Evalute _BST */
+	/* Evaluate _BST */
 
-	status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+				 &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
 		return -ENODEV;
@@ -209,55 +291,49 @@
 
 	package = buffer.pointer;
 
+	data = &battery->bst_data;
+
 	/* Extract Package Data */
 
-	status = acpi_extract_package(package, &format, &data);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-		result = -ENODEV;
+	result =
+	    acpi_battery_extract_package(battery, package, &format, data,
+					 "_BST");
+	if (result)
 		goto end;
-	}
-
-	data.pointer = kzalloc(data.length, GFP_KERNEL);
-	if (!data.pointer) {
-		result = -ENOMEM;
-		goto end;
-	}
-
-	status = acpi_extract_package(package, &format, &data);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-		kfree(data.pointer);
-		result = -ENODEV;
-		goto end;
-	}
 
       end:
 	kfree(buffer.pointer);
 
-	if (!result)
-		(*bst) = data.pointer;
-
 	return result;
 }
 
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+	battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
+
+	return 0;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+				  unsigned long alarm)
 {
 	acpi_status status = 0;
 	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 	struct acpi_object_list arg_list = { 1, &arg0 };
 
+	battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
 
-	if (!battery)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return -ENODEV;
 
-	if (!battery->flags.alarm)
+	if (!battery->flags.alarm_present)
 		return -ENODEV;
 
 	arg0.integer.value = alarm;
 
-	status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+				 &arg_list, NULL);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
@@ -268,65 +344,114 @@
 	return 0;
 }
 
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = AE_OK;
 	acpi_handle handle = NULL;
-	struct acpi_device *device = NULL;
-	struct acpi_battery_info *bif = NULL;
+	struct acpi_battery_info *bif = battery->bif_data.pointer;
+	unsigned long alarm = battery->alarm;
 
+	/* See if alarms are supported, and if so, set default */
 
-	if (!battery)
-		return -EINVAL;
-
-	device = battery->device;
-
-	result = acpi_bus_get_status(device);
-	if (result)
-		return result;
-
-	/* Insertion? */
-
-	if (!battery->flags.present && device->status.battery_present) {
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
-
-		/* Evalute _BIF to get certain static information */
-
-		result = acpi_battery_get_info(battery, &bif);
-		if (result)
-			return result;
-
-		battery->flags.power_unit = bif->power_unit;
-		battery->trips.warning = bif->design_capacity_warning;
-		battery->trips.low = bif->design_capacity_low;
-		kfree(bif);
-
-		/* See if alarms are supported, and if so, set default */
-
-		status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
-		if (ACPI_SUCCESS(status)) {
-			battery->flags.alarm = 1;
-			acpi_battery_set_alarm(battery, battery->trips.warning);
+	status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+	if (ACPI_SUCCESS(status)) {
+		battery->flags.alarm_present = 1;
+		if (!alarm && bif) {
+			alarm = bif->design_capacity_warning;
 		}
+		result = acpi_battery_set_alarm(battery, alarm);
+		if (result)
+			goto end;
+	} else {
+		battery->flags.alarm_present = 0;
 	}
 
-	/* Removal? */
-
-	else if (battery->flags.present && !device->status.battery_present) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
-	}
-
-	battery->flags.present = device->status.battery_present;
+      end:
 
 	return result;
 }
 
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static int acpi_battery_init_update(struct acpi_battery *battery)
 {
-	if (!battery->flags.present) {
-		acpi_battery_check(battery);
+	int result = 0;
+
+	result = acpi_battery_get_status(battery);
+	if (result)
+		return result;
+
+	battery->flags.battery_present_prev = acpi_battery_present(battery);
+
+	if (acpi_battery_present(battery)) {
+		result = acpi_battery_get_info(battery);
+		if (result)
+			return result;
+		result = acpi_battery_get_state(battery);
+		if (result)
+			return result;
+
+		acpi_battery_init_alarm(battery);
+	}
+
+	return result;
+}
+
+static int acpi_battery_update(struct acpi_battery *battery,
+			       int update, int *update_result_ptr)
+{
+	int result = 0;
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
+
+	if (!acpi_battery_present(battery)) {
+		update = 1;
+	}
+
+	if (battery->flags.init_update) {
+		result = acpi_battery_init_update(battery);
+		if (result)
+			goto end;
+		update_result = ACPI_BATTERY_INIT_UPDATE;
+	} else if (update) {
+		result = acpi_battery_get_status(battery);
+		if (result)
+			goto end;
+		if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
+		    || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
+			result = acpi_battery_init_update(battery);
+			if (result)
+				goto end;
+			update_result = ACPI_BATTERY_INIT_UPDATE;
+		} else {
+			update_result = ACPI_BATTERY_EASY_UPDATE;
+		}
+	}
+
+      end:
+
+	battery->flags.init_update = (result != 0);
+
+	*update_result_ptr = update_result;
+
+	return result;
+}
+
+static void acpi_battery_notify_update(struct acpi_battery *battery)
+{
+	acpi_battery_get_status(battery);
+
+	if (battery->flags.init_update) {
+		return;
+	}
+
+	if ((!battery->flags.battery_present_prev &
+	     acpi_battery_present(battery)) ||
+	    (battery->flags.battery_present_prev &
+	     !acpi_battery_present(battery))) {
+		battery->flags.init_update = 1;
+	} else {
+		battery->flags.update[ACPI_BATTERY_INFO] = 1;
+		battery->flags.update[ACPI_BATTERY_STATE] = 1;
+		battery->flags.update[ACPI_BATTERY_ALARM] = 1;
 	}
 }
 
@@ -335,37 +460,33 @@
    -------------------------------------------------------------------------- */
 
 static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_print_info(struct seq_file *seq, int result)
 {
-	int result = 0;
 	struct acpi_battery *battery = seq->private;
 	struct acpi_battery_info *bif = NULL;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (battery->flags.present)
+	if (acpi_battery_present(battery))
 		seq_printf(seq, "present:                 yes\n");
 	else {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
-	/* Battery Info (_BIF) */
-
-	result = acpi_battery_get_info(battery, &bif);
-	if (result || !bif) {
-		seq_printf(seq, "ERROR: Unable to read battery information\n");
+	bif = battery->bif_data.pointer;
+	if (!bif) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+		result = -ENODEV;
 		goto end;
 	}
 
-	units =
-	    bif->
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+	/* Battery Units */
+
+	units = acpi_battery_power_units(battery);
 
 	if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
 		seq_printf(seq, "design capacity:         unknown\n");
@@ -396,7 +517,6 @@
 	else
 		seq_printf(seq, "design voltage:          %d mV\n",
 			   (u32) bif->design_voltage);
-
 	seq_printf(seq, "design capacity warning: %d %sh\n",
 		   (u32) bif->design_capacity_warning, units);
 	seq_printf(seq, "design capacity low:     %d %sh\n",
@@ -411,50 +531,40 @@
 	seq_printf(seq, "OEM info:                %s\n", bif->oem_info);
 
       end:
-	kfree(bif);
 
-	return 0;
+	if (result)
+		seq_printf(seq, "ERROR: Unable to read battery info\n");
+
+	return result;
 }
 
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+static int acpi_battery_print_state(struct seq_file *seq, int result)
 {
-	return single_open(file, acpi_battery_read_info, PDE(inode)->data);
-}
-
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
-{
-	int result = 0;
 	struct acpi_battery *battery = seq->private;
-	struct acpi_battery_status *bst = NULL;
+	struct acpi_battery_state *bst = NULL;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (battery->flags.present)
+	if (acpi_battery_present(battery))
 		seq_printf(seq, "present:                 yes\n");
 	else {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
-	/* Battery Units */
-
-	units =
-	    battery->flags.
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-	/* Battery Status (_BST) */
-
-	result = acpi_battery_get_status(battery, &bst);
-	if (result || !bst) {
-		seq_printf(seq, "ERROR: Unable to read battery status\n");
+	bst = battery->bst_data.pointer;
+	if (!bst) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+		result = -ENODEV;
 		goto end;
 	}
 
+	/* Battery Units */
+
+	units = acpi_battery_power_units(battery);
+
 	if (!(bst->state & 0x04))
 		seq_printf(seq, "capacity state:          ok\n");
 	else
@@ -490,48 +600,43 @@
 			   (u32) bst->present_voltage);
 
       end:
-	kfree(bst);
 
-	return 0;
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery state\n");
+	}
+
+	return result;
 }
 
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_battery_read_state, PDE(inode)->data);
-}
-
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_print_alarm(struct seq_file *seq, int result)
 {
 	struct acpi_battery *battery = seq->private;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (!battery->flags.present) {
+	if (!acpi_battery_present(battery)) {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
 	/* Battery Units */
 
-	units =
-	    battery->flags.
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-	/* Battery Alarm */
+	units = acpi_battery_power_units(battery);
 
 	seq_printf(seq, "alarm:                   ");
 	if (!battery->alarm)
 		seq_printf(seq, "unsupported\n");
 	else
-		seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+		seq_printf(seq, "%lu %sh\n", battery->alarm, units);
 
       end:
-	return 0;
+
+	if (result)
+		seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+	return result;
 }
 
 static ssize_t
@@ -543,27 +648,113 @@
 	char alarm_string[12] = { '\0' };
 	struct seq_file *m = file->private_data;
 	struct acpi_battery *battery = m->private;
-
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
 
 	if (!battery || (count > sizeof(alarm_string) - 1))
 		return -EINVAL;
 
-	acpi_battery_check_present(battery);
+	mutex_lock(&battery->mutex);
 
-	if (!battery->flags.present)
-		return -ENODEV;
+	result = acpi_battery_update(battery, 1, &update_result);
+	if (result) {
+		result = -ENODEV;
+		goto end;
+	}
 
-	if (copy_from_user(alarm_string, buffer, count))
-		return -EFAULT;
+	if (!acpi_battery_present(battery)) {
+		result = -ENODEV;
+		goto end;
+	}
+
+	if (copy_from_user(alarm_string, buffer, count)) {
+		result = -EFAULT;
+		goto end;
+	}
 
 	alarm_string[count] = '\0';
 
 	result = acpi_battery_set_alarm(battery,
 					simple_strtoul(alarm_string, NULL, 0));
 	if (result)
-		return result;
+		goto end;
 
-	return count;
+      end:
+
+	acpi_battery_check_result(battery, result);
+
+	if (!result)
+		result = count;
+
+	mutex_unlock(&battery->mutex);
+
+	return result;
+}
+
+typedef int(*print_func)(struct seq_file *seq, int result);
+typedef int(*get_func)(struct acpi_battery *battery);
+
+static struct acpi_read_mux {
+	print_func print;
+	get_func get;
+} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
+	{.get = acpi_battery_get_info, .print = acpi_battery_print_info},
+	{.get = acpi_battery_get_state, .print = acpi_battery_print_state},
+	{.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+};
+
+static int acpi_battery_read(int fid, struct seq_file *seq)
+{
+	struct acpi_battery *battery = seq->private;
+	int result = 0;
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
+	int update = 0;
+
+	mutex_lock(&battery->mutex);
+
+	update = (get_seconds() - battery->update_time[fid] >= update_time);
+	update = (update | battery->flags.update[fid]);
+
+	result = acpi_battery_update(battery, update, &update_result);
+	if (result)
+		goto end;
+
+	if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+		result = acpi_read_funcs[fid].get(battery);
+		if (result)
+			goto end;
+	}
+
+      end:
+	result = acpi_read_funcs[fid].print(seq, result);
+	acpi_battery_check_result(battery, result);
+	battery->flags.update[fid] = result;
+	mutex_unlock(&battery->mutex);
+	return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_INFO, seq);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_STATE, seq);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_battery_read_state, PDE(inode)->data);
 }
 
 static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -571,35 +762,51 @@
 	return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
 }
 
-static const struct file_operations acpi_battery_info_ops = {
+static struct battery_file {
+	struct file_operations ops;
+	mode_t mode;
+	char *name;
+} acpi_battery_file[] = {
+	{
+	.name = "info",
+	.mode = S_IRUGO,
+	.ops = {
 	.open = acpi_battery_info_open_fs,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_state_ops = {
+	},
+	},
+	{
+	.name = "state",
+	.mode = S_IRUGO,
+	.ops = {
 	.open = acpi_battery_state_open_fs,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_alarm_ops = {
+	},
+	},
+	{
+	.name = "alarm",
+	.mode = S_IFREG | S_IRUGO | S_IWUSR,
+	.ops = {
 	.open = acpi_battery_alarm_open_fs,
 	.read = seq_read,
 	.write = acpi_battery_write_alarm,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
+	},
+	},
 };
 
 static int acpi_battery_add_fs(struct acpi_device *device)
 {
 	struct proc_dir_entry *entry = NULL;
-
+	int i;
 
 	if (!acpi_device_dir(device)) {
 		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -609,38 +816,16 @@
 		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
-	/* 'info' [R] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
-				  S_IRUGO, acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_info_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
-	}
-
-	/* 'status' [R] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
-				  S_IRUGO, acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_state_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
-	}
-
-	/* 'alarm' [R/W] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
-				  S_IFREG | S_IRUGO | S_IWUSR,
-				  acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_alarm_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
+	for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+		entry = create_proc_entry(acpi_battery_file[i].name,
+				  acpi_battery_file[i].mode, acpi_device_dir(device));
+		if (!entry)
+			return -ENODEV;
+		else {
+			entry->proc_fops = &acpi_battery_file[i].ops;
+			entry->data = acpi_driver_data(device);
+			entry->owner = THIS_MODULE;
+		}
 	}
 
 	return 0;
@@ -648,15 +833,12 @@
 
 static int acpi_battery_remove_fs(struct acpi_device *device)
 {
-
+	int i;
 	if (acpi_device_dir(device)) {
-		remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+		for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+			remove_proc_entry(acpi_battery_file[i].name,
 				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_BATTERY_FILE_INFO,
-				  acpi_device_dir(device));
-
+		}
 		remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
 		acpi_device_dir(device) = NULL;
 	}
@@ -673,7 +855,6 @@
 	struct acpi_battery *battery = data;
 	struct acpi_device *device = NULL;
 
-
 	if (!battery)
 		return;
 
@@ -684,8 +865,10 @@
 	case ACPI_BATTERY_NOTIFY_INFO:
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
-		acpi_battery_check(battery);
-		acpi_bus_generate_event(device, event, battery->flags.present);
+		device = battery->device;
+		acpi_battery_notify_update(battery);
+		acpi_bus_generate_event(device, event,
+					acpi_battery_present(battery));
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +885,6 @@
 	acpi_status status = 0;
 	struct acpi_battery *battery = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
@@ -710,15 +892,21 @@
 	if (!battery)
 		return -ENOMEM;
 
+	mutex_init(&battery->mutex);
+
+	mutex_lock(&battery->mutex);
+
 	battery->device = device;
 	strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
 	acpi_driver_data(device) = battery;
 
-	result = acpi_battery_check(battery);
+	result = acpi_battery_get_status(battery);
 	if (result)
 		goto end;
 
+	battery->flags.init_update = 1;
+
 	result = acpi_battery_add_fs(device);
 	if (result)
 		goto end;
@@ -727,6 +915,7 @@
 					     ACPI_ALL_NOTIFY,
 					     acpi_battery_notify, battery);
 	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -736,11 +925,14 @@
 	       device->status.battery_present ? "present" : "absent");
 
       end:
+
 	if (result) {
 		acpi_battery_remove_fs(device);
 		kfree(battery);
 	}
 
+	mutex_unlock(&battery->mutex);
+
 	return result;
 }
 
@@ -749,18 +941,27 @@
 	acpi_status status = 0;
 	struct acpi_battery *battery = NULL;
 
-
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
 	battery = acpi_driver_data(device);
 
+	mutex_lock(&battery->mutex);
+
 	status = acpi_remove_notify_handler(device->handle,
 					    ACPI_ALL_NOTIFY,
 					    acpi_battery_notify);
 
 	acpi_battery_remove_fs(device);
 
+	kfree(battery->bif_data.pointer);
+
+	kfree(battery->bst_data.pointer);
+
+	mutex_unlock(&battery->mutex);
+
+	mutex_destroy(&battery->mutex);
+
 	kfree(battery);
 
 	return 0;
@@ -775,7 +976,10 @@
 		return -EINVAL;
 
 	battery = device->driver_data;
-	return acpi_battery_check(battery);
+
+	battery->flags.init_update = 1;
+
+	return 0;
 }
 
 static int __init acpi_battery_init(void)
@@ -800,7 +1004,6 @@
 
 static void __exit acpi_battery_exit(void)
 {
-
 	acpi_bus_unregister_driver(&acpi_battery_driver);
 
 	acpi_unlock_battery_dir(acpi_battery_dir);
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index fb3f31b..56a5b3f 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -288,6 +288,11 @@
 	new_bay->pdev = pdev;
 	platform_set_drvdata(pdev, new_bay);
 
+	/*
+	 * we want the bay driver to be able to send uevents
+	 */
+	pdev->dev.uevent_suppress = 0;
+
 	if (acpi_bay_add_fs(new_bay)) {
 		platform_device_unregister(new_bay->pdev);
 		goto bay_add_err;
@@ -328,18 +333,12 @@
 {
 	struct bay *bay_dev = (struct bay *)data;
 	struct device *dev = &bay_dev->pdev->dev;
+	char event_string[12];
+	char *envp[] = { event_string, NULL };
 
 	bay_dprintk(handle, "Bay event");
-
-	switch(event) {
-	case ACPI_NOTIFY_BUS_CHECK:
-	case ACPI_NOTIFY_DEVICE_CHECK:
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		kobject_uevent(&dev->kobj, KOBJ_CHANGE);
-		break;
-	default:
-		printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
-	}
+	sprintf(event_string, "BAY_EVENT=%d\n", event);
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 static acpi_status
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e5084ec..6b2658c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -292,6 +292,10 @@
 	if (!device)
 		return -EINVAL;
 
+	if (acpi_bus_generate_genetlink_event(device, type, data))
+		printk(KERN_WARNING PREFIX
+			"Failed to generate an ACPI event via genetlink!\n");
+
 	/* drop event on the floor if no one's listening */
 	if (!event_is_open)
 		return 0;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 4546bf8..6192c8b 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -40,8 +40,15 @@
 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
 MODULE_LICENSE("GPL");
 
+static int immediate_undock = 1;
+module_param(immediate_undock, bool, 0644);
+MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
+	"undock immediately when the undock button is pressed, 0 will cause"
+	" the driver to wait for userspace to write the undock sysfs file "
+	" before undocking");
+
 static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device dock_device;
+static struct platform_device *dock_device;
 static char dock_device_name[] = "dock";
 
 struct dock_station {
@@ -63,6 +70,7 @@
 };
 
 #define DOCK_DOCKING	0x00000001
+#define DOCK_UNDOCKING  0x00000002
 #define DOCK_EVENT	3
 #define UNDOCK_EVENT	2
 
@@ -327,12 +335,20 @@
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
 {
-	struct device *dev = &dock_device.dev;
+	struct device *dev = &dock_device->dev;
+	char event_string[7];
+	char *envp[] = { event_string, NULL };
+
+	if (num == UNDOCK_EVENT)
+		sprintf(event_string, "UNDOCK");
+	else
+		sprintf(event_string, "DOCK");
+
 	/*
 	 * Indicate that the status of the dock station has
 	 * changed.
 	 */
-	kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 /**
@@ -380,12 +396,11 @@
 	union acpi_object arg;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *obj;
 
 	acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
-	obj = name_buffer.pointer;
 
-	printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+	printk(KERN_INFO PREFIX "%s - %s\n",
+		(char *)name_buffer.pointer, dock ? "docking" : "undocking");
 
 	/* _DCK method has one argument */
 	arg_list.count = 1;
@@ -394,7 +409,8 @@
 	arg.integer.value = dock;
 	status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
 	if (ACPI_FAILURE(status))
-		pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+		printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
+			 (char *)name_buffer.pointer);
 	kfree(buffer.pointer);
 	kfree(name_buffer.pointer);
 }
@@ -420,6 +436,16 @@
 	ds->last_dock_time = jiffies;
 }
 
+static inline void begin_undock(struct dock_station *ds)
+{
+	ds->flags |= DOCK_UNDOCKING;
+}
+
+static inline void complete_undock(struct dock_station *ds)
+{
+	ds->flags &= ~(DOCK_UNDOCKING);
+}
+
 /**
  * dock_in_progress - see if we are in the middle of handling a dock event
  * @ds: the dock station
@@ -550,7 +576,7 @@
 		printk(KERN_ERR PREFIX "Unable to undock!\n");
 		return -EBUSY;
 	}
-
+	complete_undock(ds);
 	return 0;
 }
 
@@ -594,7 +620,11 @@
 	 * to the driver who wish to hotplug.
          */
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		handle_eject_request(ds, event);
+		begin_undock(ds);
+		if (immediate_undock)
+			handle_eject_request(ds, event);
+		else
+			dock_event(ds, event, UNDOCK_EVENT);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -653,6 +683,17 @@
 DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
 /*
+ * show_flags - read method for flags file in sysfs
+ */
+static ssize_t show_flags(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
+
+}
+DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
+/*
  * write_undock - write method for "undock" file in sysfs
  */
 static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
@@ -675,16 +716,15 @@
 			     struct device_attribute *attr, char *buf)
 {
 	unsigned long lbuf;
-	acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
-	if(ACPI_FAILURE(status)) {
+	acpi_status status = acpi_evaluate_integer(dock_station->handle,
+					"_UID", NULL, &lbuf);
+	if (ACPI_FAILURE(status))
 	    return 0;
-	}
+
 	return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
 }
 DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 
-
-
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -711,33 +751,53 @@
 	ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 
 	/* initialize platform device stuff */
-	dock_device.name = dock_device_name;
-	ret = platform_device_register(&dock_device);
-	if (ret) {
-		printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+	dock_device =
+		platform_device_register_simple(dock_device_name, 0, NULL, 0);
+	if (IS_ERR(dock_device)) {
 		kfree(dock_station);
-		return ret;
+		dock_station = NULL;
+		return PTR_ERR(dock_device);
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+
+	/* we want the dock device to send uevents */
+	dock_device->dev.uevent_suppress = 0;
+
+	ret = device_create_file(&dock_device->dev, &dev_attr_docked);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		platform_device_unregister(&dock_device);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+	ret = device_create_file(&dock_device->dev, &dev_attr_undock);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		device_remove_file(&dock_device.dev, &dev_attr_docked);
-		platform_device_unregister(&dock_device);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+	ret = device_create_file(&dock_device->dev, &dev_attr_uid);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		platform_device_unregister(&dock_device);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		device_remove_file(&dock_device->dev, &dev_attr_undock);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
+		return ret;
+	}
+	ret = device_create_file(&dock_device->dev, &dev_attr_flags);
+	if (ret) {
+		printk("Error %d adding sysfs file\n", ret);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		device_remove_file(&dock_device->dev, &dev_attr_undock);
+		device_remove_file(&dock_device->dev, &dev_attr_uid);
+		platform_device_unregister(dock_device);
+		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
 
@@ -750,6 +810,7 @@
 	dd = alloc_dock_dependent_device(handle);
 	if (!dd) {
 		kfree(dock_station);
+		dock_station = NULL;
 		ret = -ENOMEM;
 		goto dock_add_err_unregister;
 	}
@@ -773,10 +834,13 @@
 dock_add_err:
 	kfree(dd);
 dock_add_err_unregister:
-	device_remove_file(&dock_device.dev, &dev_attr_docked);
-	device_remove_file(&dock_device.dev, &dev_attr_undock);
-	platform_device_unregister(&dock_device);
+	device_remove_file(&dock_device->dev, &dev_attr_docked);
+	device_remove_file(&dock_device->dev, &dev_attr_undock);
+	device_remove_file(&dock_device->dev, &dev_attr_uid);
+	device_remove_file(&dock_device->dev, &dev_attr_flags);
+	platform_device_unregister(dock_device);
 	kfree(dock_station);
+	dock_station = NULL;
 	return ret;
 }
 
@@ -804,12 +868,15 @@
 		printk(KERN_ERR "Error removing notify handler\n");
 
 	/* cleanup sysfs */
-	device_remove_file(&dock_device.dev, &dev_attr_docked);
-	device_remove_file(&dock_device.dev, &dev_attr_undock);
-	platform_device_unregister(&dock_device);
+	device_remove_file(&dock_device->dev, &dev_attr_docked);
+	device_remove_file(&dock_device->dev, &dev_attr_undock);
+	device_remove_file(&dock_device->dev, &dev_attr_uid);
+	device_remove_file(&dock_device->dev, &dev_attr_flags);
+	platform_device_unregister(dock_device);
 
 	/* free dock station memory */
 	kfree(dock_station);
+	dock_station = NULL;
 	return 0;
 }
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 82f496c..10e8510 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,25 +34,26 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 #include <asm/io.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/actypes.h>
 
-#define _COMPONENT		ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("ec");
-#define ACPI_EC_COMPONENT		0x00100000
 #define ACPI_EC_CLASS			"embedded_controller"
 #define ACPI_EC_HID			"PNP0C09"
 #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
 #define ACPI_EC_FILE_INFO		"info"
+
 #undef PREFIX
 #define PREFIX				"ACPI: EC: "
+
 /* EC status register */
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
 #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
 #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
 #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
+
 /* EC commands */
 enum ec_command {
 	ACPI_EC_COMMAND_READ = 0x80,
@@ -61,6 +62,7 @@
 	ACPI_EC_BURST_DISABLE = 0x83,
 	ACPI_EC_COMMAND_QUERY = 0x84,
 };
+
 /* EC events */
 enum ec_event {
 	ACPI_EC_EVENT_OBF_1 = 1,	/* Output buffer full */
@@ -94,6 +96,16 @@
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
+typedef int (*acpi_ec_query_func) (void *data);
+
+struct acpi_ec_query_handler {
+	struct list_head node;
+	acpi_ec_query_func func;
+	acpi_handle handle;
+	void *data;
+	u8 query_bit;
+};
+
 static struct acpi_ec {
 	acpi_handle handle;
 	unsigned long gpe;
@@ -104,6 +116,7 @@
 	atomic_t query_pending;
 	atomic_t event_count;
 	wait_queue_head_t wait;
+	struct list_head list;
 } *boot_ec, *first_ec;
 
 /* --------------------------------------------------------------------------
@@ -245,7 +258,7 @@
 
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
 	if (status) {
-		printk(KERN_DEBUG PREFIX
+		printk(KERN_ERR PREFIX
 		       "input buffer is not empty, aborting transaction\n");
 		goto end;
 	}
@@ -394,21 +407,67 @@
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
+int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+			      acpi_handle handle, acpi_ec_query_func func,
+			      void *data)
+{
+	struct acpi_ec_query_handler *handler =
+	    kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+	if (!handler)
+		return -ENOMEM;
+
+	handler->query_bit = query_bit;
+	handler->handle = handle;
+	handler->func = func;
+	handler->data = data;
+	mutex_lock(&ec->lock);
+	list_add_tail(&handler->node, &ec->list);
+	mutex_unlock(&ec->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+	struct acpi_ec_query_handler *handler;
+	mutex_lock(&ec->lock);
+	list_for_each_entry(handler, &ec->list, node) {
+		if (query_bit == handler->query_bit) {
+			list_del(&handler->node);
+			kfree(handler);
+			break;
+		}
+	}
+	mutex_unlock(&ec->lock);
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
 	struct acpi_ec *ec = ec_cxt;
 	u8 value = 0;
-	char object_name[8];
+	struct acpi_ec_query_handler *handler, copy;
 
 	if (!ec || acpi_ec_query(ec, &value))
 		return;
-
-	snprintf(object_name, 8, "_Q%2.2X", value);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
-
-	acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+	mutex_lock(&ec->lock);
+	list_for_each_entry(handler, &ec->list, node) {
+		if (value == handler->query_bit) {
+			/* have custom handler for this bit */
+			memcpy(&copy, handler, sizeof(copy));
+			mutex_unlock(&ec->lock);
+			if (copy.func) {
+				copy.func(copy.data);
+			} else if (copy.handle) {
+				acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+			}
+			return;
+		}
+	}
+	mutex_unlock(&ec->lock);
+	printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
@@ -427,8 +486,7 @@
 	if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
 		atomic_set(&ec->query_pending, 1);
 		status =
-		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
-				    ec);
+		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
 	}
 
 	return status == AE_OK ?
@@ -454,57 +512,35 @@
 }
 
 static acpi_status
-acpi_ec_space_handler(u32 function,
-		      acpi_physical_address address,
-		      u32 bit_width,
-		      acpi_integer * value,
+acpi_ec_space_handler(u32 function, acpi_physical_address address,
+		      u32 bits, acpi_integer *value,
 		      void *handler_context, void *region_context)
 {
-	int result = 0;
 	struct acpi_ec *ec = handler_context;
-	u64 temp = *value;
-	acpi_integer f_v = 0;
-	int i = 0;
+	int result = 0, i = 0;
+	u8 temp = 0;
 
 	if ((address > 0xFF) || !value || !handler_context)
 		return AE_BAD_PARAMETER;
 
-	if (bit_width != 8 && acpi_strict) {
+	if (function != ACPI_READ && function != ACPI_WRITE)
 		return AE_BAD_PARAMETER;
+
+	if (bits != 8 && acpi_strict)
+		return AE_BAD_PARAMETER;
+
+	while (bits - i > 0) {
+		if (function == ACPI_READ) {
+			result = acpi_ec_read(ec, address, &temp);
+			(*value) |= ((acpi_integer)temp) << i;
+		} else {
+			temp = 0xff & ((*value) >> i);
+			result = acpi_ec_write(ec, address, temp);
+		}
+		i += 8;
+		++address;
 	}
 
-      next_byte:
-	switch (function) {
-	case ACPI_READ:
-		temp = 0;
-		result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
-		break;
-	case ACPI_WRITE:
-		result = acpi_ec_write(ec, (u8) address, (u8) temp);
-		break;
-	default:
-		result = -EINVAL;
-		goto out;
-		break;
-	}
-
-	bit_width -= 8;
-	if (bit_width) {
-		if (function == ACPI_READ)
-			f_v |= temp << 8 * i;
-		if (function == ACPI_WRITE)
-			temp >>= 8;
-		i++;
-		address++;
-		goto next_byte;
-	}
-
-	if (function == ACPI_READ) {
-		f_v |= temp << 8 * i;
-		*value = f_v;
-	}
-
-      out:
 	switch (result) {
 	case -EINVAL:
 		return AE_BAD_PARAMETER;
@@ -597,9 +633,6 @@
 static acpi_status
 ec_parse_io_ports(struct acpi_resource *resource, void *context);
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
-
 static struct acpi_ec *make_acpi_ec(void)
 {
 	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
@@ -610,13 +643,52 @@
 	atomic_set(&ec->event_count, 1);
 	mutex_init(&ec->lock);
 	init_waitqueue_head(&ec->wait);
+	INIT_LIST_HEAD(&ec->list);
 
 	return ec;
 }
 
+static acpi_status
+acpi_ec_register_query_methods(acpi_handle handle, u32 level,
+			       void *context, void **return_value)
+{
+	struct acpi_namespace_node *node = handle;
+	struct acpi_ec *ec = context;
+	int value = 0;
+	if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+		acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
+	}
+	return AE_OK;
+}
+
+static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle)
+{
+	if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS,
+				     ec_parse_io_ports, ec)))
+		return -EINVAL;
+
+	/* Get GPE bit assignment (EC events). */
+	/* TODO: Add support for _GPE returning a package */
+	if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe)))
+		return -EINVAL;
+
+	/* Use the global lock for all EC transactions? */
+	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+
+	/* Find and register all query methods */
+	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
+			    acpi_ec_register_query_methods, ec, NULL);
+
+	ec->handle = handle;
+
+	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx",
+			  ec->gpe, ec->command_addr, ec->data_addr);
+
+	return 0;
+}
+
 static int acpi_ec_add(struct acpi_device *device)
 {
-	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
 	if (!device)
@@ -629,8 +701,7 @@
 	if (!ec)
 		return -ENOMEM;
 
-	status = ec_parse_device(device->handle, 0, ec, NULL);
-	if (status != AE_CTRL_TERMINATE) {
+	if (ec_parse_device(ec, device->handle)) {
 		kfree(ec);
 		return -EINVAL;
 	}
@@ -641,6 +712,8 @@
 			/* We might have incorrect info for GL at boot time */
 			mutex_lock(&boot_ec->lock);
 			boot_ec->global_lock = ec->global_lock;
+			/* Copy handlers from new ec into boot ec */
+			list_splice(&ec->list, &boot_ec->list);
 			mutex_unlock(&boot_ec->lock);
 			kfree(ec);
 			ec = boot_ec;
@@ -651,22 +724,24 @@
 	acpi_driver_data(device) = ec;
 
 	acpi_ec_add_fs(device);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
-			  acpi_device_name(device), acpi_device_bid(device),
-			  (u32) ec->gpe));
-
 	return 0;
 }
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
 	struct acpi_ec *ec;
+	struct acpi_ec_query_handler *handler;
 
 	if (!device)
 		return -EINVAL;
 
 	ec = acpi_driver_data(device);
+	mutex_lock(&ec->lock);
+	list_for_each_entry(handler, &ec->list, node) {
+		list_del(&handler->node);
+		kfree(handler);
+	}
+	mutex_unlock(&ec->lock);
 	acpi_ec_remove_fs(device);
 	acpi_driver_data(device) = NULL;
 	if (ec == first_ec)
@@ -722,15 +797,13 @@
 		return -ENODEV;
 	}
 
-	/* EC is fully operational, allow queries */
-	atomic_set(&ec->query_pending, 0);
-
 	return 0;
 }
 
 static int acpi_ec_start(struct acpi_device *device)
 {
 	struct acpi_ec *ec;
+	int ret = 0;
 
 	if (!device)
 		return -EINVAL;
@@ -740,14 +813,14 @@
 	if (!ec)
 		return -EINVAL;
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-			  ec->gpe, ec->command_addr, ec->data_addr));
-
 	/* Boot EC is already working */
-	if (ec == boot_ec)
-		return 0;
+	if (ec != boot_ec)
+		ret = ec_install_handlers(ec);
 
-	return ec_install_handlers(ec);
+	/* EC is fully operational, allow queries */
+	atomic_set(&ec->query_pending, 0);
+
+	return ret;
 }
 
 static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -779,34 +852,6 @@
 	return 0;
 }
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
-{
-	acpi_status status;
-
-	struct acpi_ec *ec = context;
-	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-				     ec_parse_io_ports, ec);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	/* Get GPE bit assignment (EC events). */
-	/* TODO: Add support for _GPE returning a package */
-	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	/* Use the global lock for all EC transactions? */
-	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
-	ec->handle = handle;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-			  ec->gpe, ec->command_addr, ec->data_addr));
-
-	return AE_CTRL_TERMINATE;
-}
-
 int __init acpi_ec_ecdt_probe(void)
 {
 	int ret;
@@ -825,7 +870,7 @@
 	if (ACPI_FAILURE(status))
 		goto error;
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
+	printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
 
 	boot_ec->command_addr = ecdt_ptr->control.address;
 	boot_ec->data_addr = ecdt_ptr->data.address;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 3b23562..dfa5853 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -11,6 +11,8 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <acpi/acpi_drivers.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("event");
@@ -48,7 +50,6 @@
 	static int chars_remaining = 0;
 	static char *ptr;
 
-
 	if (!chars_remaining) {
 		memset(&event, 0, sizeof(struct acpi_bus_event));
 
@@ -106,23 +107,161 @@
 	.poll = acpi_system_poll_event,
 };
 
+#ifdef CONFIG_NET
+unsigned int acpi_event_seqnum;
+struct acpi_genl_event {
+	acpi_device_class device_class;
+	char bus_id[15];
+	u32 type;
+	u32 data;
+};
+
+/* attributes of acpi_genl_family */
+enum {
+	ACPI_GENL_ATTR_UNSPEC,
+	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
+	__ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+	ACPI_GENL_CMD_UNSPEC,
+	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
+	__ACPI_GENL_CMD_MAX,
+};
+#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
+
+#define ACPI_GENL_FAMILY_NAME		"acpi_event"
+#define ACPI_GENL_VERSION		0x01
+#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
+
+static struct genl_family acpi_event_genl_family = {
+	.id = GENL_ID_GENERATE,
+	.name = ACPI_GENL_FAMILY_NAME,
+	.version = ACPI_GENL_VERSION,
+	.maxattr = ACPI_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group acpi_event_mcgrp = {
+	.name = ACPI_GENL_MCAST_GROUP_NAME,
+};
+
+int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+				      u8 type, int data)
+{
+	struct sk_buff *skb;
+	struct nlattr *attr;
+	struct acpi_genl_event *event;
+	void *msg_header;
+	int size;
+	int result;
+
+	/* allocate memory */
+	size = nla_total_size(sizeof(struct acpi_genl_event)) +
+	    nla_total_size(0);
+
+	skb = genlmsg_new(size, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	/* add the genetlink message header */
+	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
+				 &acpi_event_genl_family, 0,
+				 ACPI_GENL_CMD_EVENT);
+	if (!msg_header) {
+		nlmsg_free(skb);
+		return -ENOMEM;
+	}
+
+	/* fill the data */
+	attr =
+	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
+			sizeof(struct acpi_genl_event));
+	if (!attr) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	event = nla_data(attr);
+	if (!event) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	memset(event, 0, sizeof(struct acpi_genl_event));
+
+	strcpy(event->device_class, device->pnp.device_class);
+	strcpy(event->bus_id, device->dev.bus_id);
+	event->type = type;
+	event->data = data;
+
+	/* send multicast genetlink message */
+	result = genlmsg_end(skb, msg_header);
+	if (result < 0) {
+		nlmsg_free(skb);
+		return result;
+	}
+
+	result =
+	    genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+	if (result)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Failed to send a Genetlink message!\n"));
+	return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+	int result;
+
+	result = genl_register_family(&acpi_event_genl_family);
+	if (result)
+		return result;
+
+	result = genl_register_mc_group(&acpi_event_genl_family,
+					&acpi_event_mcgrp);
+	if (result)
+		genl_unregister_family(&acpi_event_genl_family);
+
+	return result;
+}
+
+#else
+int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
+				      int data)
+{
+	return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+	return -ENODEV;
+}
+#endif
+
 static int __init acpi_event_init(void)
 {
 	struct proc_dir_entry *entry;
 	int error = 0;
 
-
 	if (acpi_disabled)
 		return 0;
 
+	/* create genetlink for acpi event */
+	error = acpi_event_genetlink_init();
+	if (error)
+		printk(KERN_WARNING PREFIX
+		       "Failed to create genetlink family for ACPI event\n");
+
 	/* 'event' [R] */
 	entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
 	if (entry)
 		entry->proc_fops = &acpi_system_event_ops;
-	else {
-		error = -ENODEV;
-	}
-	return error;
+	else
+		return -ENODEV;
+
+	return 0;
 }
 
-subsys_initcall(acpi_event_init);
+fs_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 902c287..361ebe6 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -586,6 +586,10 @@
 	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 	if (gpe_xrupt->previous) {
 		gpe_xrupt->previous->next = gpe_xrupt->next;
+	} else {
+		/* No previous, update list head */
+
+		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
 	}
 
 	if (gpe_xrupt->next) {
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 400d90f..23ee7bc 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -284,6 +284,7 @@
 	}
 
 	if (!pci_device_node) {
+		ACPI_FREE(pci_id);
 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 	}
 
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 41427a4..4893e25 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -16,7 +16,7 @@
 #if ACPI_GLUE_DEBUG
 #define DBG(x...) printk(PREFIX x)
 #else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
 #endif
 static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 0c9f15c..ab04d84 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -36,13 +36,11 @@
 ACPI_MODULE_NAME("numa");
 
 static nodemask_t nodes_found_map = NODE_MASK_NONE;
-#define PXM_INVAL	-1
-#define NID_INVAL	-1
 
 /* maps to convert between proximity domain and logical node ID */
-static int pxm_to_node_map[MAX_PXM_DOMAINS]
+static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
 				= { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
-static int node_to_pxm_map[MAX_NUMNODES]
+static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
 				= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
 int pxm_to_node(int pxm)
@@ -59,6 +57,12 @@
 	return node_to_pxm_map[node];
 }
 
+void __acpi_map_pxm_to_node(int pxm, int node)
+{
+	pxm_to_node_map[pxm] = node;
+	node_to_pxm_map[node] = pxm;
+}
+
 int acpi_map_pxm_to_node(int pxm)
 {
 	int node = pxm_to_node_map[pxm];
@@ -67,8 +71,7 @@
 		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
 			return NID_INVAL;
 		node = first_unset_node(nodes_found_map);
-		pxm_to_node_map[pxm] = node;
-		node_to_pxm_map[node] = pxm;
+		__acpi_map_pxm_to_node(pxm, node);
 		node_set(node, nodes_found_map);
 	}
 
@@ -83,7 +86,8 @@
 	node_clear(node, nodes_found_map);
 }
 
-void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
+static void __init
+acpi_table_print_srat_entry(struct acpi_subtable_header *header)
 {
 
 	ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -200,7 +204,7 @@
 	return 0;
 }
 
-int __init
+static int __init
 acpi_table_parse_srat(enum acpi_srat_type id,
 		      acpi_table_entry_handler handler, unsigned int max_entries)
 {
@@ -211,14 +215,13 @@
 
 int __init acpi_numa_init(void)
 {
-	int result;
-
 	/* SRAT: Static Resource Affinity Table */
 	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-					       acpi_parse_processor_affinity,
-					       NR_CPUS);
-		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);	// IA64 specific
+		acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
+				      acpi_parse_processor_affinity, NR_CPUS);
+		acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+				      acpi_parse_memory_affinity,
+				      NR_NODE_MEMBLKS);
 	}
 
 	/* SLIT: System Locality Information Table */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 00d53c2..12c09fa 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,13 +77,7 @@
 #define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-#define OSI_LINUX_ENABLED
-#ifdef	OSI_LINUX_ENABLED
-int osi_linux = 1;	/* enable _OSI(Linux) by default */
-#else
-int osi_linux;		/* disable _OSI(Linux) by default */
-#endif
-
+static int osi_linux;		/* disable _OSI(Linux) by default */
 
 #ifdef CONFIG_DMI
 static struct __initdata dmi_system_id acpi_osl_dmi_table[];
@@ -1183,17 +1177,10 @@
 	if (!strcmp("Linux", interface)) {
 		printk(KERN_WARNING PREFIX
 			"System BIOS is requesting _OSI(Linux)\n");
-#ifdef	OSI_LINUX_ENABLED
-		printk(KERN_WARNING PREFIX
-			"Please test with \"acpi_osi=!Linux\"\n"
-			"Please send dmidecode "
-			"to linux-acpi@vger.kernel.org\n");
-#else
 		printk(KERN_WARNING PREFIX
 			"If \"acpi_osi=Linux\" works better,\n"
 			"Please send dmidecode "
 			"to linux-acpi@vger.kernel.org\n");
-#endif
 		if(osi_linux)
 			return AE_OK;
 	}
@@ -1227,36 +1214,14 @@
 }
 
 #ifdef CONFIG_DMI
-#ifdef	OSI_LINUX_ENABLED
-static int dmi_osi_not_linux(struct dmi_system_id *d)
-{
-	printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
-	enable_osi_linux(0);
-	return 0;
-}
-#else
 static int dmi_osi_linux(struct dmi_system_id *d)
 {
-	printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
+	printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
 	enable_osi_linux(1);
 	return 0;
 }
-#endif
 
 static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-#ifdef	OSI_LINUX_ENABLED
-	/*
-	 * Boxes that need NOT _OSI(Linux)
-	 */
-	{
-	 .callback = dmi_osi_not_linux,
-	 .ident = "Toshiba Satellite P100",
-	 .matches = {
-		     DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
-		     DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
-		     },
-	 },
-#else
 	/*
 	 * Boxes that need _OSI(Linux)
 	 */
@@ -1268,7 +1233,6 @@
 		     DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
 		     },
 	 },
-#endif
 	{}
 };
 #endif /* CONFIG_DMI */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index acc5947..3448edd 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -733,7 +733,7 @@
 	/* query and set link->irq.active */
 	acpi_pci_link_get_current(link);
 
-	printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
 	       acpi_device_bid(device));
 	for (i = 0; i < link->irq.possible_count; i++) {
 		if (link->irq.active == link->irq.possible[i]) {
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e1ca86d..81aceb5 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -66,6 +66,7 @@
 #define ACPI_PROCESSOR_FILE_LIMIT	"limit"
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER	0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82
 
 #define ACPI_PROCESSOR_LIMIT_USER	0
 #define ACPI_PROCESSOR_LIMIT_THERMAL	1
@@ -84,6 +85,8 @@
 static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
 static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
 
 static struct acpi_driver acpi_processor_driver = {
 	.name = "processor",
@@ -696,6 +699,9 @@
 		acpi_processor_cst_has_changed(pr);
 		acpi_bus_generate_event(device, event, 0);
 		break;
+	case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+		acpi_processor_tstate_has_changed(pr);
+		acpi_bus_generate_event(device, event, 0);
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc78..a898991 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -475,7 +475,7 @@
 		/* Get end time (ticks) */
 		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C2, so notify users */
 		mark_tsc_unstable("possible TSC halt in C2");
 #endif
@@ -490,7 +490,17 @@
 
 	case ACPI_STATE_C3:
 
-		if (pr->flags.bm_check) {
+		/*
+		 * disable bus master
+		 * bm_check implies we need ARB_DIS
+		 * !bm_check implies we need cache flush
+		 * bm_control implies whether we can do ARB_DIS
+		 *
+		 * That leaves a case where bm_check is set and bm_control is
+		 * not set. In that case we cannot do much, we enter C3
+		 * without doing anything.
+		 */
+		if (pr->flags.bm_check && pr->flags.bm_control) {
 			if (atomic_inc_return(&c3_cpu_count) ==
 			    num_online_cpus()) {
 				/*
@@ -499,7 +509,7 @@
 				 */
 				acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 			}
-		} else {
+		} else if (!pr->flags.bm_check) {
 			/* SMP with no shared cache... Invalidate cache  */
 			ACPI_FLUSH_CPU_CACHE();
 		}
@@ -511,13 +521,13 @@
 		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-		if (pr->flags.bm_check) {
+		if (pr->flags.bm_check && pr->flags.bm_control) {
 			/* Enable bus master arbitration */
 			atomic_dec(&c3_cpu_count);
 			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 		}
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C3, so notify users */
 		mark_tsc_unstable("TSC halts in C3");
 #endif
@@ -961,9 +971,9 @@
 	if (pr->flags.bm_check) {
 		/* bus mastering control is necessary */
 		if (!pr->flags.bm_control) {
+			/* In this case we enter C3 without bus mastering */
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "C3 support requires bus mastering control\n"));
-			return;
+				"C3 support without bus mastering control\n"));
 		}
 	} else {
 		/*
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index b334860..3f55d1f 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -44,17 +44,231 @@
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_throttling");
 
+static int acpi_processor_get_throttling(struct acpi_processor *pr);
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+
+static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
+{
+	acpi_status status = 0;
+	unsigned long tpc = 0;
+
+	if (!pr)
+		return -EINVAL;
+	status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+		return -ENODEV;
+	}
+	pr->throttling_platform_limit = (int)tpc;
+	return 0;
+}
+
+int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
+{
+	return acpi_processor_get_platform_limit(pr);
+}
+
+/* --------------------------------------------------------------------------
+                             _PTC, _TSS, _TSD support 
+   -------------------------------------------------------------------------- */
+static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = 0;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *ptc = NULL;
+	union acpi_object obj = { 0 };
+
+	status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+		return -ENODEV;
+	}
+
+	ptc = (union acpi_object *)buffer.pointer;
+	if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
+	    || (ptc->package.count != 2)) {
+		printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	/*
+	 * control_register
+	 */
+
+	obj = ptc->package.elements[0];
+
+	if ((obj.type != ACPI_TYPE_BUFFER)
+	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+	    || (obj.buffer.pointer == NULL)) {
+		printk(KERN_ERR PREFIX
+		       "Invalid _PTC data (control_register)\n");
+		result = -EFAULT;
+		goto end;
+	}
+	memcpy(&pr->throttling.control_register, obj.buffer.pointer,
+	       sizeof(struct acpi_ptc_register));
+
+	/*
+	 * status_register
+	 */
+
+	obj = ptc->package.elements[1];
+
+	if ((obj.type != ACPI_TYPE_BUFFER)
+	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+	    || (obj.buffer.pointer == NULL)) {
+		printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	memcpy(&pr->throttling.status_register, obj.buffer.pointer,
+	       sizeof(struct acpi_ptc_register));
+
+      end:
+	kfree(buffer.pointer);
+
+	return result;
+}
+static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+	struct acpi_buffer state = { 0, NULL };
+	union acpi_object *tss = NULL;
+	int i;
+
+	status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+		return -ENODEV;
+	}
+
+	tss = buffer.pointer;
+	if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
+		printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+			  tss->package.count));
+
+	pr->throttling.state_count = tss->package.count;
+	pr->throttling.states_tss =
+	    kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
+		    GFP_KERNEL);
+	if (!pr->throttling.states_tss) {
+		result = -ENOMEM;
+		goto end;
+	}
+
+	for (i = 0; i < pr->throttling.state_count; i++) {
+
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[i]);
+
+		state.length = sizeof(struct acpi_processor_tx_tss);
+		state.pointer = tx;
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+		status = acpi_extract_package(&(tss->package.elements[i]),
+					      &format, &state);
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
+			result = -EFAULT;
+			kfree(pr->throttling.states_tss);
+			goto end;
+		}
+
+		if (!tx->freqpercentage) {
+			printk(KERN_ERR PREFIX
+			       "Invalid _TSS data: freq is zero\n");
+			result = -EFAULT;
+			kfree(pr->throttling.states_tss);
+			goto end;
+		}
+	}
+
+      end:
+	kfree(buffer.pointer);
+
+	return result;
+}
+static int acpi_processor_get_tsd(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+	struct acpi_buffer state = { 0, NULL };
+	union acpi_object *tsd = NULL;
+	struct acpi_tsd_package *pdomain;
+
+	status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		return -ENODEV;
+	}
+
+	tsd = buffer.pointer;
+	if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (tsd->package.count != 1) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	pdomain = &(pr->throttling.domain_info);
+
+	state.length = sizeof(struct acpi_tsd_package);
+	state.pointer = pdomain;
+
+	status = acpi_extract_package(&(tsd->package.elements[0]),
+				      &format, &state);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+      end:
+	kfree(buffer.pointer);
+	return result;
+}
+
 /* --------------------------------------------------------------------------
                               Throttling Control
    -------------------------------------------------------------------------- */
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 {
 	int state = 0;
 	u32 value = 0;
 	u32 duty_mask = 0;
 	u32 duty_value = 0;
 
-
 	if (!pr)
 		return -EINVAL;
 
@@ -94,13 +308,115 @@
 	return 0;
 }
 
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+static int acpi_read_throttling_status(struct acpi_processor_throttling
+				       *throttling)
+{
+	int value = -1;
+	switch (throttling->status_register.space_id) {
+	case ACPI_ADR_SPACE_SYSTEM_IO:
+		acpi_os_read_port((acpi_io_address) throttling->status_register.
+				  address, &value,
+				  (u32) throttling->status_register.bit_width *
+				  8);
+		break;
+	case ACPI_ADR_SPACE_FIXED_HARDWARE:
+		printk(KERN_ERR PREFIX
+		       "HARDWARE addr space,NOT supported yet\n");
+		break;
+	default:
+		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+		       (u32) (throttling->status_register.space_id));
+	}
+	return value;
+}
+
+static int acpi_write_throttling_state(struct acpi_processor_throttling
+				       *throttling, int value)
+{
+	int ret = -1;
+
+	switch (throttling->control_register.space_id) {
+	case ACPI_ADR_SPACE_SYSTEM_IO:
+		acpi_os_write_port((acpi_io_address) throttling->
+				   control_register.address, value,
+				   (u32) throttling->control_register.
+				   bit_width * 8);
+		ret = 0;
+		break;
+	case ACPI_ADR_SPACE_FIXED_HARDWARE:
+		printk(KERN_ERR PREFIX
+		       "HARDWARE addr space,NOT supported yet\n");
+		break;
+	default:
+		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+		       (u32) (throttling->control_register.space_id));
+	}
+	return ret;
+}
+
+static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+{
+	int i;
+
+	for (i = 0; i < pr->throttling.state_count; i++) {
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[i]);
+		if (tx->control == value)
+			break;
+	}
+	if (i > pr->throttling.state_count)
+		i = -1;
+	return i;
+}
+
+static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+{
+	int value = -1;
+	if (state >= 0 && state <= pr->throttling.state_count) {
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[state]);
+		value = tx->control;
+	}
+	return value;
+}
+
+static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
+{
+	int state = 0;
+	u32 value = 0;
+
+	if (!pr)
+		return -EINVAL;
+
+	if (!pr->flags.throttling)
+		return -ENODEV;
+
+	pr->throttling.state = 0;
+	local_irq_disable();
+	value = acpi_read_throttling_status(&pr->throttling);
+	if (value >= 0) {
+		state = acpi_get_throttling_state(pr, value);
+		pr->throttling.state = state;
+	}
+	local_irq_enable();
+
+	return 0;
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
+	return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
+					      int state)
 {
 	u32 value = 0;
 	u32 duty_mask = 0;
 	u32 duty_value = 0;
 
-
 	if (!pr)
 		return -EINVAL;
 
@@ -113,6 +429,8 @@
 	if (state == pr->throttling.state)
 		return 0;
 
+	if (state < pr->throttling_platform_limit)
+		return -EPERM;
 	/*
 	 * Calculate the duty_value and duty_mask.
 	 */
@@ -165,12 +483,51 @@
 	return 0;
 }
 
+static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
+					     int state)
+{
+	u32 value = 0;
+
+	if (!pr)
+		return -EINVAL;
+
+	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+		return -EINVAL;
+
+	if (!pr->flags.throttling)
+		return -ENODEV;
+
+	if (state == pr->throttling.state)
+		return 0;
+
+	if (state < pr->throttling_platform_limit)
+		return -EPERM;
+
+	local_irq_disable();
+
+	value = acpi_get_throttling_value(pr, state);
+	if (value >= 0) {
+		acpi_write_throttling_state(&pr->throttling, value);
+		pr->throttling.state = state;
+	}
+	local_irq_enable();
+
+	return 0;
+}
+
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+{
+	return pr->throttling.acpi_processor_set_throttling(pr, state);
+}
+
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
 	int result = 0;
 	int step = 0;
 	int i = 0;
-
+	int no_ptc = 0;
+	int no_tss = 0;
+	int no_tsd = 0;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -182,6 +539,21 @@
 		return -EINVAL;
 
 	/* TBD: Support ACPI 2.0 objects */
+	no_ptc = acpi_processor_get_throttling_control(pr);
+	no_tss = acpi_processor_get_throttling_states(pr);
+	no_tsd = acpi_processor_get_tsd(pr);
+
+	if (no_ptc || no_tss) {
+		pr->throttling.acpi_processor_get_throttling =
+		    &acpi_processor_get_throttling_fadt;
+		pr->throttling.acpi_processor_set_throttling =
+		    &acpi_processor_set_throttling_fadt;
+	} else {
+		pr->throttling.acpi_processor_get_throttling =
+		    &acpi_processor_get_throttling_ptc;
+		pr->throttling.acpi_processor_set_throttling =
+		    &acpi_processor_set_throttling_ptc;
+	}
 
 	if (!pr->throttling.address) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
@@ -262,7 +634,6 @@
 	int i = 0;
 	int result = 0;
 
-
 	if (!pr)
 		goto end;
 
@@ -280,15 +651,25 @@
 	}
 
 	seq_printf(seq, "state count:             %d\n"
-		   "active state:            T%d\n",
-		   pr->throttling.state_count, pr->throttling.state);
+		   "active state:            T%d\n"
+		   "state available: T%d to T%d\n",
+		   pr->throttling.state_count, pr->throttling.state,
+		   pr->throttling_platform_limit,
+		   pr->throttling.state_count - 1);
 
 	seq_puts(seq, "states:\n");
-	for (i = 0; i < pr->throttling.state_count; i++)
-		seq_printf(seq, "   %cT%d:                  %02d%%\n",
-			   (i == pr->throttling.state ? '*' : ' '), i,
-			   (pr->throttling.states[i].performance ? pr->
-			    throttling.states[i].performance / 10 : 0));
+	if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt)
+		for (i = 0; i < pr->throttling.state_count; i++)
+			seq_printf(seq, "   %cT%d:                  %02d%%\n",
+				   (i == pr->throttling.state ? '*' : ' '), i,
+				   (pr->throttling.states[i].performance ? pr->
+				    throttling.states[i].performance / 10 : 0));
+	else
+		for (i = 0; i < pr->throttling.state_count; i++)
+			seq_printf(seq, "   %cT%d:                  %02d%%\n",
+				   (i == pr->throttling.state ? '*' : ' '), i,
+				   (int)pr->throttling.states_tss[i].
+				   freqpercentage);
 
       end:
 	return 0;
@@ -301,7 +682,7 @@
 			   PDE(inode)->data);
 }
 
-static ssize_t acpi_processor_write_throttling(struct file * file,
+static ssize_t acpi_processor_write_throttling(struct file *file,
 					       const char __user * buffer,
 					       size_t count, loff_t * data)
 {
@@ -310,7 +691,6 @@
 	struct acpi_processor *pr = m->private;
 	char state_string[12] = { '\0' };
 
-
 	if (!pr || (count > sizeof(state_string) - 1))
 		return -EINVAL;
 
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index c1bae10..974d00c 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -127,7 +127,7 @@
 static struct acpi_driver acpi_sbs_driver = {
 	.name = "sbs",
 	.class = ACPI_SBS_CLASS,
-	.ids = ACPI_SBS_HID,
+	.ids = "ACPI0001,ACPI0005",
 	.ops = {
 		.add = acpi_sbs_add,
 		.remove = acpi_sbs_remove,
@@ -176,10 +176,8 @@
 };
 
 struct acpi_sbs {
-	acpi_handle handle;
 	int base;
 	struct acpi_device *device;
-	struct acpi_ec_smbus *smbus;
 	struct mutex mutex;
 	int sbsm_present;
 	int sbsm_batteries_supported;
@@ -511,7 +509,7 @@
 				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
-
+	sbs->sbsm_present = 1;
 	sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
 
       end:
@@ -1630,13 +1628,12 @@
 {
 	struct acpi_sbs *sbs = NULL;
 	int result = 0, remove_result = 0;
-	unsigned long sbs_obj;
 	int id;
 	acpi_status status = AE_OK;
 	unsigned long val;
 
 	status =
-	    acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+	    acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
 		return -EIO;
@@ -1653,7 +1650,7 @@
 
 	sbs_mutex_lock(sbs);
 
-	sbs->base = (val & 0xff00ull) >> 8;
+	sbs->base = 0xff & (val >> 8);
 	sbs->device = device;
 
 	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
@@ -1665,24 +1662,10 @@
 		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
 		goto end;
 	}
-	status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
-	if (status) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"acpi_evaluate_integer() failed"));
-		result = -EIO;
-		goto end;
-	}
-	if (sbs_obj > 0) {
-		result = acpi_sbsm_get_info(sbs);
-		if (result) {
-			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
-					"acpi_sbsm_get_info() failed"));
-			goto end;
-		}
-		sbs->sbsm_present = 1;
-	}
 
-	if (sbs->sbsm_present == 0) {
+	acpi_sbsm_get_info(sbs);
+
+	if (!sbs->sbsm_present) {
 		result = acpi_battery_add(sbs, 0);
 		if (result) {
 			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
@@ -1702,8 +1685,6 @@
 		}
 	}
 
-	sbs->handle = device->handle;
-
 	init_timer(&sbs->update_timer);
 	result = acpi_check_update_proc(sbs);
 	if (result)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 42127c0..3279e72 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -210,11 +210,6 @@
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
-
-	if (init_8259A_after_S1) {
-		printk("Broken toshiba laptop -> kicking interrupts\n");
-		init_8259A(0);
-	}
 }
 
 static int acpi_hibernation_pre_restore(void)
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 83a8d30..edee280 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -39,15 +39,12 @@
 
 #define ACPI_SYSTEM_CLASS		"system"
 #define ACPI_SYSTEM_DEVICE_NAME		"System"
-#define ACPI_SYSTEM_FILE_INFO		"info"
-#define ACPI_SYSTEM_FILE_EVENT		"event"
-#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
-#define ACPI_SYSTEM_FILE_FADT		"fadt"
 
 /*
  * Make ACPICA version work as module param
  */
-static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
+{
 	int result;
 
 	result = sprintf(buffer, "%x", ACPI_CA_VERSION);
@@ -58,9 +55,126 @@
 module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 
 /* --------------------------------------------------------------------------
+                              FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+static LIST_HEAD(acpi_table_attr_list);
+static struct kobject tables_kobj;
+
+struct acpi_table_attr {
+	struct bin_attribute attr;
+	char name[8];
+	int instance;
+	struct list_head node;
+};
+
+static ssize_t acpi_table_show(struct kobject *kobj,
+			       struct bin_attribute *bin_attr, char *buf,
+			       loff_t offset, size_t count)
+{
+	struct acpi_table_attr *table_attr =
+	    container_of(bin_attr, struct acpi_table_attr, attr);
+	struct acpi_table_header *table_header = NULL;
+	acpi_status status;
+	ssize_t ret_count = count;
+
+	status =
+	    acpi_get_table(table_attr->name, table_attr->instance,
+			   &table_header);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (offset >= table_header->length) {
+		ret_count = 0;
+		goto end;
+	}
+
+	if (offset + ret_count > table_header->length)
+		ret_count = table_header->length - offset;
+
+	memcpy(buf, ((char *)table_header) + offset, ret_count);
+
+      end:
+	return ret_count;
+}
+
+static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
+				 struct acpi_table_header *table_header)
+{
+	struct acpi_table_header *header = NULL;
+	struct acpi_table_attr *attr = NULL;
+
+	memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
+
+	list_for_each_entry(attr, &acpi_table_attr_list, node) {
+		if (!memcmp(table_header->signature, attr->name,
+			    ACPI_NAME_SIZE))
+			if (table_attr->instance < attr->instance)
+				table_attr->instance = attr->instance;
+	}
+	table_attr->instance++;
+
+	if (table_attr->instance > 1 || (table_attr->instance == 1 &&
+					 !acpi_get_table(table_header->
+							 signature, 2,
+							 &header)))
+		sprintf(table_attr->name + 4, "%d", table_attr->instance);
+
+	table_attr->attr.size = 0;
+	table_attr->attr.read = acpi_table_show;
+	table_attr->attr.attr.name = table_attr->name;
+	table_attr->attr.attr.mode = 0444;
+	table_attr->attr.attr.owner = THIS_MODULE;
+
+	return;
+}
+
+static int acpi_system_sysfs_init(void)
+{
+	struct acpi_table_attr *table_attr;
+	struct acpi_table_header *table_header = NULL;
+	int table_index = 0;
+	int result;
+
+	tables_kobj.parent = &acpi_subsys.kobj;
+	kobject_set_name(&tables_kobj, "tables");
+	result = kobject_register(&tables_kobj);
+	if (result)
+		return result;
+
+	do {
+		result = acpi_get_table_by_index(table_index, &table_header);
+		if (!result) {
+			table_index++;
+			table_attr = NULL;
+			table_attr =
+			    kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+			if (!table_attr)
+				return -ENOMEM;
+
+			acpi_table_attr_init(table_attr, table_header);
+			result =
+			    sysfs_create_bin_file(&tables_kobj,
+						  &table_attr->attr);
+			if (result) {
+				kfree(table_attr);
+				return result;
+			} else
+				list_add_tail(&table_attr->node,
+					      &acpi_table_attr_list);
+		}
+	} while (!result);
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 #ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_INFO		"info"
+#define ACPI_SYSTEM_FILE_EVENT		"event"
+#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
+#define ACPI_SYSTEM_FILE_FADT		"fadt"
 
 static int acpi_system_read_info(struct seq_file *seq, void *offset)
 {
@@ -80,7 +194,6 @@
 	.llseek = seq_lseek,
 	.release = single_release,
 };
-#endif
 
 static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
 				     loff_t *);
@@ -97,13 +210,11 @@
 	struct acpi_table_header *dsdt = NULL;
 	ssize_t res;
 
-
 	status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	res = simple_read_from_buffer(buffer, count, ppos,
-				      dsdt, dsdt->length);
+	res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
 
 	return res;
 }
@@ -123,28 +234,21 @@
 	struct acpi_table_header *fadt = NULL;
 	ssize_t res;
 
-
 	status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	res = simple_read_from_buffer(buffer, count, ppos,
-				      fadt, fadt->length);
+	res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
 
 	return res;
 }
 
-static int __init acpi_system_init(void)
+static int acpi_system_procfs_init(void)
 {
 	struct proc_dir_entry *entry;
 	int error = 0;
 	char *name;
 
-
-	if (acpi_disabled)
-		return 0;
-
-#ifdef CONFIG_ACPI_PROCFS
 	/* 'info' [R] */
 	name = ACPI_SYSTEM_FILE_INFO;
 	entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -153,7 +257,6 @@
 	else {
 		entry->proc_fops = &acpi_system_info_ops;
 	}
-#endif
 
 	/* 'dsdt' [R] */
 	name = ACPI_SYSTEM_FILE_DSDT;
@@ -177,12 +280,32 @@
       Error:
 	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
-#ifdef CONFIG_ACPI_PROCFS
 	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
-#endif
 
 	error = -EFAULT;
 	goto Done;
 }
+#else
+static int acpi_system_procfs_init(void)
+{
+	return 0;
+}
+#endif
+
+static int __init acpi_system_init(void)
+{
+	int result = 0;
+
+	if (acpi_disabled)
+		return 0;
+
+	result = acpi_system_procfs_init();
+	if (result)
+		return result;
+
+	result = acpi_system_sysfs_init();
+
+	return result;
+}
 
 subsys_initcall(acpi_system_init);
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 1285e91..002bb33 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -211,14 +211,17 @@
  * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
  *              Performs validation on some important FADT fields.
  *
+ * NOTE:        We create a local copy of the FADT regardless of the version.
+ *
  ******************************************************************************/
 
 void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
 {
 
 	/*
-	 * Check if the FADT is larger than what we know about (ACPI 2.0 version).
-	 * Truncate the table, but make some noise.
+	 * Check if the FADT is larger than the largest table that we expect
+	 * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+	 * a warning.
 	 */
 	if (length > sizeof(struct acpi_table_fadt)) {
 		ACPI_WARNING((AE_INFO,
@@ -227,10 +230,12 @@
 			      sizeof(struct acpi_table_fadt)));
 	}
 
-	/* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+	/* Clear the entire local FADT */
 
 	ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
 
+	/* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
+
 	ACPI_MEMCPY(&acpi_gbl_FADT, table,
 		    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
 
@@ -251,7 +256,7 @@
  * RETURN:      None
  *
  * DESCRIPTION: Converts all versions of the FADT to a common internal format.
- *              -> Expand all 32-bit addresses to 64-bit.
+ *              Expand all 32-bit addresses to 64-bit.
  *
  * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
  *              and must contain a copy of the actual FADT.
@@ -292,8 +297,23 @@
 	}
 
 	/*
-	 * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
-	 * structures as necessary.
+	 * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
+	 * should be zero are indeed zero. This will workaround BIOSs that
+	 * inadvertently place values in these fields.
+	 *
+	 * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
+	 * offset 45, 55, 95, and the word located at offset 109, 110.
+	 */
+	if (acpi_gbl_FADT.header.revision < 3) {
+		acpi_gbl_FADT.preferred_profile = 0;
+		acpi_gbl_FADT.pstate_control = 0;
+		acpi_gbl_FADT.cst_control = 0;
+		acpi_gbl_FADT.boot_flags = 0;
+	}
+
+	/*
+	 * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
+	 * generic address structures as necessary.
 	 */
 	for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
 		target =
@@ -349,18 +369,6 @@
 		    acpi_gbl_FADT.xpm1a_event_block.space_id;
 
 	}
-
-	/*
-	 * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
-	 * are indeed zero. This will workaround BIOSs that inadvertently placed
-	 * values in these fields.
-	 */
-	if (acpi_gbl_FADT.header.revision < 3) {
-		acpi_gbl_FADT.preferred_profile = 0;
-		acpi_gbl_FADT.pstate_control = 0;
-		acpi_gbl_FADT.cst_control = 0;
-		acpi_gbl_FADT.boot_flags = 0;
-	}
 }
 
 /******************************************************************************
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 8ec6f8e..f112af4 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -62,16 +62,13 @@
 static char *acpi_interfaces_supported[] = {
 	/* Operating System Vendor Strings */
 
-	"Windows 2000",
-	"Windows 2001",
-	"Windows 2001 SP0",
-	"Windows 2001 SP1",
-	"Windows 2001 SP2",
-	"Windows 2001 SP3",
-	"Windows 2001 SP4",
-	"Windows 2001.1",
-	"Windows 2001.1 SP1",	/* Added 03/2006 */
-	"Windows 2006",		/* Added 03/2006 */
+	"Windows 2000",		/* Windows 2000 */
+	"Windows 2001",		/* Windows XP */
+	"Windows 2001 SP1",	/* Windows XP SP1 */
+	"Windows 2001 SP2",	/* Windows XP SP2 */
+	"Windows 2001.1",	/* Windows Server 2003 */
+	"Windows 2001.1 SP1",	/* Windows Server 2003 SP1 - Added 03/2006 */
+	"Windows 2006",		/* Windows Vista - Added 03/2006 */
 
 	/* Feature Group Strings */
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 00d25b3..04ea697 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -33,6 +33,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/backlight.h>
+#include <linux/video_output.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -169,6 +170,7 @@
 	struct acpi_device *dev;
 	struct acpi_video_device_brightness *brightness;
 	struct backlight_device *backlight;
+	struct output_device *output_dev;
 };
 
 /* bus */
@@ -272,13 +274,17 @@
 				     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
 					 int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+			    unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
 
 /*backlight device sysfs support*/
 static int acpi_video_get_brightness(struct backlight_device *bd)
 {
 	unsigned long cur_level;
 	struct acpi_video_device *vd =
-		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+		(struct acpi_video_device *)bl_get_data(bd);
 	acpi_video_device_lcd_get_level_current(vd, &cur_level);
 	return (int) cur_level;
 }
@@ -287,7 +293,7 @@
 {
 	int request_level = bd->props.brightness;
 	struct acpi_video_device *vd =
-		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+		(struct acpi_video_device *)bl_get_data(bd);
 	acpi_video_device_lcd_set_level(vd, request_level);
 	return 0;
 }
@@ -297,6 +303,28 @@
 	.update_status  = acpi_video_set_brightness,
 };
 
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+	unsigned long state;
+	struct acpi_video_device *vd =
+		(struct acpi_video_device *)class_get_devdata(&od->class_dev);
+	acpi_video_device_get_state(vd, &state);
+	return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+	unsigned long state = od->request_state;
+	struct acpi_video_device *vd=
+		(struct acpi_video_device *)class_get_devdata(&od->class_dev);
+	return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+	.set_state = acpi_video_output_set,
+	.get_status = acpi_video_output_get,
+};
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -531,7 +559,6 @@
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-	acpi_integer status;
 	acpi_handle h_dummy1;
 	int i;
 	u32 max_level = 0;
@@ -565,50 +592,55 @@
 		device->cap._DSS = 1;
 	}
 
-	status = acpi_video_device_lcd_query_levels(device, &obj);
+	if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
 
-	if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
-		int count = 0;
-		union acpi_object *o;
+		if (obj->package.count >= 2) {
+			int count = 0;
+			union acpi_object *o;
 
-		br = kzalloc(sizeof(*br), GFP_KERNEL);
-		if (!br) {
-			printk(KERN_ERR "can't allocate memory\n");
-		} else {
-			br->levels = kmalloc(obj->package.count *
-					     sizeof *(br->levels), GFP_KERNEL);
-			if (!br->levels)
-				goto out;
-
-			for (i = 0; i < obj->package.count; i++) {
-				o = (union acpi_object *)&obj->package.
-				    elements[i];
-				if (o->type != ACPI_TYPE_INTEGER) {
-					printk(KERN_ERR PREFIX "Invalid data\n");
-					continue;
-				}
-				br->levels[count] = (u32) o->integer.value;
-				if (br->levels[count] > max_level)
-					max_level = br->levels[count];
-				count++;
-			}
-		      out:
-			if (count < 2) {
-				kfree(br->levels);
-				kfree(br);
+			br = kzalloc(sizeof(*br), GFP_KERNEL);
+			if (!br) {
+				printk(KERN_ERR "can't allocate memory\n");
 			} else {
-				br->count = count;
-				device->brightness = br;
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-						  "found %d brightness levels\n",
-						  count));
+				br->levels = kmalloc(obj->package.count *
+						     sizeof *(br->levels), GFP_KERNEL);
+				if (!br->levels)
+					goto out;
+
+				for (i = 0; i < obj->package.count; i++) {
+					o = (union acpi_object *)&obj->package.
+					    elements[i];
+					if (o->type != ACPI_TYPE_INTEGER) {
+						printk(KERN_ERR PREFIX "Invalid data\n");
+						continue;
+					}
+					br->levels[count] = (u32) o->integer.value;
+
+					if (br->levels[count] > max_level)
+						max_level = br->levels[count];
+					count++;
+				}
+			      out:
+				if (count < 2) {
+					kfree(br->levels);
+					kfree(br);
+				} else {
+					br->count = count;
+					device->brightness = br;
+					ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+							  "found %d brightness levels\n",
+							  count));
+				}
 			}
 		}
+
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
 	}
 
 	kfree(obj);
 
-	if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+	if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
 		unsigned long tmp;
 		static int count = 0;
 		char *name;
@@ -626,6 +658,17 @@
 
 		kfree(name);
 	}
+	if (device->cap._DCS && device->cap._DSS){
+		static int count = 0;
+		char *name;
+		name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+		if (!name)
+			return;
+		sprintf(name, "acpi_video%d", count++);
+		device->output_dev = video_output_register(name,
+				NULL, device, &acpi_output_properties);
+		kfree(name);
+	}
 	return;
 }
 
@@ -1669,6 +1712,7 @@
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
 	backlight_device_unregister(device->backlight);
+	video_output_unregister(device->output_dev);
 	return 0;
 }
 
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9..06f212f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -99,6 +99,7 @@
 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
+	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -113,11 +114,11 @@
 	PORT_TFDATA		= 0x20,	/* taskfile data */
 	PORT_SIG		= 0x24,	/* device TF signature */
 	PORT_CMD_ISSUE		= 0x38, /* command issue */
-	PORT_SCR		= 0x28, /* SATA phy register block */
 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
+	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
 
 	/* PORT_IRQ_{STAT,MASK} bits */
 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
@@ -216,8 +217,8 @@
 	unsigned int		ncq_saw_sdb:1;
 };
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static void ahci_irq_clear(struct ata_port *ap);
@@ -417,7 +418,10 @@
 
 	/* ATI */
 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
-	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
+	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
+	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
+	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
 
 	/* VIA */
 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -545,13 +549,19 @@
 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
-	/* some chips lie about 64bit support */
+	/* some chips have errata preventing 64bit use */
 	if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
 		dev_printk(KERN_INFO, &pdev->dev,
 			   "controller can't do 64bit DMA, forcing 32bit\n");
 		cap &= ~HOST_CAP_64;
 	}
 
+	if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			   "controller can't do NCQ, turning off CAP_NCQ\n");
+		cap &= ~HOST_CAP_NCQ;
+	}
+
 	/* fixup zero port_map */
 	if (!port_map) {
 		port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -625,38 +635,45 @@
 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
 }
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
 {
-	unsigned int sc_reg;
+	static const int offset[] = {
+		[SCR_STATUS]		= PORT_SCR_STAT,
+		[SCR_CONTROL]		= PORT_SCR_CTL,
+		[SCR_ERROR]		= PORT_SCR_ERR,
+		[SCR_ACTIVE]		= PORT_SCR_ACT,
+		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
+	};
+	struct ahci_host_priv *hpriv = ap->host->private_data;
 
-	switch (sc_reg_in) {
-	case SCR_STATUS:	sc_reg = 0; break;
-	case SCR_CONTROL:	sc_reg = 1; break;
-	case SCR_ERROR:		sc_reg = 2; break;
-	case SCR_ACTIVE:	sc_reg = 3; break;
-	default:
-		return 0xffffffffU;
-	}
-
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	if (sc_reg < ARRAY_SIZE(offset) &&
+	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+		return offset[sc_reg];
+	return 0;
 }
 
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
-			       u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
-	unsigned int sc_reg;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	int offset = ahci_scr_offset(ap, sc_reg);
 
-	switch (sc_reg_in) {
-	case SCR_STATUS:	sc_reg = 0; break;
-	case SCR_CONTROL:	sc_reg = 1; break;
-	case SCR_ERROR:		sc_reg = 2; break;
-	case SCR_ACTIVE:	sc_reg = 3; break;
-	default:
-		return;
+	if (offset) {
+		*val = readl(port_mmio + offset);
+		return 0;
 	}
+	return -EINVAL;
+}
 
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	int offset = ahci_scr_offset(ap, sc_reg);
+
+	if (offset) {
+		writel(val, port_mmio + offset);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static void ahci_start_engine(struct ata_port *ap)
@@ -948,37 +965,87 @@
 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
 	struct ahci_host_priv *hpriv = ap->host->private_data;
 	u32 tmp;
+	int busy, rc;
 
-	if (!(hpriv->cap & HOST_CAP_CLO))
-		return -EOPNOTSUPP;
+	/* do we need to kick the port? */
+	busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+	if (!busy && !force_restart)
+		return 0;
 
+	/* stop engine */
+	rc = ahci_stop_engine(ap);
+	if (rc)
+		goto out_restart;
+
+	/* need to do CLO? */
+	if (!busy) {
+		rc = 0;
+		goto out_restart;
+	}
+
+	if (!(hpriv->cap & HOST_CAP_CLO)) {
+		rc = -EOPNOTSUPP;
+		goto out_restart;
+	}
+
+	/* perform CLO */
 	tmp = readl(port_mmio + PORT_CMD);
 	tmp |= PORT_CMD_CLO;
 	writel(tmp, port_mmio + PORT_CMD);
 
+	rc = 0;
 	tmp = ata_wait_register(port_mmio + PORT_CMD,
 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
 	if (tmp & PORT_CMD_CLO)
-		return -EIO;
+		rc = -EIO;
+
+	/* restart engine */
+ out_restart:
+	ahci_start_engine(ap);
+	return rc;
+}
+
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+				struct ata_taskfile *tf, int is_cmd, u16 flags,
+				unsigned long timeout_msec)
+{
+	const u32 cmd_fis_len = 5; /* five dwords */
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u8 *fis = pp->cmd_tbl;
+	u32 tmp;
+
+	/* prep the command */
+	ata_tf_to_fis(tf, pmp, is_cmd, fis);
+	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+	/* issue & wait */
+	writel(1, port_mmio + PORT_CMD_ISSUE);
+
+	if (timeout_msec) {
+		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+					1, timeout_msec);
+		if (tmp & 0x1) {
+			ahci_kick_engine(ap, 1);
+			return -EBUSY;
+		}
+	} else
+		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
 
 	return 0;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
-			  unsigned long deadline)
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+			     int pmp, unsigned long deadline)
 {
-	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *port_mmio = ahci_port_base(ap);
-	const u32 cmd_fis_len = 5; /* five dwords */
 	const char *reason = NULL;
+	unsigned long now, msecs;
 	struct ata_taskfile tf;
-	u32 tmp;
-	u8 *fis;
 	int rc;
 
 	DPRINTK("ENTER\n");
@@ -990,43 +1057,22 @@
 	}
 
 	/* prepare for SRST (AHCI-1.1 10.4.1) */
-	rc = ahci_stop_engine(ap);
-	if (rc) {
-		reason = "failed to stop engine";
-		goto fail_restart;
-	}
-
-	/* check BUSY/DRQ, perform Command List Override if necessary */
-	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-		rc = ahci_clo(ap);
-
-		if (rc == -EOPNOTSUPP) {
-			reason = "port busy but CLO unavailable";
-			goto fail_restart;
-		} else if (rc) {
-			reason = "port busy but CLO failed";
-			goto fail_restart;
-		}
-	}
-
-	/* restart engine */
-	ahci_start_engine(ap);
+	rc = ahci_kick_engine(ap, 1);
+	if (rc)
+		ata_port_printk(ap, KERN_WARNING,
+				"failed to reset engine (errno=%d)", rc);
 
 	ata_tf_init(ap->device, &tf);
-	fis = pp->cmd_tbl;
 
 	/* issue the first D2H Register FIS */
-	ahci_fill_cmd_slot(pp, 0,
-			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+	msecs = 0;
+	now = jiffies;
+	if (time_after(now, deadline))
+		msecs = jiffies_to_msecs(deadline - now);
 
 	tf.ctl |= ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-
-	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
-	if (tmp & 0x1) {
+	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
 		rc = -EIO;
 		reason = "1st FIS failed";
 		goto fail;
@@ -1036,14 +1082,8 @@
 	msleep(1);
 
 	/* issue the second D2H Register FIS */
-	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
 	tf.ctl &= ~ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
+	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
 	/* spec mandates ">= 2ms" before checking status.
 	 * We wait 150ms, because that was the magic delay used for
@@ -1066,13 +1106,17 @@
 	DPRINTK("EXIT, class=%u\n", *class);
 	return 0;
 
- fail_restart:
-	ahci_start_engine(ap);
  fail:
 	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
 	return rc;
 }
 
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+			  unsigned long deadline)
+{
+	return ahci_do_softreset(ap, class, 0, deadline);
+}
+
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
 			  unsigned long deadline)
 {
@@ -1088,7 +1132,7 @@
 	/* clear D2H reception area to properly wait for D2H FIS */
 	ata_tf_init(ap->device, &tf);
 	tf.command = 0x80;
-	ata_tf_to_fis(&tf, d2h_fis, 0);
+	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
 	rc = sata_std_hardreset(ap, class, deadline);
 
@@ -1106,6 +1150,7 @@
 static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
 				 unsigned long deadline)
 {
+	u32 serror;
 	int rc;
 
 	DPRINTK("ENTER\n");
@@ -1116,7 +1161,8 @@
 				 deadline);
 
 	/* vt8251 needs SError cleared for the port to operate */
-	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+	ahci_scr_read(ap, SCR_ERROR, &serror);
+	ahci_scr_write(ap, SCR_ERROR, serror);
 
 	ahci_start_engine(ap);
 
@@ -1205,7 +1251,7 @@
 	 */
 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
 	if (is_atapi) {
 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1238,7 +1284,7 @@
 	ata_ehi_clear_desc(ehi);
 
 	/* AHCI needs SError cleared; otherwise, it might lock up */
-	serror = ahci_scr_read(ap, SCR_ERROR);
+	ahci_scr_read(ap, SCR_ERROR, &serror);
 	ahci_scr_write(ap, SCR_ERROR, serror);
 
 	/* analyze @irq_stat */
@@ -1262,12 +1308,12 @@
 	if (irq_stat & PORT_IRQ_IF_ERR) {
 		err_mask |= AC_ERR_ATA_BUS;
 		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, ", interface fatal error");
+		ata_ehi_push_desc(ehi, "interface fatal error");
 	}
 
 	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
 		ata_ehi_hotplugged(ehi);
-		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+		ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
 			"connection status changed" : "PHY RDY changed");
 	}
 
@@ -1276,7 +1322,7 @@
 
 		err_mask |= AC_ERR_HSM;
 		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+		ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
 				  unk[0], unk[1], unk[2], unk[3]);
 	}
 
@@ -1512,11 +1558,17 @@
 {
 	struct ata_port *ap = qc->ap;
 
-	if (qc->flags & ATA_QCFLAG_FAILED) {
-		/* make DMA engine forget about the failed command */
-		ahci_stop_engine(ap);
-		ahci_start_engine(ap);
-	}
+	/* make DMA engine forget about the failed command */
+	if (qc->flags & ATA_QCFLAG_FAILED)
+		ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+	ahci_power_up(ap);
+	ahci_start_port(ap);
+
+	return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1536,14 +1588,6 @@
 	return rc;
 }
 
-static int ahci_port_resume(struct ata_port *ap)
-{
-	ahci_power_up(ap);
-	ahci_start_port(ap);
-
-	return 0;
-}
-
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1734,12 +1778,13 @@
 
 	dev_printk(KERN_INFO, &pdev->dev,
 		"flags: "
-	       	"%s%s%s%s%s%s"
-	       	"%s%s%s%s%s%s%s\n"
+		"%s%s%s%s%s%s%s"
+		"%s%s%s%s%s%s%s\n"
 	       	,
 
 		cap & (1 << 31) ? "64bit " : "",
 		cap & (1 << 30) ? "ncq " : "",
+		cap & (1 << 29) ? "sntf " : "",
 		cap & (1 << 28) ? "ilck " : "",
 		cap & (1 << 27) ? "stag " : "",
 		cap & (1 << 26) ? "pm " : "",
@@ -1794,7 +1839,7 @@
 	ahci_save_initial_config(pdev, &pi, hpriv);
 
 	/* prepare host */
-	if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+	if (hpriv->cap & HOST_CAP_NCQ)
 		pi.flags |= ATA_FLAG_NCQ;
 
 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
@@ -1808,10 +1853,8 @@
 		void __iomem *port_mmio = ahci_port_base(ap);
 
 		/* standard SATA port setup */
-		if (hpriv->port_map & (1 << i)) {
+		if (hpriv->port_map & (1 << i))
 			ap->ioaddr.cmd_addr = port_mmio;
-			ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
-		}
 
 		/* disabled/not-implemented port */
 		else
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 88e2dd0..6001aae 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -111,8 +111,9 @@
 /**
  *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *	@tf: Taskfile to convert
- *	@fis: Buffer into which data will output
  *	@pmp: Port multiplier port
+ *	@is_cmd: This FIS is for command
+ *	@fis: Buffer into which data will output
  *
  *	Converts a standard ATA taskfile to a Serial ATA
  *	FIS structure (Register - Host to Device).
@@ -120,12 +121,13 @@
  *	LOCKING:
  *	Inherited from caller.
  */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
 {
-	fis[0] = 0x27;	/* Register - Host to Device FIS */
-	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
-					    bit 7 indicates Command FIS */
+	fis[0] = 0x27;			/* Register - Host to Device FIS */
+	fis[1] = pmp & 0xf;		/* Port multiplier number*/
+	if (is_cmd)
+		fis[1] |= (1 << 7);	/* bit 7 indicates Command FIS */
+
 	fis[2] = tf->command;
 	fis[3] = tf->feature;
 
@@ -2387,21 +2389,35 @@
 	u32 sstatus, spd, mask;
 	int rc, highbit;
 
+	if (!sata_scr_valid(ap))
+		return -EOPNOTSUPP;
+
+	/* If SCR can be read, use it to determine the current SPD.
+	 * If not, use cached value in ap->sata_spd.
+	 */
 	rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
-	if (rc)
-		return rc;
+	if (rc == 0)
+		spd = (sstatus >> 4) & 0xf;
+	else
+		spd = ap->sata_spd;
 
 	mask = ap->sata_spd_limit;
 	if (mask <= 1)
 		return -EINVAL;
+
+	/* unconditionally mask off the highest bit */
 	highbit = fls(mask) - 1;
 	mask &= ~(1 << highbit);
 
-	spd = (sstatus >> 4) & 0xf;
-	if (spd <= 1)
-		return -EINVAL;
-	spd--;
-	mask &= (1 << spd) - 1;
+	/* Mask off all speeds higher than or equal to the current
+	 * one.  Force 1.5Gbps if current SPD is not available.
+	 */
+	if (spd > 1)
+		mask &= (1 << (spd - 1)) - 1;
+	else
+		mask &= 1;
+
+	/* were we already at the bottom? */
 	if (!mask)
 		return -EINVAL;
 
@@ -3251,9 +3267,11 @@
 		last = cur;
 		last_jiffies = jiffies;
 
-		/* check deadline */
+		/* Check deadline.  If debouncing failed, return
+		 * -EPIPE to tell upper layer to lower link speed.
+		 */
 		if (time_after(jiffies, deadline))
-			return -EBUSY;
+			return -EPIPE;
 	}
 }
 
@@ -3769,6 +3787,7 @@
 	{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
 	{ "WDC WD740ADFD-00NLR1", NULL,		ATA_HORKAGE_NONCQ, },
 	{ "FUJITSU MHV2080BH",	"00840028",	ATA_HORKAGE_NONCQ, },
+	{ "ST9160821AS",	"3.CLF",	ATA_HORKAGE_NONCQ, },
 
 	/* Devices with NCQ limits */
 
@@ -5729,10 +5748,8 @@
  */
 int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
 {
-	if (sata_scr_valid(ap)) {
-		*val = ap->ops->scr_read(ap, reg);
-		return 0;
-	}
+	if (sata_scr_valid(ap))
+		return ap->ops->scr_read(ap, reg, val);
 	return -EOPNOTSUPP;
 }
 
@@ -5754,10 +5771,8 @@
  */
 int sata_scr_write(struct ata_port *ap, int reg, u32 val)
 {
-	if (sata_scr_valid(ap)) {
-		ap->ops->scr_write(ap, reg, val);
-		return 0;
-	}
+	if (sata_scr_valid(ap))
+		return ap->ops->scr_write(ap, reg, val);
 	return -EOPNOTSUPP;
 }
 
@@ -5778,10 +5793,13 @@
  */
 int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
 {
+	int rc;
+
 	if (sata_scr_valid(ap)) {
-		ap->ops->scr_write(ap, reg, val);
-		ap->ops->scr_read(ap, reg);
-		return 0;
+		rc = ap->ops->scr_write(ap, reg, val);
+		if (rc == 0)
+			rc = ap->ops->scr_read(ap, reg, &val);
+		return rc;
 	}
 	return -EOPNOTSUPP;
 }
@@ -5993,6 +6011,7 @@
 
 	/* SATA spd limit is bound to the first device */
 	ap->sata_spd_limit = ap->hw_sata_spd_limit;
+	ap->sata_spd = 0;
 
 	/* High bits of dev->flags are used to record warm plug
 	 * requests which occur asynchronously.  Synchronize using
@@ -6058,6 +6077,9 @@
 	INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
 	INIT_LIST_HEAD(&ap->eh_done_q);
 	init_waitqueue_head(&ap->eh_wait_q);
+	init_timer_deferrable(&ap->fastdrain_timer);
+	ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+	ap->fastdrain_timer.data = (unsigned long)ap;
 
 	ap->cbl = ATA_CBL_NONE;
 
@@ -6434,7 +6456,7 @@
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
-		ata_scsi_scan_host(ap);
+		ata_scsi_scan_host(ap, 1);
 	}
 
 	return 0;
@@ -6942,6 +6964,9 @@
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_port_abort);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9aa62a0..ac6ceed 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -56,6 +56,7 @@
  */
 enum {
 	ATA_EH_PRERESET_TIMEOUT		= 10 * HZ,
+	ATA_EH_FASTDRAIN_INTERVAL	= 3 * HZ,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -85,6 +86,71 @@
 { }
 #endif /* CONFIG_PM */
 
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+				 va_list args)
+{
+	ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+				     ATA_EH_DESC_LEN - ehi->desc_len,
+				     fmt, args);
+}
+
+/**
+ *	__ata_ehi_push_desc - push error description without adding separator
+ *	@ehi: target EHI
+ *	@fmt: printf format string
+ *
+ *	Format string according to @fmt and append it to @ehi->desc.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	__ata_ehi_pushv_desc(ehi, fmt, args);
+	va_end(args);
+}
+
+/**
+ *	ata_ehi_push_desc - push error description with separator
+ *	@ehi: target EHI
+ *	@fmt: printf format string
+ *
+ *	Format string according to @fmt and append it to @ehi->desc.
+ *	If @ehi->desc is not empty, ", " is added in-between.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+	va_list args;
+
+	if (ehi->desc_len)
+		__ata_ehi_push_desc(ehi, ", ");
+
+	va_start(args, fmt);
+	__ata_ehi_pushv_desc(ehi, fmt, args);
+	va_end(args);
+}
+
+/**
+ *	ata_ehi_clear_desc - clean error description
+ *	@ehi: target EHI
+ *
+ *	Clear @ehi->desc.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+	ehi->desc[0] = '\0';
+	ehi->desc_len = 0;
+}
+
 static void ata_ering_record(struct ata_ering *ering, int is_io,
 			     unsigned int err_mask)
 {
@@ -296,6 +362,9 @@
  repeat:
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
+		/* kill fast drain timer */
+		del_timer_sync(&ap->fastdrain_timer);
+
 		/* process port resume request */
 		ata_eh_handle_port_resume(ap);
 
@@ -511,6 +580,94 @@
 	DPRINTK("EXIT\n");
 }
 
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+	unsigned int tag;
+	int nr = 0;
+
+	/* count only non-internal commands */
+	for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+		if (ata_qc_from_tag(ap, tag))
+			nr++;
+
+	return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+	struct ata_port *ap = (void *)arg;
+	unsigned long flags;
+	int cnt;
+
+	spin_lock_irqsave(ap->lock, flags);
+
+	cnt = ata_eh_nr_in_flight(ap);
+
+	/* are we done? */
+	if (!cnt)
+		goto out_unlock;
+
+	if (cnt == ap->fastdrain_cnt) {
+		unsigned int tag;
+
+		/* No progress during the last interval, tag all
+		 * in-flight qcs as timed out and freeze the port.
+		 */
+		for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+			struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+			if (qc)
+				qc->err_mask |= AC_ERR_TIMEOUT;
+		}
+
+		ata_port_freeze(ap);
+	} else {
+		/* some qcs have finished, give it another chance */
+		ap->fastdrain_cnt = cnt;
+		ap->fastdrain_timer.expires =
+			jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+		add_timer(&ap->fastdrain_timer);
+	}
+
+ out_unlock:
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *	ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ *	@ap: target ATA port
+ *	@fastdrain: activate fast drain
+ *
+ *	Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ *	is non-zero and EH wasn't pending before.  Fast drain ensures
+ *	that EH kicks in in timely manner.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+	int cnt;
+
+	/* already scheduled? */
+	if (ap->pflags & ATA_PFLAG_EH_PENDING)
+		return;
+
+	ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+	if (!fastdrain)
+		return;
+
+	/* do we have in-flight qcs? */
+	cnt = ata_eh_nr_in_flight(ap);
+	if (!cnt)
+		return;
+
+	/* activate fast drain */
+	ap->fastdrain_cnt = cnt;
+	ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+	add_timer(&ap->fastdrain_timer);
+}
+
 /**
  *	ata_qc_schedule_eh - schedule qc for error handling
  *	@qc: command to schedule error handling for
@@ -528,7 +685,7 @@
 	WARN_ON(!ap->ops->error_handler);
 
 	qc->flags |= ATA_QCFLAG_FAILED;
-	qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+	ata_eh_set_pending(ap, 1);
 
 	/* The following will fail if timeout has already expired.
 	 * ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,7 +712,7 @@
 	if (ap->pflags & ATA_PFLAG_INITIALIZING)
 		return;
 
-	ap->pflags |= ATA_PFLAG_EH_PENDING;
+	ata_eh_set_pending(ap, 1);
 	scsi_schedule_eh(ap->scsi_host);
 
 	DPRINTK("port EH scheduled\n");
@@ -579,6 +736,9 @@
 
 	WARN_ON(!ap->ops->error_handler);
 
+	/* we're gonna abort all commands, no need for fast drain */
+	ata_eh_set_pending(ap, 0);
+
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
@@ -1130,7 +1290,7 @@
 	/* we've got the perpetrator, condemn it */
 	qc = __ata_qc_from_tag(ap, tag);
 	memcpy(&qc->result_tf, &tf, sizeof(tf));
-	qc->err_mask |= AC_ERR_DEV;
+	qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
 	ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1413,8 +1573,12 @@
 	if (rc == 0) {
 		ehc->i.serror |= serror;
 		ata_eh_analyze_serror(ap);
-	} else if (rc != -EOPNOTSUPP)
+	} else if (rc != -EOPNOTSUPP) {
+		/* SError read failed, force hardreset and probing */
+		ata_ehi_schedule_probe(&ehc->i);
 		ehc->i.action |= ATA_EH_HARDRESET;
+		ehc->i.err_mask |= AC_ERR_OTHER;
+	}
 
 	/* analyze NCQ failure */
 	ata_eh_analyze_ncq_error(ap);
@@ -1524,14 +1688,14 @@
 			       ehc->i.err_mask, ap->sactive, ehc->i.serror,
 			       ehc->i.action, frozen);
 		if (desc)
-			ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+			ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
 	} else {
 		ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
 				"SAct 0x%x SErr 0x%x action 0x%x%s\n",
 				ehc->i.err_mask, ap->sactive, ehc->i.serror,
 				ehc->i.action, frozen);
 		if (desc)
-			ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+			ata_port_printk(ap, KERN_ERR, "%s\n", desc);
 	}
 
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
@@ -1551,7 +1715,7 @@
 			"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
 			"tag %d cdb 0x%x data %u %s\n         "
 			"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
-			"Emask 0x%x (%s)\n",
+			"Emask 0x%x (%s)%s\n",
 			cmd->command, cmd->feature, cmd->nsect,
 			cmd->lbal, cmd->lbam, cmd->lbah,
 			cmd->hob_feature, cmd->hob_nsect,
@@ -1562,7 +1726,8 @@
 			res->lbal, res->lbam, res->lbah,
 			res->hob_feature, res->hob_nsect,
 			res->hob_lbal, res->hob_lbam, res->hob_lbah,
-			res->device, qc->err_mask, ata_err_string(qc->err_mask));
+			res->device, qc->err_mask, ata_err_string(qc->err_mask),
+			qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
 	}
 }
 
@@ -1648,7 +1813,7 @@
 			} else
 				ata_port_printk(ap, KERN_ERR,
 					"prereset failed (errno=%d)\n", rc);
-			return rc;
+			goto out;
 		}
 	}
 
@@ -1661,7 +1826,8 @@
 		/* prereset told us not to reset, bang classes and return */
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
 			classes[i] = ATA_DEV_NONE;
-		return 0;
+		rc = 0;
+		goto out;
 	}
 
 	/* did prereset() screw up?  if so, fix up to avoid oopsing */
@@ -1697,7 +1863,8 @@
 			ata_port_printk(ap, KERN_ERR,
 					"follow-up softreset required "
 					"but no softreset avaliable\n");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto out;
 		}
 
 		ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1707,7 +1874,8 @@
 		    classes[0] == ATA_DEV_UNKNOWN) {
 			ata_port_printk(ap, KERN_ERR,
 					"classification failed\n");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto out;
 		}
 	}
 
@@ -1724,7 +1892,7 @@
 			schedule_timeout_uninterruptible(delta);
 		}
 
-		if (reset == hardreset &&
+		if (rc == -EPIPE ||
 		    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
 			sata_down_spd_limit(ap);
 		if (hardreset)
@@ -1733,12 +1901,18 @@
 	}
 
 	if (rc == 0) {
+		u32 sstatus;
+
 		/* After the reset, the device state is PIO 0 and the
 		 * controller state is undefined.  Record the mode.
 		 */
 		for (i = 0; i < ATA_MAX_DEVICES; i++)
 			ap->device[i].pio_mode = XFER_PIO_0;
 
+		/* record current link speed */
+		if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
+			ap->sata_spd = (sstatus >> 4) & 0xf;
+
 		if (postreset)
 			postreset(ap, classes);
 
@@ -1746,7 +1920,9 @@
 		ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
 		ehc->i.action |= ATA_EH_REVALIDATE;
 	}
-
+ out:
+	/* clear hotplug flag */
+	ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
 	return rc;
 }
 
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22d..12ac0b5 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2947,17 +2947,22 @@
 	return rc;
 }
 
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
+	int tries = 5;
+	struct ata_device *last_failed_dev = NULL;
+	struct ata_device *dev;
 	unsigned int i;
 
 	if (ap->flags & ATA_FLAG_DISABLED)
 		return;
 
+ repeat:
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
 		struct scsi_device *sdev;
 
+		dev = &ap->device[i];
+
 		if (!ata_dev_enabled(dev) || dev->sdev)
 			continue;
 
@@ -2967,6 +2972,45 @@
 			scsi_device_put(sdev);
 		}
 	}
+
+	/* If we scanned while EH was in progress or allocation
+	 * failure occurred, scan would have failed silently.  Check
+	 * whether all devices are attached.
+	 */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		dev = &ap->device[i];
+		if (ata_dev_enabled(dev) && !dev->sdev)
+			break;
+	}
+	if (i == ATA_MAX_DEVICES)
+		return;
+
+	/* we're missing some SCSI devices */
+	if (sync) {
+		/* If caller requested synchrnous scan && we've made
+		 * any progress, sleep briefly and repeat.
+		 */
+		if (dev != last_failed_dev) {
+			msleep(100);
+			last_failed_dev = dev;
+			goto repeat;
+		}
+
+		/* We might be failing to detect boot device, give it
+		 * a few more chances.
+		 */
+		if (--tries) {
+			msleep(100);
+			goto repeat;
+		}
+
+		ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+				"failed without making any progress,\n"
+				"                  switching to async\n");
+	}
+
+	queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+			   round_jiffies_relative(HZ));
 }
 
 /**
@@ -3093,20 +3137,7 @@
 	}
 
 	/* scan for new ones */
-	ata_scsi_scan_host(ap);
-
-	/* If we scanned while EH was in progress, scan would have
-	 * failed silently.  Requeue if there are enabled but
-	 * unattached devices.
-	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_enabled(dev) && !dev->sdev) {
-			queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
-				round_jiffies_relative(HZ));
-			break;
-		}
-	}
+	ata_scsi_scan_host(ap, 0);
 
 	DPRINTK("EXIT\n");
 }
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index ca7d224..6c289c7 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,5 +1,5 @@
 /*
- *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *  libata-sff.c - helper library for PCI IDE BMDMA
  *
  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
@@ -211,6 +211,8 @@
 		tf->hob_lbal = ioread8(ioaddr->lbal_addr);
 		tf->hob_lbam = ioread8(ioaddr->lbam_addr);
 		tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+		iowrite8(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
 	}
 }
 
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5..564cd23 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -112,7 +112,7 @@
 /* libata-scsi.c */
 extern int ata_scsi_add_hosts(struct ata_host *host,
 			      struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -151,6 +151,7 @@
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
 
 /* libata-sff.c */
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 6bf037d..7dc76e7 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -275,7 +275,7 @@
 
 	for (i = 0; i < 2; i++) {
 		static const int irq[] = { 14, 15 };
-		struct ata_port *ap = host->ports[0];
+		struct ata_port *ap = host->ports[i];
 
 		if (ata_port_is_dummy(ap))
 			continue;
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 79f841b..a909f79 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -213,8 +213,9 @@
 	pata_platform_setup_port(&ap->ioaddr, pp_info);
 
 	/* activate */
-	return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
-				 pp_info->irq_flags, &pata_platform_sht);
+	return ata_host_activate(host, platform_get_irq(pdev, 0),
+				 ata_interrupt, pp_info ? pp_info->irq_flags
+				 : 0, &pata_platform_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index c55667e..36cdbd2 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -238,12 +238,6 @@
 	else
 		offset = 0;	/* 100MHz */
 
-	/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
-	if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
-		printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
-		speed = XFER_UDMA_4;
-	}
-
 	if (speed >= XFER_UDMA_0)
 		idx = speed - XFER_UDMA_0;
 	else
@@ -264,6 +258,17 @@
 		 JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
 }
 
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+	/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+	if (adev->class == ATA_DEV_ATAPI &&
+	    (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+		printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+		mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+	}
+	return ata_pci_default_filter(adev, mask);
+}
+
 /**
  *	scc_tf_load - send taskfile registers to host controller
  *	@ap: Port to which output is sent
@@ -358,6 +363,8 @@
 		tf->hob_lbal = in_be32(ioaddr->lbal_addr);
 		tf->hob_lbam = in_be32(ioaddr->lbam_addr);
 		tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+		out_be32(ioaddr->ctl_addr, tf->ctl);
+		ap->last_ctl = tf->ctl;
 	}
 }
 
@@ -741,7 +748,7 @@
 		return host_stat;
 
 	/* errata A252,A308 workaround: Step4 */
-	if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+	if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
 		return (host_stat | ATA_DMA_INTR);
 
 	/* errata A308 workaround Step5 */
@@ -752,11 +759,11 @@
 		if ((qc->tf.protocol == ATA_PROT_DMA &&
 		     qc->dev->xfer_mode > XFER_UDMA_4)) {
 			if (!(int_status & INTSTS_ACTEINT)) {
-				printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
-				       ap->print_id, retry);
+				printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+				       ap->print_id);
 				host_stat |= ATA_DMA_ERR;
 				if (retry++)
-					ap->udma_mask >>= 1;
+					ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
 			} else
 				retry = 0;
 		}
@@ -1016,7 +1023,7 @@
 	.port_disable		= ata_port_disable,
 	.set_piomode		= scc_set_piomode,
 	.set_dmamode		= scc_set_dmamode,
-	.mode_filter		= ata_pci_default_filter,
+	.mode_filter		= scc_mode_filter,
 
 	.tf_load		= scc_tf_load,
 	.tf_read		= scc_tf_read,
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3de1834..a9c948d 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -190,34 +190,34 @@
 	writew(ctl, idma_ctl);
 }
 
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
 	void __iomem *addr;
-	u32 val;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-		return 0xffffffffU;
+		return -EINVAL;
 
 	addr = scr_addr + scr_map[sc_reg] * 4;
-	val = readl(scr_addr + scr_map[sc_reg] * 4);
+	*val = readl(scr_addr + scr_map[sc_reg] * 4);
 
 	/* this controller has stuck DIAG.N, ignore it */
 	if (sc_reg == SCR_ERROR)
-		val &= ~SERR_PHYRDY_CHG;
-	return val;
+		*val &= ~SERR_PHYRDY_CHG;
+	return 0;
 }
 
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
 	void __iomem *addr;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-		return;
+		return -EINVAL;
 
 	addr = scr_addr + scr_map[sc_reg] * 4;
 	writel(val, scr_addr + scr_map[sc_reg] * 4);
+	return 0;
 }
 
 /*
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index fb8a749..8ec5208 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -35,8 +35,6 @@
 
   6) Add port multiplier support (intermediate)
 
-  7) Test and verify 3.0 Gbps support
-
   8) Develop a low-power-consumption strategy, and implement it.
 
   9) [Experiment, low priority] See if ATAPI can be supported using
@@ -227,26 +225,26 @@
 
 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
-	EDMA_ERR_D_PAR		= (1 << 0),
-	EDMA_ERR_PRD_PAR	= (1 << 1),
-	EDMA_ERR_DEV		= (1 << 2),
-	EDMA_ERR_DEV_DCON	= (1 << 3),
-	EDMA_ERR_DEV_CON	= (1 << 4),
-	EDMA_ERR_SERR		= (1 << 5),
+	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
+	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
+	EDMA_ERR_DEV		= (1 << 2),	/* device error */
+	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
+	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
+	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
 	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
 	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
-	EDMA_ERR_BIST_ASYNC	= (1 << 8),
+	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
 	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
-	EDMA_ERR_CRBQ_PAR	= (1 << 9),
-	EDMA_ERR_CRPB_PAR	= (1 << 10),
-	EDMA_ERR_INTRL_PAR	= (1 << 11),
-	EDMA_ERR_IORDY		= (1 << 12),
-	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),
+	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
+	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
+	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
+	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
+	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
 	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
-	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),
-	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),
-	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),
-	EDMA_ERR_TRANS_PROTO	= (1 << 31),
+	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
+	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
+	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
+	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
 	EDMA_ERR_OVERRUN_5	= (1 << 5),
 	EDMA_ERR_UNDERRUN_5	= (1 << 6),
 	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
@@ -255,7 +253,7 @@
 				  EDMA_ERR_DEV_CON |
 				  EDMA_ERR_SERR |
 				  EDMA_ERR_SELF_DIS |
-				  EDMA_ERR_CRBQ_PAR |
+				  EDMA_ERR_CRQB_PAR |
 				  EDMA_ERR_CRPB_PAR |
 				  EDMA_ERR_INTRL_PAR |
 				  EDMA_ERR_IORDY |
@@ -270,7 +268,7 @@
 				  EDMA_ERR_OVERRUN_5 |
 				  EDMA_ERR_UNDERRUN_5 |
 				  EDMA_ERR_SELF_DIS_5 |
-				  EDMA_ERR_CRBQ_PAR |
+				  EDMA_ERR_CRQB_PAR |
 				  EDMA_ERR_CRPB_PAR |
 				  EDMA_ERR_INTRL_PAR |
 				  EDMA_ERR_IORDY,
@@ -286,10 +284,10 @@
 	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
 	EDMA_RSP_Q_PTR_SHIFT	= 3,
 
-	EDMA_CMD_OFS		= 0x28,
-	EDMA_EN			= (1 << 0),
-	EDMA_DS			= (1 << 1),
-	ATA_RST			= (1 << 2),
+	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
+	EDMA_EN			= (1 << 0),	/* enable EDMA */
+	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
+	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
 
 	EDMA_IORDY_TMOUT	= 0x34,
 	EDMA_ARB_CFG		= 0x38,
@@ -301,14 +299,13 @@
 	MV_HP_ERRATA_60X1B2	= (1 << 3),
 	MV_HP_ERRATA_60X1C0	= (1 << 4),
 	MV_HP_ERRATA_XX42A0	= (1 << 5),
-	MV_HP_GEN_I		= (1 << 6),
-	MV_HP_GEN_II		= (1 << 7),
-	MV_HP_GEN_IIE		= (1 << 8),
+	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
+	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
+	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
 
 	/* Port private flags (pp_flags) */
-	MV_PP_FLAG_EDMA_EN	= (1 << 0),
-	MV_PP_FLAG_EDMA_DS_ACT	= (1 << 1),
-	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),
+	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
+	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -318,8 +315,12 @@
 enum {
 	MV_DMA_BOUNDARY		= 0xffffffffU,
 
+	/* mask of register bits containing lower 32 bits
+	 * of EDMA request queue DMA address
+	 */
 	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
 
+	/* ditto, for response queue */
 	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
 };
 
@@ -403,10 +404,10 @@
 };
 
 static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -823,7 +824,7 @@
 }
 
 /**
- *      mv_stop_dma - Disable eDMA engine
+ *      __mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
  *      Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +833,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
 {
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct mv_port_priv *pp	= ap->private_data;
@@ -865,6 +866,18 @@
 	return err;
 }
 
+static int mv_stop_dma(struct ata_port *ap)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&ap->host->lock, flags);
+	rc = __mv_stop_dma(ap);
+	spin_unlock_irqrestore(&ap->host->lock, flags);
+
+	return rc;
+}
+
 #ifdef ATA_DEBUG
 static void mv_dump_mem(void __iomem *start, unsigned bytes)
 {
@@ -961,22 +974,26 @@
 	return ofs;
 }
 
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-	if (0xffffffffU != ofs)
-		return readl(mv_ap_base(ap) + ofs);
-	else
-		return (u32) ofs;
+	if (ofs != 0xffffffffU) {
+		*val = readl(mv_ap_base(ap) + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-	if (0xffffffffU != ofs)
+	if (ofs != 0xffffffffU) {
 		writelfl(val, mv_ap_base(ap) + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1046,7 @@
 	void __iomem *port_mmio = mv_ap_base(ap);
 	void *mem;
 	dma_addr_t mem_dma;
+	unsigned long flags;
 	int rc;
 
 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1085,14 @@
 	pp->sg_tbl = mem;
 	pp->sg_tbl_dma = mem_dma;
 
+	spin_lock_irqsave(&ap->host->lock, flags);
+
 	mv_edma_cfg(ap, hpriv, port_mmio);
 
 	mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
+	spin_unlock_irqrestore(&ap->host->lock, flags);
+
 	/* Don't turn on EDMA here...do it before DMA commands only.  Else
 	 * we'll be unable to send non-data, PIO, etc due to restricted access
 	 * to shadow regs.
@@ -1090,11 +1112,7 @@
  */
 static void mv_port_stop(struct ata_port *ap)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ap->host->lock, flags);
 	mv_stop_dma(ap);
-	spin_unlock_irqrestore(&ap->host->lock, flags);
 }
 
 /**
@@ -1325,7 +1343,7 @@
 		 * port.  Turn off EDMA so there won't be problems accessing
 		 * shadow block, etc registers.
 		 */
-		mv_stop_dma(ap);
+		__mv_stop_dma(ap);
 		return ata_qc_issue_prot(qc);
 	}
 
@@ -1393,16 +1411,16 @@
 	if (edma_err_cause & EDMA_ERR_DEV)
 		err_mask |= AC_ERR_DEV;
 	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
-			EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
 			EDMA_ERR_INTRL_PAR)) {
 		err_mask |= AC_ERR_ATA_BUS;
 		action |= ATA_EH_HARDRESET;
-		ata_ehi_push_desc(ehi, ", parity error");
+		ata_ehi_push_desc(ehi, "parity error");
 	}
 	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
 		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
-			", dev disconnect" : ", dev connect");
+			"dev disconnect" : "dev connect");
 	}
 
 	if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1429,7 @@
 		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
 			struct mv_port_priv *pp	= ap->private_data;
 			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-			ata_ehi_push_desc(ehi, ", EDMA self-disable");
+			ata_ehi_push_desc(ehi, "EDMA self-disable");
 		}
 	} else {
 		eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,7 +1437,7 @@
 		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
 			struct mv_port_priv *pp	= ap->private_data;
 			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-			ata_ehi_push_desc(ehi, ", EDMA self-disable");
+			ata_ehi_push_desc(ehi, "EDMA self-disable");
 		}
 
 		if (edma_err_cause & EDMA_ERR_SERR) {
@@ -1489,33 +1507,30 @@
 
 	while (1) {
 		u16 status;
+		unsigned int tag;
 
 		/* get s/w response queue last-read pointer, and compare */
 		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
 		if (in_index == out_index)
 			break;
 
-		 
 		/* 50xx: get active ATA command */
-		if (IS_GEN_I(hpriv)) 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+		if (IS_GEN_I(hpriv))
+			tag = ap->active_tag;
 
-		/* 60xx: get active ATA command via tag, to enable support
-		 * for queueing.  this works transparently for queued and
-		 * non-queued modes.
+		/* Gen II/IIE: get active ATA command via tag, to enable
+		 * support for queueing.  this works transparently for
+		 * queued and non-queued modes.
 		 */
-		else {
-			unsigned int tag;
+		else if (IS_GEN_II(hpriv))
+			tag = (le16_to_cpu(pp->crpb[out_index].id)
+				>> CRPB_IOID_SHIFT_6) & 0x3f;
 
-			if (IS_GEN_II(hpriv))
-				tag = (le16_to_cpu(pp->crpb[out_index].id)
-					>> CRPB_IOID_SHIFT_6) & 0x3f;
-			else
-				tag = (le16_to_cpu(pp->crpb[out_index].id)
-					>> CRPB_IOID_SHIFT_7) & 0x3f;
+		else /* IS_GEN_IIE */
+			tag = (le16_to_cpu(pp->crpb[out_index].id)
+				>> CRPB_IOID_SHIFT_7) & 0x3f;
 
-			qc = ata_qc_from_tag(ap, tag);
-		}
+		qc = ata_qc_from_tag(ap, tag);
 
 		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
 		 * bits (WARNING: might not necessarily be associated
@@ -1535,7 +1550,7 @@
 			ata_qc_complete(qc);
 		}
 
-		/* advance software response queue pointer, to 
+		/* advance software response queue pointer, to
 		 * indicate (after the loop completes) to hardware
 		 * that we have consumed a response queue entry.
 		 */
@@ -1741,26 +1756,30 @@
 	return ofs;
 }
 
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-	if (ofs != 0xffffffffU)
-		return readl(addr + ofs);
-	else
-		return (u32) ofs;
+	if (ofs != 0xffffffffU) {
+		*val = readl(addr + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-	if (ofs != 0xffffffffU)
+	if (ofs != 0xffffffffU) {
 		writelfl(val, addr + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
 static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,9 +2157,17 @@
 
 	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-	DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
-		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+	{
+		u32 sstatus, serror, scontrol;
+
+		mv_scr_read(ap, SCR_STATUS, &sstatus);
+		mv_scr_read(ap, SCR_ERROR, &serror);
+		mv_scr_read(ap, SCR_CONTROL, &scontrol);
+		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+			"SCtrl 0x%08x\n", status, serror, scontrol);
+	}
+#endif
 
 	/* Issue COMRESET via SControl */
 comreset_retry:
@@ -2164,9 +2191,17 @@
 	    (retry-- > 0))
 		goto comreset_retry;
 
-	DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
-		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+	{
+		u32 sstatus, serror, scontrol;
+
+		mv_scr_read(ap, SCR_STATUS, &sstatus);
+		mv_scr_read(ap, SCR_ERROR, &serror);
+		mv_scr_read(ap, SCR_CONTROL, &scontrol);
+		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
+	}
+#endif
 
 	if (ata_port_offline(ap)) {
 		*class = ATA_DEV_NONE;
@@ -2209,7 +2244,7 @@
 	struct mv_port_priv *pp	= ap->private_data;
 	struct ata_eh_context *ehc = &ap->eh_context;
 	int rc;
-	
+
 	rc = mv_stop_dma(ap);
 	if (rc)
 		ehc->i.action |= ATA_EH_HARDRESET;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index db81e3e..0b58c4d 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -236,8 +236,8 @@
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
@@ -715,19 +715,20 @@
 		int freeze = 0;
 
 		ata_ehi_clear_desc(ehi);
-		ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+		__ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
 		if (flags & NV_CPB_RESP_ATA_ERR) {
-			ata_ehi_push_desc(ehi, ": ATA error");
+			ata_ehi_push_desc(ehi, "ATA error");
 			ehi->err_mask |= AC_ERR_DEV;
 		} else if (flags & NV_CPB_RESP_CMD_ERR) {
-			ata_ehi_push_desc(ehi, ": CMD error");
+			ata_ehi_push_desc(ehi, "CMD error");
 			ehi->err_mask |= AC_ERR_DEV;
 		} else if (flags & NV_CPB_RESP_CPB_ERR) {
-			ata_ehi_push_desc(ehi, ": CPB error");
+			ata_ehi_push_desc(ehi, "CPB error");
 			ehi->err_mask |= AC_ERR_SYSTEM;
 			freeze = 1;
 		} else {
 			/* notifier error, but no error in CPB flags? */
+			ata_ehi_push_desc(ehi, "unknown");
 			ehi->err_mask |= AC_ERR_OTHER;
 			freeze = 1;
 		}
@@ -854,20 +855,21 @@
 				struct ata_eh_info *ehi = &ap->eh_info;
 
 				ata_ehi_clear_desc(ehi);
-				ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+				__ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
 				if (status & NV_ADMA_STAT_TIMEOUT) {
 					ehi->err_mask |= AC_ERR_SYSTEM;
-					ata_ehi_push_desc(ehi, ": timeout");
+					ata_ehi_push_desc(ehi, "timeout");
 				} else if (status & NV_ADMA_STAT_HOTPLUG) {
 					ata_ehi_hotplugged(ehi);
-					ata_ehi_push_desc(ehi, ": hotplug");
+					ata_ehi_push_desc(ehi, "hotplug");
 				} else if (status & NV_ADMA_STAT_HOTUNPLUG) {
 					ata_ehi_hotplugged(ehi);
-					ata_ehi_push_desc(ehi, ": hot unplug");
+					ata_ehi_push_desc(ehi, "hot unplug");
 				} else if (status & NV_ADMA_STAT_SERROR) {
 					/* let libata analyze SError and figure out the cause */
-					ata_ehi_push_desc(ehi, ": SError");
-				}
+					ata_ehi_push_desc(ehi, "SError");
+				} else
+					ata_ehi_push_desc(ehi, "unknown");
 				ata_port_freeze(ap);
 				continue;
 			}
@@ -1391,20 +1393,22 @@
 	return ret;
 }
 
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
-	return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 
 	iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 static void nv_nf2_freeze(struct ata_port *ap)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d2fcb9a..d39ebc2 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -128,8 +128,8 @@
 	dma_addr_t		pkt_dma;
 };
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -427,19 +427,20 @@
 	return ATA_CBL_SATA;
 }
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -642,8 +643,12 @@
 			   | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
 		ac_err_mask |= AC_ERR_HOST_BUS;
 
-	if (sata_scr_valid(ap))
-		ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+	if (sata_scr_valid(ap)) {
+		u32 serror;
+
+		pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+		ehi->serror |= serror;
+	}
 
 	qc->err_mask |= ac_err_mask;
 
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554d..c8f9242 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -111,8 +111,8 @@
 	qs_state_t		state;
 };
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
@@ -255,18 +255,20 @@
 	ata_eng_timeout(ap);
 }
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return ~0U;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+	return 0;
 }
 
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+	return 0;
 }
 
 static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +339,7 @@
 	buf[28] = dflags;
 
 	/* frame information structure (FIS) */
-	ata_tf_to_fis(&qc->tf, &buf[32], 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4..db67637 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -115,8 +115,8 @@
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
 static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
@@ -350,19 +350,26 @@
 	return NULL;
 }
 
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-	if (mmio)
-		return readl(mmio);
-	return 0xffffffffU;
+
+	if (mmio) {
+		*val = readl(mmio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-	if (mmio)
+
+	if (mmio) {
 		writel(val, mmio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
@@ -378,7 +385,7 @@
 		 * controllers continue to assert IRQ as long as
 		 * SError bits are pending.  Clear SError immediately.
 		 */
-		serror = sil_scr_read(ap, SCR_ERROR);
+		sil_scr_read(ap, SCR_ERROR, &serror);
 		sil_scr_write(ap, SCR_ERROR, serror);
 
 		/* Trigger hotplug and accumulate SError only if the
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30..46fbbe7 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -326,8 +326,8 @@
 
 static void sil24_dev_config(struct ata_device *dev);
 static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -464,15 +464,15 @@
 		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-	struct sil24_port_priv *pp = ap->private_data;
 	void __iomem *port = ap->ioaddr.cmd_addr;
-	struct sil24_prb __iomem *prb = port;
+	struct sil24_prb __iomem *prb;
 	u8 fis[6 * 4];
 
-	memcpy_fromio(fis, prb->fis, 6 * 4);
-	ata_tf_from_fis(fis, &pp->tf);
+	prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+	memcpy_fromio(fis, prb->fis, sizeof(fis));
+	ata_tf_from_fis(fis, tf);
 }
 
 static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +488,30 @@
 	[SCR_ACTIVE]	= 3,
 };
 
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
 		addr = scr_addr + sil24_scr_map[sc_reg] * 4;
-		return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+		*val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+		return 0;
 	}
-	return 0xffffffffU;
+	return -EINVAL;
 }
 
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
 		addr = scr_addr + sil24_scr_map[sc_reg] * 4;
 		writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+		return 0;
 	}
+	return -EINVAL;
 }
 
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -531,15 +536,60 @@
 	return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
-			   unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+				 const struct ata_taskfile *tf,
+				 int is_cmd, u32 ctrl,
+				 unsigned long timeout_msec)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
-	u32 mask, irq_stat;
+	u32 irq_enabled, irq_mask, irq_stat;
+	int rc;
+
+	prb->ctrl = cpu_to_le16(ctrl);
+	ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+	/* temporarily plug completion and error interrupts */
+	irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+	writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+				     10, timeout_msec);
+
+	writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+	irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+	if (irq_stat & PORT_IRQ_COMPLETE)
+		rc = 0;
+	else {
+		/* force port into known state */
+		sil24_init_port(ap);
+
+		if (irq_stat & PORT_IRQ_ERROR)
+			rc = -EIO;
+		else
+			rc = -EBUSY;
+	}
+
+	/* restore IRQ enabled */
+	writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+	return rc;
+}
+
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+			      int pmp, unsigned long deadline)
+{
+	unsigned long timeout_msec = 0;
+	struct ata_taskfile tf;
 	const char *reason;
+	int rc;
 
 	DPRINTK("ENTER\n");
 
@@ -556,29 +606,22 @@
 	}
 
 	/* do SRST */
-	prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
-	prb->fis[1] = 0; /* no PMP yet */
+	if (time_after(deadline, jiffies))
+		timeout_msec = jiffies_to_msecs(deadline - jiffies);
 
-	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
-	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
-	mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
-				     100, jiffies_to_msecs(deadline - jiffies));
-
-	writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
-	irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
-	if (!(irq_stat & PORT_IRQ_COMPLETE)) {
-		if (irq_stat & PORT_IRQ_ERROR)
-			reason = "SRST command error";
-		else
-			reason = "timeout";
+	ata_tf_init(ap->device, &tf);	/* doesn't really matter */
+	rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+				   timeout_msec);
+	if (rc == -EBUSY) {
+		reason = "timeout";
+		goto err;
+	} else if (rc) {
+		reason = "SRST command error";
 		goto err;
 	}
 
-	sil24_update_tf(ap);
-	*class = ata_dev_classify(&pp->tf);
+	sil24_read_tf(ap, 0, &tf);
+	*class = ata_dev_classify(&tf);
 
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
@@ -592,6 +635,12 @@
 	return -EIO;
 }
 
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+			   unsigned long deadline)
+{
+	return sil24_do_softreset(ap, class, 0, deadline);
+}
+
 static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
 			   unsigned long deadline)
 {
@@ -699,7 +748,7 @@
 	}
 
 	prb->ctrl = cpu_to_le16(ctrl);
-	ata_tf_to_fis(&qc->tf, prb->fis, 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
 
 	if (qc->flags & ATA_QCFLAG_DMAMAP)
 		sil24_fill_sg(qc, sge);
@@ -754,6 +803,7 @@
 static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	struct ata_eh_info *ehi = &ap->eh_info;
 	int freeze = 0;
 	u32 irq_stat;
@@ -769,16 +819,16 @@
 
 	if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
 		ata_ehi_hotplugged(ehi);
-		ata_ehi_push_desc(ehi, ", %s",
-			       irq_stat & PORT_IRQ_PHYRDY_CHG ?
-			       "PHY RDY changed" : "device exchanged");
+		ata_ehi_push_desc(ehi, "%s",
+				  irq_stat & PORT_IRQ_PHYRDY_CHG ?
+				  "PHY RDY changed" : "device exchanged");
 		freeze = 1;
 	}
 
 	if (irq_stat & PORT_IRQ_UNK_FIS) {
 		ehi->err_mask |= AC_ERR_HSM;
 		ehi->action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi , ", unknown FIS");
+		ata_ehi_push_desc(ehi, "unknown FIS");
 		freeze = 1;
 	}
 
@@ -797,18 +847,18 @@
 		if (ci && ci->desc) {
 			err_mask |= ci->err_mask;
 			action |= ci->action;
-			ata_ehi_push_desc(ehi, ", %s", ci->desc);
+			ata_ehi_push_desc(ehi, "%s", ci->desc);
 		} else {
 			err_mask |= AC_ERR_OTHER;
 			action |= ATA_EH_SOFTRESET;
-			ata_ehi_push_desc(ehi, ", unknown command error %d",
+			ata_ehi_push_desc(ehi, "unknown command error %d",
 					  cerr);
 		}
 
 		/* record error info */
 		qc = ata_qc_from_tag(ap, ap->active_tag);
 		if (qc) {
-			sil24_update_tf(ap);
+			sil24_read_tf(ap, qc->tag, &pp->tf);
 			qc->err_mask |= err_mask;
 		} else
 			ehi->err_mask |= err_mask;
@@ -825,8 +875,11 @@
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
+	struct ata_port *ap = qc->ap;
+	struct sil24_port_priv *pp = ap->private_data;
+
 	if (qc->flags & ATA_QCFLAG_RESULT_TF)
-		sil24_update_tf(qc->ap);
+		sil24_read_tf(ap, qc->tag, &pp->tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 33716b0..31a2f55 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -64,8 +64,8 @@
 };
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
 	{ PCI_VDEVICE(SI, 0x0180), sis_180 },		/* SiS 964/180 */
@@ -207,36 +207,37 @@
 		pci_write_config_dword(pdev, cfg_addr+0x10, val);
 }
 
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u32 val, val2 = 0;
 	u8 pmr;
 
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
 	if (ap->flags & SIS_FLAG_CFGSCR)
 		return sis_scr_cfg_read(ap, sc_reg);
 
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
-	val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
 
 	if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
 	    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
-		val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+		*val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
 
-	return (val | val2) &  0xfffffffb;
+	*val &= 0xfffffffb;
+
+	return 0;
 }
 
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 pmr;
 
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
@@ -248,6 +249,7 @@
 		    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
 			iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
 	}
+	return 0;
 }
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 63fe99af..92e8770 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -103,20 +103,21 @@
 	return 0;
 }
 
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index b52f83a..78c2851 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -57,8 +57,8 @@
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -164,20 +164,22 @@
 	pci_write_config_dword(pdev, cfg_addr, val);
 }
 
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
-	return uli_scr_cfg_read(ap, sc_reg);
+	*val = uli_scr_cfg_read(ap, sc_reg);
+	return 0;
 }
 
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)	//SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
-		return;
+		return -EINVAL;
 
 	uli_scr_cfg_write(ap, sc_reg, val);
+	return 0;
 }
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c412447..86b7bfc 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -72,8 +72,8 @@
 };
 
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -249,18 +249,20 @@
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+		return -EINVAL;
+	*val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+	return 0;
 }
 
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+	return 0;
 }
 
 static void svia_noop_freeze(struct ata_port *ap)
@@ -305,18 +307,19 @@
 
 	/* Resume phy.  This is the old SATA resume sequence */
 	svia_scr_write(ap, SCR_CONTROL, 0x300);
-	svia_scr_read(ap, SCR_CONTROL); /* flush */
+	svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+		svia_scr_read(ap, SCR_STATUS, &sstatus);
+		if ((sstatus & 0xf) != 1)
 			break;
 	} while (time_before(jiffies, timeout));
 
 	/* open code sata_print_link_status() */
-	sstatus = svia_scr_read(ap, SCR_STATUS);
-	scontrol = svia_scr_read(ap, SCR_CONTROL);
+	svia_scr_read(ap, SCR_STATUS, &sstatus);
+	svia_scr_read(ap, SCR_CONTROL, &scontrol);
 
 	online = (sstatus & 0xf) == 0x3;
 
@@ -325,7 +328,7 @@
 			online ? "up" : "down", sstatus, scontrol);
 
 	/* SStatus is read one more time */
-	svia_scr_read(ap, SCR_STATUS);
+	svia_scr_read(ap, SCR_STATUS, &sstatus);
 
 	if (!online) {
 		/* tell EH to bail */
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1b5d81f..24344d0 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,20 +98,21 @@
 			      VSC_SATA_INT_PHY_CHANGE),
 };
 
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index a9ab30f..2b0c601 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -142,6 +142,7 @@
 {
 	dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
 }
+EXPORT_SYMBOL(set_trace_device);
 
 /*
  * We could just take the "tracedata" index into the .tracedata
@@ -162,6 +163,7 @@
 	file_hash_value = hash_string(lineno, file, FILEHASH);
 	set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
 }
+EXPORT_SYMBOL(generate_resume_trace);
 
 extern char __tracedata_start, __tracedata_end;
 static int show_file_hash(unsigned int value)
@@ -170,7 +172,8 @@
 	char *tracedata;
 
 	match = 0;
-	for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+	for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+			tracedata += 2 + sizeof(unsigned long)) {
 		unsigned short lineno = *(unsigned short *)tracedata;
 		const char *file = *(const char **)(tracedata + 2);
 		unsigned int hash = hash_string(lineno, file, FILEHASH);
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 819c829..a7a0990 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
 obj-$(CONFIG_AMIGA_FLOPPY)	+= amiflop.o
+obj-$(CONFIG_PS3_DISK)		+= ps3disk.o
 obj-$(CONFIG_ATARI_FLOPPY)	+= ataflop.o
 obj-$(CONFIG_AMIGA_Z2RAM)	+= z2ram.o
 obj-$(CONFIG_BLK_DEV_RAM)	+= rd.o
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
new file mode 100644
index 0000000..170fb33
--- /dev/null
+++ b/drivers/block/ps3disk.c
@@ -0,0 +1,630 @@
+/*
+ * PS3 Disk Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+#include <asm/firmware.h>
+
+
+#define DEVICE_NAME		"ps3disk"
+
+#define BOUNCE_SIZE		(64*1024)
+
+#define PS3DISK_MAX_DISKS	16
+#define PS3DISK_MINORS		16
+
+
+#define PS3DISK_NAME		"ps3d%c"
+
+
+struct ps3disk_private {
+	spinlock_t lock;		/* Request queue spinlock */
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+	unsigned int blocking_factor;
+	struct request *req;
+	u64 raw_capacity;
+	unsigned char model[ATA_ID_PROD_LEN+1];
+};
+
+
+#define LV1_STORAGE_SEND_ATA_COMMAND	(2)
+#define LV1_STORAGE_ATA_HDDOUT		(0x23)
+
+struct lv1_ata_cmnd_block {
+	u16	features;
+	u16	sector_count;
+	u16	LBA_low;
+	u16	LBA_mid;
+	u16	LBA_high;
+	u8	device;
+	u8	command;
+	u32	is_ext;
+	u32	proto;
+	u32	in_out;
+	u32	size;
+	u64	buffer;
+	u32	arglen;
+};
+
+enum lv1_ata_proto {
+	NON_DATA_PROTO     = 0,
+	PIO_DATA_IN_PROTO  = 1,
+	PIO_DATA_OUT_PROTO = 2,
+	DMA_PROTO = 3
+};
+
+enum lv1_ata_in_out {
+	DIR_WRITE = 0,			/* memory -> device */
+	DIR_READ = 1			/* device -> memory */
+};
+
+static int ps3disk_major;
+
+
+static struct block_device_operations ps3disk_fops = {
+	.owner		= THIS_MODULE,
+};
+
+
+static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
+				   struct request *req, int gather)
+{
+	unsigned int offset = 0;
+	struct bio *bio;
+	sector_t sector;
+	struct bio_vec *bvec;
+	unsigned int i = 0, j;
+	size_t size;
+	void *buf;
+
+	rq_for_each_bio(bio, req) {
+		sector = bio->bi_sector;
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: bio %u: %u segs %u sectors from %lu\n",
+			__func__, __LINE__, i, bio_segments(bio),
+			bio_sectors(bio), sector);
+		bio_for_each_segment(bvec, bio, j) {
+			size = bvec->bv_len;
+			buf = __bio_kmap_atomic(bio, j, KM_IRQ0);
+			if (gather)
+				memcpy(dev->bounce_buf+offset, buf, size);
+			else
+				memcpy(buf, dev->bounce_buf+offset, size);
+			offset += size;
+			flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page);
+			__bio_kunmap_atomic(bio, KM_IRQ0);
+		}
+		i++;
+	}
+}
+
+static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+				     struct request *req)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	int write = rq_data_dir(req), res;
+	const char *op = write ? "write" : "read";
+	u64 start_sector, sectors;
+	unsigned int region_id = dev->regions[dev->region_idx].id;
+
+#ifdef DEBUG
+	unsigned int n = 0;
+	struct bio *bio;
+
+	rq_for_each_bio(bio, req)
+		n++;
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n",
+		__func__, __LINE__, op, n, req->nr_sectors,
+		req->hard_nr_sectors);
+#endif
+
+	start_sector = req->sector * priv->blocking_factor;
+	sectors = req->nr_sectors * priv->blocking_factor;
+	dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+		__func__, __LINE__, op, sectors, start_sector);
+
+	if (write) {
+		ps3disk_scatter_gather(dev, req, 1);
+
+		res = lv1_storage_write(dev->sbd.dev_id, region_id,
+					start_sector, sectors, 0,
+					dev->bounce_lpar, &dev->tag);
+	} else {
+		res = lv1_storage_read(dev->sbd.dev_id, region_id,
+				       start_sector, sectors, 0,
+				       dev->bounce_lpar, &dev->tag);
+	}
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+			__LINE__, op, res);
+		end_request(req, 0);
+		return 0;
+	}
+
+	priv->req = req;
+	return 1;
+}
+
+static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+					struct request *req)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
+
+	res = lv1_storage_send_device_command(dev->sbd.dev_id,
+					      LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
+					      0, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+			__func__, __LINE__, res);
+		end_request(req, 0);
+		return 0;
+	}
+
+	priv->req = req;
+	return 1;
+}
+
+static void ps3disk_do_request(struct ps3_storage_device *dev,
+			       request_queue_t *q)
+{
+	struct request *req;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	while ((req = elv_next_request(q))) {
+		if (blk_fs_request(req)) {
+			if (ps3disk_submit_request_sg(dev, req))
+				break;
+		} else if (req->cmd_type == REQ_TYPE_FLUSH) {
+			if (ps3disk_submit_flush_request(dev, req))
+				break;
+		} else {
+			blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+			end_request(req, 0);
+			continue;
+		}
+	}
+}
+
+static void ps3disk_request(request_queue_t *q)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+	if (priv->req) {
+		dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
+		return;
+	}
+
+	ps3disk_do_request(dev, q);
+}
+
+static irqreturn_t ps3disk_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	struct ps3disk_private *priv;
+	struct request *req;
+	int res, read, uptodate;
+	u64 tag, status;
+	unsigned long num_sectors;
+	const char *op;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+		return IRQ_HANDLED;
+	}
+
+	priv = dev->sbd.core.driver_data;
+	req = priv->req;
+	if (!req) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u non-block layer request completed\n", __func__,
+			__LINE__);
+		dev->lv1_status = status;
+		complete(&dev->done);
+		return IRQ_HANDLED;
+	}
+
+	if (req->cmd_type == REQ_TYPE_FLUSH) {
+		read = 0;
+		num_sectors = req->hard_cur_sectors;
+		op = "flush";
+	} else {
+		read = !rq_data_dir(req);
+		num_sectors = req->nr_sectors;
+		op = read ? "read" : "write";
+	}
+	if (status) {
+		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+			__LINE__, op, status);
+		uptodate = 0;
+	} else {
+		dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+			__LINE__, op);
+		uptodate = 1;
+		if (read)
+			ps3disk_scatter_gather(dev, req, 0);
+	}
+
+	spin_lock(&priv->lock);
+	if (!end_that_request_first(req, uptodate, num_sectors)) {
+		add_disk_randomness(req->rq_disk);
+		blkdev_dequeue_request(req);
+		end_that_request_last(req, uptodate);
+	}
+	priv->req = NULL;
+	ps3disk_do_request(dev, priv->queue);
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int ps3disk_sync_cache(struct ps3_storage_device *dev)
+{
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
+
+	res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+			__func__, __LINE__, res);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+/* ATA helpers copied from drivers/ata/libata-core.c */
+
+static void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+	unsigned int i;
+
+	for (i = 0; i < buf_words; i++)
+		buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+	if (ata_id_has_lba(id)) {
+		if (ata_id_has_lba48(id))
+			return ata_id_u64(id, 100);
+		else
+			return ata_id_u32(id, 60);
+	} else {
+		if (ata_id_current_chs_valid(id))
+			return ata_id_u32(id, 57);
+		else
+			return id[1] * id[3] * id[6];
+	}
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
+			  unsigned int len)
+{
+	unsigned int c;
+
+	while (len > 0) {
+		c = id[ofs] >> 8;
+		*s = c;
+		s++;
+
+		c = id[ofs] & 0xff;
+		*s = c;
+		s++;
+
+		ofs++;
+		len -= 2;
+	}
+}
+
+static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
+			    unsigned int len)
+{
+	unsigned char *p;
+
+	WARN_ON(!(len & 1));
+
+	ata_id_string(id, s, ofs, len - 1);
+
+	p = s + strnlen(s, len - 1);
+	while (p > s && p[-1] == ' ')
+		p--;
+	*p = '\0';
+}
+
+static int ps3disk_identify(struct ps3_storage_device *dev)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	struct lv1_ata_cmnd_block ata_cmnd;
+	u16 *id = dev->bounce_buf;
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
+
+	memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
+	ata_cmnd.command = ATA_CMD_ID_ATA;
+	ata_cmnd.sector_count = 1;
+	ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
+	ata_cmnd.buffer = dev->bounce_lpar;
+	ata_cmnd.proto = PIO_DATA_IN_PROTO;
+	ata_cmnd.in_out = DIR_READ;
+
+	res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
+				   ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
+				   sizeof(ata_cmnd), ata_cmnd.buffer,
+				   ata_cmnd.arglen);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+			__func__, __LINE__, res);
+		return -EIO;
+	}
+
+	swap_buf_le16(id, ATA_ID_WORDS);
+
+	/* All we're interested in are raw capacity and model name */
+	priv->raw_capacity = ata_id_n_sectors(id);
+	ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
+	return 0;
+}
+
+static void ps3disk_prepare_flush(request_queue_t *q, struct request *req)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	memset(req->cmd, 0, sizeof(req->cmd));
+	req->cmd_type = REQ_TYPE_FLUSH;
+}
+
+static int ps3disk_issue_flush(request_queue_t *q, struct gendisk *gendisk,
+			       sector_t *sector)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+	struct request *req;
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	req = blk_get_request(q, WRITE, __GFP_WAIT);
+	ps3disk_prepare_flush(q, req);
+	res = blk_execute_rq(q, gendisk, req, 0);
+	if (res)
+		dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
+			__func__, __LINE__, res);
+	blk_put_request(req);
+	return res;
+}
+
+
+static unsigned long ps3disk_mask;
+
+static DEFINE_MUTEX(ps3disk_mask_mutex);
+
+static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3disk_private *priv;
+	int error;
+	unsigned int devidx;
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+
+	if (dev->blk_size < 512) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: cannot handle block size %lu\n", __func__,
+			__LINE__, dev->blk_size);
+		return -EINVAL;
+	}
+
+	BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
+	mutex_lock(&ps3disk_mask_mutex);
+	devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
+	if (devidx >= PS3DISK_MAX_DISKS) {
+		dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
+			__LINE__);
+		mutex_unlock(&ps3disk_mask_mutex);
+		return -ENOSPC;
+	}
+	__set_bit(devidx, &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dev->sbd.core.driver_data = priv;
+	spin_lock_init(&priv->lock);
+
+	dev->bounce_size = BOUNCE_SIZE;
+	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+	if (!dev->bounce_buf) {
+		error = -ENOMEM;
+		goto fail_free_priv;
+	}
+
+	error = ps3stor_setup(dev, ps3disk_interrupt);
+	if (error)
+		goto fail_free_bounce;
+
+	ps3disk_identify(dev);
+
+	queue = blk_init_queue(ps3disk_request, &priv->lock);
+	if (!queue) {
+		dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+			__func__, __LINE__);
+		error = -ENOMEM;
+		goto fail_teardown;
+	}
+
+	priv->queue = queue;
+	queue->queuedata = dev;
+
+	blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
+
+	blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+	blk_queue_segment_boundary(queue, -1UL);
+	blk_queue_dma_alignment(queue, dev->blk_size-1);
+	blk_queue_hardsect_size(queue, dev->blk_size);
+
+	blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
+	blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
+			  ps3disk_prepare_flush);
+
+	blk_queue_max_phys_segments(queue, -1);
+	blk_queue_max_hw_segments(queue, -1);
+	blk_queue_max_segment_size(queue, dev->bounce_size);
+
+	gendisk = alloc_disk(PS3DISK_MINORS);
+	if (!gendisk) {
+		dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
+			__LINE__);
+		error = -ENOMEM;
+		goto fail_cleanup_queue;
+	}
+
+	priv->gendisk = gendisk;
+	gendisk->major = ps3disk_major;
+	gendisk->first_minor = devidx * PS3DISK_MINORS;
+	gendisk->fops = &ps3disk_fops;
+	gendisk->queue = queue;
+	gendisk->private_data = dev;
+	gendisk->driverfs_dev = &dev->sbd.core;
+	snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
+		 devidx+'a');
+	priv->blocking_factor = dev->blk_size >> 9;
+	set_capacity(gendisk,
+		     dev->regions[dev->region_idx].size*priv->blocking_factor);
+
+	dev_info(&dev->sbd.core,
+		 "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+		 gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
+		 get_capacity(gendisk) >> 11);
+
+	add_disk(gendisk);
+	return 0;
+
+fail_cleanup_queue:
+	blk_cleanup_queue(queue);
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_bounce:
+	kfree(dev->bounce_buf);
+fail_free_priv:
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+fail:
+	mutex_lock(&ps3disk_mask_mutex);
+	__clear_bit(devidx, &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+	return error;
+}
+
+static int ps3disk_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+	mutex_lock(&ps3disk_mask_mutex);
+	__clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+		    &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+	del_gendisk(priv->gendisk);
+	blk_cleanup_queue(priv->queue);
+	put_disk(priv->gendisk);
+	dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
+	ps3disk_sync_cache(dev);
+	ps3stor_teardown(dev);
+	kfree(dev->bounce_buf);
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3disk = {
+	.match_id	= PS3_MATCH_ID_STOR_DISK,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3disk_probe,
+	.remove		= ps3disk_remove,
+	.shutdown	= ps3disk_remove,
+};
+
+
+static int __init ps3disk_init(void)
+{
+	int error;
+
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ENODEV;
+
+	error = register_blkdev(0, DEVICE_NAME);
+	if (error <= 0) {
+		printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
+		       __LINE__, error);
+		return error;
+	}
+	ps3disk_major = error;
+
+	pr_info("%s:%u: registered block device major %d\n", __func__,
+		__LINE__, ps3disk_major);
+
+	error = ps3_system_bus_driver_register(&ps3disk);
+	if (error)
+		unregister_blkdev(ps3disk_major, DEVICE_NAME);
+
+	return error;
+}
+
+static void __exit ps3disk_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3disk);
+	unregister_blkdev(ps3disk_major, DEVICE_NAME);
+}
+
+module_init(ps3disk_init);
+module_exit(ps3disk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Disk Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 2288b55..d50b823 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -64,7 +64,6 @@
 	u64			operations;
 	u32			vdisk_size;
 	u8			vdisk_type;
-	u8			dev_no;
 
 	char			disk_name[32];
 
@@ -703,7 +702,7 @@
 	blk_queue_max_phys_segments(q, port->ring_cookies);
 	blk_queue_max_sectors(q, port->max_xfer_size);
 	g->major = vdc_major;
-	g->first_minor = port->dev_no << PARTITION_SHIFT;
+	g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
 	strcpy(g->disk_name, port->disk_name);
 
 	g->fops = &vdc_fops;
@@ -747,21 +746,16 @@
 {
 	struct mdesc_handle *hp;
 	struct vdc_port *port;
-	const u64 *port_id;
 	int err;
 
 	print_version();
 
 	hp = mdesc_grab();
 
-	port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
 	err = -ENODEV;
-	if (!port_id) {
-		printk(KERN_ERR PFX "Port lacks id property.\n");
-		goto err_out_release_mdesc;
-	}
-	if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
-		printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+	if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+		printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+		       vdev->dev_no);
 		goto err_out_release_mdesc;
 	}
 
@@ -772,16 +766,14 @@
 		goto err_out_release_mdesc;
 	}
 
-	port->dev_no = *port_id;
-
-	if (port->dev_no >= 26)
+	if (vdev->dev_no >= 26)
 		snprintf(port->disk_name, sizeof(port->disk_name),
 			 VDCBLK_NAME "%c%c",
-			 'a' + (port->dev_no / 26) - 1,
-			 'a' + (port->dev_no % 26));
+			 'a' + ((int)vdev->dev_no / 26) - 1,
+			 'a' + ((int)vdev->dev_no % 26));
 	else
 		snprintf(port->disk_name, sizeof(port->disk_name),
-			 VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+			 VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
 
 	err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
 			      vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -849,7 +841,7 @@
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
 
 static struct vio_driver vdc_port_driver = {
 	.id_table	= vdc_port_match,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9e8f214..c8dfd18 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -185,7 +185,7 @@
 
 config MOXA_INTELLIO
 	tristate "Moxa Intellio support"
-	depends on SERIAL_NONSTANDARD
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
 	help
 	  Say Y here if you have a Moxa Intellio multiport serial card.
 
@@ -241,7 +241,7 @@
 
 config SYNCLINKMP
 	tristate "SyncLink Multiport support"
-	depends on SERIAL_NONSTANDARD
+	depends on SERIAL_NONSTANDARD && PCI
 	help
 	  Enable support for the SyncLink Multiport (2 or 4 ports)
 	  serial adapter, running asynchronous and HDLC communications up
@@ -726,7 +726,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+	depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 4e6f387..8fecaf4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -107,6 +107,8 @@
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)		+= tpm/
 
+obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
+
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c
 
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0be700f..ba0e74a 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -29,6 +29,7 @@
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include <linux/clocksource.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
@@ -51,8 +52,34 @@
 
 #define HPET_RANGE_SIZE		1024	/* from HPET spec */
 
+#if BITS_PER_LONG == 64
+#define	write_counter(V, MC)	writeq(V, MC)
+#define	read_counter(MC)	readq(MC)
+#else
+#define	write_counter(V, MC)	writel(V, MC)
+#define	read_counter(MC)	readl(MC)
+#endif
+
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+	return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+        .name           = "hpet",
+        .rating         = 250,
+        .read           = read_hpet,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
 /* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +106,7 @@
 	struct hpets *hp_next;
 	struct hpet __iomem *hp_hpet;
 	unsigned long hp_hpet_phys;
-	struct time_interpolator *hp_interpolator;
+	struct clocksource *hp_clocksource;
 	unsigned long long hp_tick_freq;
 	unsigned long hp_delta;
 	unsigned int hp_ntimer;
@@ -94,13 +121,6 @@
 #define	HPET_PERIODIC		0x0004
 #define	HPET_SHARED_IRQ		0x0008
 
-#if BITS_PER_LONG == 64
-#define	write_counter(V, MC)	writeq(V, MC)
-#define	read_counter(MC)	readq(MC)
-#else
-#define	write_counter(V, MC) 	writel(V, MC)
-#define	read_counter(MC)	readl(MC)
-#endif
 
 #ifndef readq
 static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +757,6 @@
 
 static struct ctl_table_header *sysctl_header;
 
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef	CONFIG_TIME_INTERPOLATION
-	struct time_interpolator *ti;
-
-	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-	if (!ti)
-		return;
-
-	ti->source = TIME_SOURCE_MMIO64;
-	ti->shift = 10;
-	ti->addr = &hpetp->hp_hpet->hpet_mc;
-	ti->frequency = hpetp->hp_tick_freq;
-	ti->drift = HPET_DRIFT;
-	ti->mask = -1;
-
-	hpetp->hp_interpolator = ti;
-	register_time_interpolator(ti);
-#endif
-}
-
 /*
  * Adjustment for when arming the timer with
  * initial conditions.  That is, main counter
@@ -909,7 +908,16 @@
 	}
 
 	hpetp->hp_delta = hpet_calibrate(hpetp);
-	hpet_register_interpolator(hpetp);
+
+	if (!hpet_clocksource) {
+		hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+		CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+		clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+						clocksource_hpet.shift);
+		clocksource_register(&clocksource_hpet);
+		hpetp->hp_clocksource = &clocksource_hpet;
+		hpet_clocksource = &clocksource_hpet;
+	}
 
 	return 0;
 }
@@ -995,7 +1003,7 @@
 
 static int hpet_acpi_remove(struct acpi_device *device, int type)
 {
-	/* XXX need to unregister interpolator, dealloc mem, etc */
+	/* XXX need to unregister clocksource, dealloc mem, etc */
 	return -EINVAL;
 }
 
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b37f1d5..a08f8f9 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -472,7 +472,7 @@
 	}
 }
 
-static int send_open(HvLpIndex remoteLp, void *sem)
+static int __init send_open(HvLpIndex remoteLp, void *sem)
 {
 	return HvCallEvent_signalLpEventFast(remoteLp,
 			HvLpEvent_Type_VirtualIo,
@@ -484,7 +484,7 @@
 			0, 0, 0, 0);
 }
 
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
 {
 	atomic_t wait_flag;
 	int rc;
@@ -552,14 +552,14 @@
 }
 module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
 
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
 {
 	vio_unregister_driver(&hvc_vio_driver);
 }
 module_exit(hvc_vio_exit);
 
 /* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
+static int __init hvc_find_vtys(void)
 {
 	struct device_node *vty;
 	int num_found = 0;
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 4b97eaf..bb09413 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -115,7 +115,7 @@
 module_exit(hvc_rtas_exit);
 
 /* This will happen prior to module init.  There is no tty at this time? */
-static int hvc_rtas_console_init(void)
+static int __init hvc_rtas_console_init(void)
 {
 	rtascons_put_char_token = rtas_token("put-term-char");
 	if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 17f96e0..69d8866 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -210,9 +210,9 @@
 static int hvcs_parm_num_devs = -1;
 module_param(hvcs_parm_num_devs, int, 0);
 
-char hvcs_driver_name[] = "hvcs";
-char hvcs_device_node[] = "hvcs";
-char hvcs_driver_string[]
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
 	= "IBM hvcs (Hypervisor Virtual Console Server) Driver";
 
 /* Status of partner info rescan triggered via sysfs. */
@@ -1092,7 +1092,7 @@
  * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
  * calling this function or you will get deadlock.
  */
-struct hvcs_struct *hvcs_get_by_index(int index)
+static struct hvcs_struct *hvcs_get_by_index(int index)
 {
 	struct hvcs_struct *hvcsd = NULL;
 	unsigned long flags;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7cda04b..2d7cd48 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -41,7 +41,7 @@
 
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
-	depends on HW_RANDOM && X86 && PCI
+	depends on HW_RANDOM && X86_32 && PCI
 	default HW_RANDOM
 	---help---
 	  This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
new file mode 100644
index 0000000..79b6f46
--- /dev/null
+++ b/drivers/char/ps3flash.c
@@ -0,0 +1,440 @@
+/*
+ * PS3 FLASH ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME		"ps3flash"
+
+#define FLASH_BLOCK_SIZE	(256*1024)
+
+
+struct ps3flash_private {
+	struct mutex mutex;	/* Bounce buffer mutex */
+};
+
+static struct ps3_storage_device *ps3flash_dev;
+
+static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+					   u64 lpar, u64 start_sector,
+					   u64 sectors, int write)
+{
+	u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+					     write);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+			__LINE__, write ? "write" : "read", res);
+		return -EIO;
+	}
+	return sectors;
+}
+
+static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
+				     u64 start_sector, u64 sectors,
+				     unsigned int sector_offset)
+{
+	u64 max_sectors, lpar;
+
+	max_sectors = dev->bounce_size / dev->blk_size;
+	if (sectors > max_sectors) {
+		dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+			__func__, __LINE__, max_sectors);
+		sectors = max_sectors;
+	}
+
+	lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
+	return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
+					   0);
+}
+
+static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
+				    u64 start_sector)
+{
+       u64 sectors = dev->bounce_size / dev->blk_size;
+       return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
+					  sectors, 1);
+}
+
+static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	loff_t res;
+
+	mutex_lock(&file->f_mapping->host->i_mutex);
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += dev->regions[dev->region_idx].size*dev->blk_size;
+		break;
+	}
+	if (offset < 0) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	file->f_pos = offset;
+	res = file->f_pos;
+
+out:
+	mutex_unlock(&file->f_mapping->host->i_mutex);
+	return res;
+}
+
+static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *pos)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	struct ps3flash_private *priv = dev->sbd.core.driver_data;
+	u64 size, start_sector, end_sector, offset;
+	ssize_t sectors_read;
+	size_t remaining, n;
+
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
+		__func__, __LINE__, count, *pos, buf);
+
+	size = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (*pos >= size || !count)
+		return 0;
+
+	if (*pos + count > size) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u Truncating count from %zu to %llu\n", __func__,
+			__LINE__, count, size - *pos);
+		count = size - *pos;
+	}
+
+	start_sector = *pos / dev->blk_size;
+	offset = *pos % dev->blk_size;
+	end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+
+	remaining = count;
+	do {
+		mutex_lock(&priv->mutex);
+
+		sectors_read = ps3flash_read_sectors(dev, start_sector,
+						     end_sector-start_sector,
+						     0);
+		if (sectors_read < 0) {
+			mutex_unlock(&priv->mutex);
+			goto fail;
+		}
+
+		n = min(remaining, sectors_read*dev->blk_size-offset);
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
+			__func__, __LINE__, n, dev->bounce_buf+offset, buf);
+		if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
+			mutex_unlock(&priv->mutex);
+			sectors_read = -EFAULT;
+			goto fail;
+		}
+
+		mutex_unlock(&priv->mutex);
+
+		*pos += n;
+		buf += n;
+		remaining -= n;
+		start_sector += sectors_read;
+		offset = 0;
+	} while (remaining > 0);
+
+	return count;
+
+fail:
+	return sectors_read;
+}
+
+static ssize_t ps3flash_write(struct file *file, const char __user *buf,
+			      size_t count, loff_t *pos)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	struct ps3flash_private *priv = dev->sbd.core.driver_data;
+	u64 size, chunk_sectors, start_write_sector, end_write_sector,
+	    end_read_sector, start_read_sector, head, tail, offset;
+	ssize_t res;
+	size_t remaining, n;
+	unsigned int sec_off;
+
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
+		__func__, __LINE__, count, *pos, buf);
+
+	size = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (*pos >= size || !count)
+		return 0;
+
+	if (*pos + count > size) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u Truncating count from %zu to %llu\n", __func__,
+			__LINE__, count, size - *pos);
+		count = size - *pos;
+	}
+
+	chunk_sectors = dev->bounce_size / dev->blk_size;
+
+	start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+	offset = *pos % dev->bounce_size;
+	end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
+			   chunk_sectors;
+
+	end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
+	start_read_sector = (*pos + count) / dev->blk_size;
+
+	/*
+	 * As we have to write in 256 KiB chunks, while we can read in blk_size
+	 * (usually 512 bytes) chunks, we perform the following steps:
+	 *   1. Read from start_write_sector to end_read_sector ("head")
+	 *   2. Read from start_read_sector to end_write_sector ("tail")
+	 *   3. Copy data to buffer
+	 *   4. Write from start_write_sector to end_write_sector
+	 * All of this is complicated by using only one 256 KiB bounce buffer.
+	 */
+
+	head = end_read_sector - start_write_sector;
+	tail = end_write_sector - start_read_sector;
+
+	remaining = count;
+	do {
+		mutex_lock(&priv->mutex);
+
+		if (end_read_sector >= start_read_sector) {
+			/* Merge head and tail */
+			dev_dbg(&dev->sbd.core,
+				"Merged head and tail: %lu sectors at %lu\n",
+				chunk_sectors, start_write_sector);
+			res = ps3flash_read_sectors(dev, start_write_sector,
+						    chunk_sectors, 0);
+			if (res < 0)
+				goto fail;
+		} else {
+			if (head) {
+				/* Read head */
+				dev_dbg(&dev->sbd.core,
+					"head: %lu sectors at %lu\n", head,
+					start_write_sector);
+				res = ps3flash_read_sectors(dev,
+							    start_write_sector,
+							    head, 0);
+				if (res < 0)
+					goto fail;
+			}
+			if (start_read_sector <
+			    start_write_sector+chunk_sectors) {
+				/* Read tail */
+				dev_dbg(&dev->sbd.core,
+					"tail: %lu sectors at %lu\n", tail,
+					start_read_sector);
+				sec_off = start_read_sector-start_write_sector;
+				res = ps3flash_read_sectors(dev,
+							    start_read_sector,
+							    tail, sec_off);
+				if (res < 0)
+					goto fail;
+			}
+		}
+
+		n = min(remaining, dev->bounce_size-offset);
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
+			__func__, __LINE__, n, buf, dev->bounce_buf+offset);
+		if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		res = ps3flash_write_chunk(dev, start_write_sector);
+		if (res < 0)
+			goto fail;
+
+		mutex_unlock(&priv->mutex);
+
+		*pos += n;
+		buf += n;
+		remaining -= n;
+		start_write_sector += chunk_sectors;
+		head = 0;
+		offset = 0;
+	} while (remaining > 0);
+
+	return count;
+
+fail:
+	mutex_unlock(&priv->mutex);
+	return res;
+}
+
+
+static irqreturn_t ps3flash_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	int res;
+	u64 tag, status;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+	} else {
+		dev->lv1_status = status;
+		complete(&dev->done);
+	}
+	return IRQ_HANDLED;
+}
+
+
+static const struct file_operations ps3flash_fops = {
+	.owner	= THIS_MODULE,
+	.llseek	= ps3flash_llseek,
+	.read	= ps3flash_read,
+	.write	= ps3flash_write,
+};
+
+static struct miscdevice ps3flash_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= DEVICE_NAME,
+	.fops	= &ps3flash_fops,
+};
+
+static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3flash_private *priv;
+	int error;
+	unsigned long tmp;
+
+	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
+	if (tmp % FLASH_BLOCK_SIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u region start %lu is not aligned\n", __func__,
+			__LINE__, tmp);
+		return -EINVAL;
+	}
+	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (tmp % FLASH_BLOCK_SIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u region size %lu is not aligned\n", __func__,
+			__LINE__, tmp);
+		return -EINVAL;
+	}
+
+	/* use static buffer, kmalloc cannot allocate 256 KiB */
+	if (!ps3flash_bounce_buffer.address)
+		return -ENODEV;
+
+	if (ps3flash_dev) {
+		dev_err(&dev->sbd.core,
+			"Only one FLASH device is supported\n");
+		return -EBUSY;
+	}
+
+	ps3flash_dev = dev;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dev->sbd.core.driver_data = priv;
+	mutex_init(&priv->mutex);
+
+	dev->bounce_size = ps3flash_bounce_buffer.size;
+	dev->bounce_buf = ps3flash_bounce_buffer.address;
+
+	error = ps3stor_setup(dev, ps3flash_interrupt);
+	if (error)
+		goto fail_free_priv;
+
+	ps3flash_misc.parent = &dev->sbd.core;
+	error = misc_register(&ps3flash_misc);
+	if (error) {
+		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
+			__func__, __LINE__, error);
+		goto fail_teardown;
+	}
+
+	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
+		 __func__, __LINE__, ps3flash_misc.minor);
+	return 0;
+
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_priv:
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+fail:
+	ps3flash_dev = NULL;
+	return error;
+}
+
+static int ps3flash_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+
+	misc_deregister(&ps3flash_misc);
+	ps3stor_teardown(dev);
+	kfree(dev->sbd.core.driver_data);
+	dev->sbd.core.driver_data = NULL;
+	ps3flash_dev = NULL;
+	return 0;
+}
+
+
+static struct ps3_system_bus_driver ps3flash = {
+	.match_id	= PS3_MATCH_ID_STOR_FLASH,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3flash_probe,
+	.remove		= ps3flash_remove,
+	.shutdown	= ps3flash_remove,
+};
+
+
+static int __init ps3flash_init(void)
+{
+	return ps3_system_bus_driver_register(&ps3flash);
+}
+
+static void __exit ps3flash_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3flash);
+}
+
+module_init(ps3flash_init);
+module_exit(ps3flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 22cf7aa..ec6b65e 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -82,16 +82,13 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#if defined(__i386__)
+#ifdef CONFIG_X86
 #include <asm/hpet.h>
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 #include <linux/pci.h>
 #include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
 
 static unsigned long rtc_port;
 static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@
 	unsigned int year, ctrl;
 	char *guess = NULL;
 #endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
-	struct sparc_isa_bridge *isa_br;
-	struct sparc_isa_device *isa_dev;
-#endif
 #else
 	void *r;
 #ifdef RTC_IRQ
@@ -944,7 +937,7 @@
 #endif
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
 			if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@
 			}
 		}
 	}
-#ifdef __sparc_v9__
-	for_each_isa(isa_br) {
-		for_each_isadev(isa_dev, isa_br) {
-			if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
-				rtc_port = isa_dev->resource.start;
-				rtc_irq = isa_dev->irq;
-				goto found;
-			}
-		}
-	}
-#endif
 	rtc_has_irq = 0;
 	printk(KERN_ERR "rtc_init: no PC rtc found\n");
 	return -EIO;
@@ -1020,7 +1002,7 @@
 
 #endif
 
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
 
 	if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@
 	remove_proc_entry ("driver/rtc", NULL);
 	misc_deregister(&rtc_dev);
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	if (rtc_has_irq)
 		free_irq (rtc_irq, &rtc_port);
 #else
@@ -1117,7 +1099,7 @@
 	if (rtc_has_irq)
 		free_irq (RTC_IRQ, NULL);
 #endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
 }
 
 module_init(rtc_init);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c585b47..f1497ce 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2573,16 +2573,10 @@
 	return cy_serial_driver;
 }
 
-static int __init serial167_console_setup(struct console *co, char *options)
-{
-	return 0;
-}
-
 static struct console sercons = {
 	.name = "ttyS",
 	.write = serial167_console_write,
 	.device = serial167_console_device,
-	.setup = serial167_console_setup,
 	.flags = CON_PRINTBUFFER,
 	.index = -1,
 };
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 4eba32b..8677fc6 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -427,7 +427,7 @@
 		return -ENOMEM;
 
 	if ((err = read_log(log)))
-		return err;
+		goto out_free;
 
 	/* now register seq file */
 	err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +435,15 @@
 		seq = file->private_data;
 		seq->private = log;
 	} else {
-		kfree(log->bios_event_log);
-		kfree(log);
+		goto out_free;
 	}
+
+out:
 	return err;
+out_free:
+	kfree(log->bios_event_log);
+	kfree(log);
+	goto out;
 }
 
 const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +465,7 @@
 		return -ENOMEM;
 
 	if ((err = read_log(log)))
-		return err;
+		goto out_free;
 
 	/* now register seq file */
 	err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +473,15 @@
 		seq = file->private_data;
 		seq->private = log;
 	} else {
-		kfree(log->bios_event_log);
-		kfree(log);
+		goto out_free;
 	}
+
+out:
 	return err;
+out_free:
+	kfree(log->bios_event_log);
+	kfree(log);
+	goto out;
 }
 
 const struct file_operations tpm_binary_bios_measurements_ops = {
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bef6d88..e122a0e 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1013,18 +1013,10 @@
 	return scc_driver;
 }
 
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
-	return 0;
-}
-
-
 static struct console sercons = {
 	.name		= "ttyS",
 	.write		= scc_console_write,
 	.device		= scc_console_device,
-	.setup		= scc_console_setup,
 	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
 };
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index a4d81cd..16fb231 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -618,7 +618,7 @@
 
 config SH_WDT
 	tristate "SuperH Watchdog"
-	depends on SUPERH
+	depends on SUPERH && (CPU_SH3 || CPU_SH4)
 	help
 	  This driver adds watchdog support for the integrated watchdog in the
 	  SuperH processors. If you have one of these processors and wish
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index e783dbf..7b46faf 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -71,7 +71,7 @@
 	.rating		= 200,
 	.read		= acpi_pm_read,
 	.mask		= (cycle_t)ACPI_PM_MASK,
-	.mult		= 0, /*to be caluclated*/
+	.mult		= 0, /*to be calculated*/
 	.shift		= 22,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e1e9d9d..f0829b8 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -54,6 +55,7 @@
      */
 
 int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
 
 
     /*
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 75b4d2a..5fe7555 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -471,37 +471,16 @@
 	return 0;
 }
 
-static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos)
-{
-	struct list_head *node;
-	loff_t i = 0;
-
-	list_for_each(node, list)
-		if (i++ == *pos)
-			return node;
-
-	return NULL;
-}
-
-static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos)
-{
-	if (element->next == list)
-		return NULL;
-
-	++(*pos);
-	return element->next;
-}
-
 static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
 
-	return list_get_nth_element(&input_dev_list, pos);
+	return seq_list_start(&input_dev_list, *pos);
 }
 
 static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	return list_get_next_element(&input_dev_list, v, pos);
+	return seq_list_next(v, &input_dev_list, pos);
 }
 
 static void input_devices_seq_stop(struct seq_file *seq, void *v)
@@ -592,13 +571,13 @@
 {
 	/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
 	seq->private = (void *)(unsigned long)*pos;
-	return list_get_nth_element(&input_handler_list, pos);
+	return seq_list_start(&input_handler_list, *pos);
 }
 
 static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	seq->private = (void *)(unsigned long)(*pos + 1);
-	return list_get_next_element(&input_handler_list, v, pos);
+	return seq_list_next(v, &input_handler_list, pos);
 }
 
 static void input_handlers_seq_stop(struct seq_file *seq, void *v)
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 12db72d..e2abe18 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -275,4 +275,11 @@
 	---help---
 	  Say Y here if you want to take advantage of xbox 360 rumble features.
 
+config JOYSTICK_XPAD_LEDS
+	bool "LED Support for Xbox360 controller 'BigX' LED"
+	depends on LEDS_CLASS && JOYSTICK_XPAD
+	---help---
+	  This option enables support for the LED which surrounds the Big X on
+	  XBox 360 controller.
+
 endif
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 244089c..2808039 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -191,13 +191,18 @@
 	unsigned char *idata;		/* input data */
 	dma_addr_t idata_dma;
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 	struct urb *irq_out;		/* urb for interrupt out report */
 	unsigned char *odata;		/* output data */
 	dma_addr_t odata_dma;
+	struct mutex odata_mutex;
 #endif
 
-	char phys[65];			/* physical device path */
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+	struct xpad_led *led;
+#endif
+
+	char phys[64];			/* physical device path */
 
 	int dpad_mapping;		/* map d-pad to buttons or to axes */
 	int xtype;			/* type of xbox device */
@@ -349,7 +354,7 @@
 		     __FUNCTION__, retval);
 }
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
 	int retval;
@@ -376,6 +381,60 @@
 		   __FUNCTION__, retval);
 }
 
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
+{
+	struct usb_endpoint_descriptor *ep_irq_out;
+	int error = -ENOMEM;
+
+	if (xpad->xtype != XTYPE_XBOX360)
+		return 0;
+
+	xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
+				       GFP_ATOMIC, &xpad->odata_dma );
+	if (!xpad->odata)
+		goto fail1;
+
+	mutex_init(&xpad->odata_mutex);
+
+	xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
+	if (!xpad->irq_out)
+		goto fail2;
+
+	ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
+	usb_fill_int_urb(xpad->irq_out, xpad->udev,
+			 usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
+			 xpad->odata, XPAD_PKT_LEN,
+			 xpad_irq_out, xpad, ep_irq_out->bInterval);
+	xpad->irq_out->transfer_dma = xpad->odata_dma;
+	xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	return 0;
+
+ fail2:	usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
+ fail1:	return error;
+}
+
+static void xpad_stop_output(struct usb_xpad *xpad)
+{
+	if (xpad->xtype == XTYPE_XBOX360)
+		usb_kill_urb(xpad->irq_out);
+}
+
+static void xpad_deinit_output(struct usb_xpad *xpad)
+{
+	if (xpad->xtype == XTYPE_XBOX360) {
+		usb_free_urb(xpad->irq_out);
+		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
+				xpad->odata, xpad->odata_dma);
+	}
+}
+#else
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_deinit_output(struct usb_xpad *xpad) {}
+static void xpad_stop_output(struct usb_xpad *xpad) {}
+#endif
+
+#ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data,
 			    struct ff_effect *effect)
 {
@@ -398,64 +457,101 @@
 	return 0;
 }
 
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_ff(struct usb_xpad *xpad)
 {
-	struct usb_endpoint_descriptor *ep_irq_out;
-	int error = -ENOMEM;
+	input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+	return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+	char name[16];
+	struct led_classdev led_cdev;
+	struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+	if (command >= 0 && command < 14) {
+		mutex_lock(&xpad->odata_mutex);
+		xpad->odata[0] = 0x01;
+		xpad->odata[1] = 0x03;
+		xpad->odata[2] = command;
+		usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+		mutex_unlock(&xpad->odata_mutex);
+	}
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+			 enum led_brightness value)
+{
+	struct xpad_led *xpad_led = container_of(led_cdev,
+						 struct xpad_led, led_cdev);
+
+	xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+	static atomic_t led_seq	= ATOMIC_INIT(0);
+	long led_no;
+	struct xpad_led *led;
+	struct led_classdev *led_cdev;
+	int error;
 
 	if (xpad->xtype != XTYPE_XBOX360)
 		return 0;
 
-	xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
-				       GFP_ATOMIC, &xpad->odata_dma );
-	if (!xpad->odata)
-		goto fail1;
+	xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
 
-	xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
-	if (!xpad->irq_out)
-		goto fail2;
+	led_no = (long)atomic_inc_return(&led_seq) - 1;
 
-	ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
-	usb_fill_int_urb(xpad->irq_out, xpad->udev,
-			 usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
-			 xpad->odata, XPAD_PKT_LEN,
-			 xpad_irq_out, xpad, ep_irq_out->bInterval);
-	xpad->irq_out->transfer_dma = xpad->odata_dma;
-	xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+	led->xpad = xpad;
 
-	input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+	led_cdev = &led->led_cdev;
+	led_cdev->name = led->name;
+	led_cdev->brightness_set = xpad_led_set;
 
-	error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
-	if (error)
-		goto fail2;
+	error = led_classdev_register(&xpad->udev->dev, led_cdev);
+	if (error) {
+		kfree(led);
+		xpad->led = NULL;
+		return error;
+	}
+
+	/*
+	 * Light up the segment corresponding to controller number
+	 */
+	xpad_send_led_command(xpad, (led_no % 4) + 2);
 
 	return 0;
-
- fail2:	usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
- fail1:	return error;
 }
 
-static void xpad_stop_ff(struct usb_xpad *xpad)
+static void xpad_led_disconnect(struct usb_xpad *xpad)
 {
-	if (xpad->xtype == XTYPE_XBOX360)
-		usb_kill_urb(xpad->irq_out);
-}
+	struct xpad_led *xpad_led = xpad->led;
 
-static void xpad_deinit_ff(struct usb_xpad *xpad)
-{
-	if (xpad->xtype == XTYPE_XBOX360) {
-		usb_free_urb(xpad->irq_out);
-		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
-				xpad->odata, xpad->odata_dma);
+	if (xpad_led) {
+		led_classdev_unregister(&xpad_led->led_cdev);
+		kfree(xpad_led->name);
 	}
 }
-
 #else
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_stop_ff(struct usb_xpad *xpad) { }
-static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
+static void xpad_led_disconnect(struct usb_xpad *xpad) { }
 #endif
 
+
 static int xpad_open(struct input_dev *dev)
 {
 	struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@
 	struct usb_xpad *xpad = input_get_drvdata(dev);
 
 	usb_kill_urb(xpad->irq_in);
-	xpad_stop_ff(xpad);
+	xpad_stop_output(xpad);
 }
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@
 		for (i = 0; xpad_abs_pad[i] >= 0; i++)
 		    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
 
-	error = xpad_init_ff(intf, xpad);
+	error = xpad_init_output(intf, xpad);
 	if (error)
 		goto fail2;
 
+	error = xpad_init_ff(xpad);
+	if (error)
+		goto fail3;
+
+	error = xpad_led_probe(xpad);
+	if (error)
+		goto fail3;
+
 	ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
 	usb_fill_int_urb(xpad->irq_in, udev,
 			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@
 
 	error = input_register_device(xpad->dev);
 	if (error)
-		goto fail3;
+		goto fail4;
 
 	usb_set_intfdata(intf, xpad);
 	return 0;
 
- fail3:	usb_free_urb(xpad->irq_in);
+ fail4:	usb_free_urb(xpad->irq_in);
+ fail3:	xpad_deinit_output(xpad);
  fail2:	usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
  fail1:	input_free_device(input_dev);
 	kfree(xpad);
@@ -597,8 +702,9 @@
 
 	usb_set_intfdata(intf, NULL);
 	if (xpad) {
+		xpad_led_disconnect(xpad);
 		input_unregister_device(xpad->dev);
-		xpad_deinit_ff(xpad);
+		xpad_deinit_output(xpad);
 		usb_free_urb(xpad->irq_in);
 		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
 				xpad->idata, xpad->idata_dma);
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 31989dc..906bf5e 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -24,7 +24,12 @@
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
 
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -43,7 +48,7 @@
 	if (value > 20 && value < 32767)
 		count = PIT_TICK_RATE / value;
 
-	spin_lock_irqsave(&i8253_beep_lock, flags);
+	spin_lock_irqsave(&i8253_lock, flags);
 
 	if (count) {
 		/* enable counter 2 */
@@ -58,7 +63,7 @@
 		outb(inb_p(0x61) & 0xFC, 0x61);
 	}
 
-	spin_unlock_irqrestore(&i8253_beep_lock, flags);
+	spin_unlock_irqrestore(&i8253_lock, flags);
 
 	return 0;
 }
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e321526..2bea1b2 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -155,6 +155,8 @@
 	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS];
 	int			overflowwarn;	/* overflow warning printed? */
 	int			datalen;	/* size of an USB urb transfer */
+	int			idlecount;      /* number of empty packets */
+	struct work_struct      work;
 };
 
 #define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@
 		(productId == GEYSER4_JIS_PRODUCT_ID);
 }
 
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+	char data[8];
+	int size;
+
+	size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_READ_REQUEST_ID,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+	if (size != 8) {
+		err("Could not do mode read request from device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+
+	/* Apply the mode switch */
+	data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+	size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+	if (size != 8) {
+		err("Could not do mode write request to device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+	struct atp *dev = container_of(work, struct atp, work);
+	struct usb_device *udev = dev->udev;
+
+	dev->idlecount = 0;
+	atp_geyser3_init(udev);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
 			     int *z, int *fingers)
 {
@@ -439,8 +490,8 @@
 		}
 		dev->x_old = x;
 		dev->y_old = y;
-	}
-	else if (!x && !y) {
+
+	} else if (!x && !y) {
 
 		dev->x_old = dev->y_old = -1;
 		input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +500,21 @@
 
 		/* reset the accumulator on release */
 		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+
+		/* Geyser 3 will continue to send packets continually after
+		   the first touch unless reinitialised. Do so if it's been
+		   idle for a while in order to avoid waking the kernel up
+		   several hundred times a second */
+		if (atp_is_geyser_3(dev)) {
+			dev->idlecount++;
+			if (dev->idlecount == 10) {
+				dev->valid = 0;
+				schedule_work(&dev->work);
+			}
+		}
 	}
 
-	input_report_key(dev->input, BTN_LEFT,
-			 !!dev->data[dev->datalen - 1]);
-
+	input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1);
 	input_sync(dev->input);
 
 exit:
@@ -480,6 +541,7 @@
 	struct atp *dev = input_get_drvdata(input);
 
 	usb_kill_urb(dev->urb);
+	cancel_work_sync(&dev->work);
 	dev->open = 0;
 }
 
@@ -528,40 +590,10 @@
 		dev->datalen = 81;
 
 	if (atp_is_geyser_3(dev)) {
-		/*
-		 * By default Geyser 3 device sends standard USB HID mouse
-		 * packets (Report ID 2). This code changes device mode, so it
-		 * sends raw sensor reports (Report ID 5).
-		 */
-		char data[8];
-		int size;
-
-		size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_READ_REQUEST_ID,
-			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode read request from device"
-							" (Geyser 3 mode)");
+		/* switch to raw sensor mode */
+		if (atp_geyser3_init(udev))
 			goto err_free_devs;
-		}
 
-		/* Apply the mode switch */
-		data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
-		size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
-			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode write request to device"
-							" (Geyser 3 mode)");
-			goto err_free_devs;
-		}
 		printk("appletouch Geyser 3 inited.\n");
 	}
 
@@ -636,6 +668,8 @@
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	return 0;
 
  err_free_buffer:
@@ -669,14 +703,17 @@
 static int atp_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct atp *dev = usb_get_intfdata(iface);
+
 	usb_kill_urb(dev->urb);
 	dev->valid = 0;
+
 	return 0;
 }
 
 static int atp_resume(struct usb_interface *iface)
 {
 	struct atp *dev = usb_get_intfdata(iface);
+
 	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
 		return -EIO;
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 1740cad..91109b4 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -109,7 +109,7 @@
 {
 	struct lifebook_data *priv = psmouse->private;
 	struct input_dev *dev1 = psmouse->dev;
-	struct input_dev *dev2 = priv->dev2;
+	struct input_dev *dev2 = priv ? priv->dev2 : NULL;
 	unsigned char *packet = psmouse->packet;
 	int relative_packet = packet[0] & 0x08;
 
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 4fca1e7..702a526 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -366,6 +366,7 @@
 static int __init i8042_pnp_init(void)
 {
 	char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+	int pnp_data_busted = 0;
 	int err;
 
 	if (i8042_nopnp) {
@@ -413,27 +414,48 @@
 #endif
 
 	if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
-	      i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
-		printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+	      i8042_pnp_data_reg != i8042_data_reg) ||
+	    !i8042_pnp_data_reg) {
+		printk(KERN_WARNING
+			"PNP: PS/2 controller has invalid data port %#x; "
+			"using default %#x\n",
 			i8042_pnp_data_reg, i8042_data_reg);
 		i8042_pnp_data_reg = i8042_data_reg;
+		pnp_data_busted = 1;
 	}
 
 	if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
-	      i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
-		printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+	      i8042_pnp_command_reg != i8042_command_reg) ||
+	    !i8042_pnp_command_reg) {
+		printk(KERN_WARNING
+			"PNP: PS/2 controller has invalid command port %#x; "
+			"using default %#x\n",
 			i8042_pnp_command_reg, i8042_command_reg);
 		i8042_pnp_command_reg = i8042_command_reg;
+		pnp_data_busted = 1;
 	}
 
 	if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
-		printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
+		printk(KERN_WARNING
+			"PNP: PS/2 controller doesn't have KBD irq; "
+			"using default %d\n", i8042_kbd_irq);
 		i8042_pnp_kbd_irq = i8042_kbd_irq;
+		pnp_data_busted = 1;
 	}
 
 	if (!i8042_noaux && !i8042_pnp_aux_irq) {
-		printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
-		i8042_pnp_aux_irq = i8042_aux_irq;
+		if (!pnp_data_busted && i8042_pnp_kbd_irq) {
+			printk(KERN_WARNING
+				"PNP: PS/2 appears to have AUX port disabled, "
+				"if this is incorrect please boot with "
+				"i8042.nopnp\n");
+			i8042_noaux = 1;
+		} else {
+			printk(KERN_WARNING
+				"PNP: PS/2 controller doesn't have AUX irq; "
+				"using default %d\n", i8042_aux_irq);
+			i8042_pnp_aux_irq = i8042_aux_irq;
+		}
 	}
 
 	i8042_data_reg = i8042_pnp_data_reg;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6937177..f929fcd 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -54,6 +54,19 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called corgi_ts.
 
+config TOUCHSCREEN_FUJITSU
+	tristate "Fujitsu serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have the Fujitsu touchscreen (such as one
+	  installed in Lifebook P series laptop) connected to your
+	  system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fujitsu-ts.
+
 config TOUCHSCREEN_GUNZE
 	tristate "Gunze AHL-51S touchscreen"
 	select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 2f86d6a..5de8933 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_TOUCHSCREEN_CORGI)		+= corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH)	+= mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o
 obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1c9069c..96581d0 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -95,7 +95,7 @@
 	u16			dummy;		/* for the pwrdown read */
 	struct ts_event		tc;
 
-	struct spi_transfer	xfer[10];
+	struct spi_transfer	xfer[18];
 	struct spi_message	msg[5];
 	struct spi_message	*last_msg;
 	int			msg_idx;
@@ -107,6 +107,8 @@
 	u16			debounce_tol;
 	u16			debounce_rep;
 
+	u16			penirq_recheck_delay_usecs;
+
 	spinlock_t		lock;
 	struct hrtimer		timer;
 	unsigned		pendown:1;	/* P: lock */
@@ -553,6 +555,15 @@
 		return;
 	}
 
+	/* Maybe check the pendown state before reporting. This discards
+	 * false readings when the pen is lifted.
+	 */
+	if (ts->penirq_recheck_delay_usecs) {
+		udelay(ts->penirq_recheck_delay_usecs);
+		if (!ts->get_pendown_state())
+			Rt = 0;
+	}
+
 	/* NOTE: We can't rely on the pressure to determine the pen down
 	 * state, even this controller has a pressure sensor.  The pressure
 	 * value can fluctuate for quite a while after lifting the pen and
@@ -896,6 +907,10 @@
 		ts->filter = ads7846_no_filter;
 	ts->get_pendown_state = pdata->get_pendown_state;
 
+	if (pdata->penirq_recheck_delay_usecs)
+		ts->penirq_recheck_delay_usecs =
+				pdata->penirq_recheck_delay_usecs;
+
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
 
 	input_dev->name = "ADS784x Touchscreen";
@@ -936,6 +951,24 @@
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
+	/* the first sample after switching drivers can be low quality;
+	 * optionally discard it, using a second one after the signals
+	 * have had enough time to stabilize.
+	 */
+	if (pdata->settle_delay_usecs) {
+		x->delay_usecs = pdata->settle_delay_usecs;
+
+		x++;
+		x->tx_buf = &ts->read_y;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &ts->tc.y;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
 	m->complete = ads7846_rx_val;
 	m->context = ts;
 
@@ -954,6 +987,21 @@
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
+	/* ... maybe discard first sample ... */
+	if (pdata->settle_delay_usecs) {
+		x->delay_usecs = pdata->settle_delay_usecs;
+
+		x++;
+		x->tx_buf = &ts->read_x;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &ts->tc.x;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
 	m->complete = ads7846_rx_val;
 	m->context = ts;
 
@@ -973,6 +1021,21 @@
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
+		/* ... maybe discard first sample ... */
+		if (pdata->settle_delay_usecs) {
+			x->delay_usecs = pdata->settle_delay_usecs;
+
+			x++;
+			x->tx_buf = &ts->read_z1;
+			x->len = 1;
+			spi_message_add_tail(x, m);
+
+			x++;
+			x->rx_buf = &ts->tc.z1;
+			x->len = 2;
+			spi_message_add_tail(x, m);
+		}
+
 		m->complete = ads7846_rx_val;
 		m->context = ts;
 
@@ -990,6 +1053,21 @@
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
+		/* ... maybe discard first sample ... */
+		if (pdata->settle_delay_usecs) {
+			x->delay_usecs = pdata->settle_delay_usecs;
+
+			x++;
+			x->tx_buf = &ts->read_z2;
+			x->len = 1;
+			spi_message_add_tail(x, m);
+
+			x++;
+			x->rx_buf = &ts->tc.z2;
+			x->len = 2;
+			spi_message_add_tail(x, m);
+		}
+
 		m->complete = ads7846_rx_val;
 		m->context = ts;
 	}
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644
index 0000000..daf7a4a
--- /dev/null
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[FUJITSU_LENGTH];
+	char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+				     unsigned char data, unsigned int flags)
+{
+	struct fujitsu *fujitsu = serio_get_drvdata(serio);
+	struct input_dev *dev = fujitsu->dev;
+
+	if (fujitsu->idx == 0) {
+		/* resync skip until start of frame */
+		if ((data & 0xf0) != 0x80)
+			return IRQ_HANDLED;
+	} else {
+		/* resync skip garbage */
+		if (data & 0x80) {
+			fujitsu->idx = 0;
+			return IRQ_HANDLED;
+		}
+	}
+
+	fujitsu->data[fujitsu->idx++] = data;
+	if (fujitsu->idx == FUJITSU_LENGTH) {
+		input_report_abs(dev, ABS_X,
+				 (fujitsu->data[2] << 7) | fujitsu->data[1]);
+		input_report_abs(dev, ABS_Y,
+				 (fujitsu->data[4] << 7) | fujitsu->data[3]);
+		input_report_key(dev, BTN_TOUCH,
+				 (fujitsu->data[0] & 0x03) != 2);
+		input_sync(dev);
+		fujitsu->idx = 0;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+	struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+	input_get_device(fujitsu->dev);
+	input_unregister_device(fujitsu->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(fujitsu->dev);
+	kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct fujitsu *fujitsu;
+	struct input_dev *input_dev;
+	int err;
+
+	fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!fujitsu || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	fujitsu->serio = serio;
+	fujitsu->dev = input_dev;
+	snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+		 "%s/input0", serio->phys);
+
+	input_dev->name = "Fujitsu Serial Touchscreen";
+	input_dev->phys = fujitsu->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_FUJITSU;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+	serio_set_drvdata(serio, fujitsu);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(fujitsu->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:
+	serio_close(serio);
+ fail2:
+	serio_set_drvdata(serio, NULL);
+ fail1:
+	input_free_device(input_dev);
+	kfree(fujitsu);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_FUJITSU,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+	.driver		= {
+		.name	= "fujitsu_ts",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= fujitsu_serio_ids,
+	.interrupt	= fujitsu_interrupt,
+	.connect	= fujitsu_connect,
+	.disconnect	= fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+	return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+	serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index cf906c8..66f946a 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,9 +21,7 @@
 
 if ISDN
 
-menu "Old ISDN4Linux"
-
-config ISDN_I4L
+menuconfig ISDN_I4L
 	tristate "Old ISDN4Linux (deprecated)"
 	---help---
 	  This driver allows you to use an ISDN adapter for networking
@@ -45,12 +43,8 @@
 source "drivers/isdn/i4l/Kconfig"
 endif
 
-endmenu
-
-comment "CAPI subsystem"
-
-config ISDN_CAPI
-	tristate "CAPI2.0 support"
+menuconfig ISDN_CAPI
+	tristate "CAPI 2.0 subsystem"
 	help
 	  This provides the CAPI (Common ISDN Application Programming
 	  Interface, a standard making it easy for programs to access ISDN
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 78e6ad8..3fc1a54 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ACT2000
 	tristate "IBM Active 2000 support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  Say Y here if you have an IBM Active 2000 ISDN card. In order to use
 	  this card, additional firmware is necessary, which has to be loaded
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index bcbb650..0017e50 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,9 +1,5 @@
-menu "Siemens Gigaset"
-	depends on ISDN_I4L
-
-config ISDN_DRV_GIGASET
+menuconfig ISDN_DRV_GIGASET
 	tristate "Siemens Gigaset support (isdn)"
-	depends on ISDN_I4L
 	select CRC_CCITT
 	select BITREVERSE
 	help
@@ -55,6 +51,4 @@
 	  features like configuration mode of M105, say yes. If you
 	  care about your device, say no.
 
-endif
-
-endmenu
+endif # ISDN_DRV_GIGASET != n
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 12d91fb..a3b945a 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -1,6 +1,5 @@
 
 menu "Passive cards"
-	depends on ISDN_I4L
 
 config ISDN_DRV_HISAX
 	tristate "HiSax SiemensChipSet driver support"
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index e91c187..36778b2 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -99,7 +99,6 @@
 
 config ISDN_DIVERSION
 	tristate "Support isdn diversion services"
-	depends on ISDN_I4L
 	help
 	  This option allows you to use some supplementary diversion
 	  services in conjunction with the HiSax driver on an EURO/DSS1
@@ -119,13 +118,11 @@
 endmenu
 
 comment "ISDN4Linux hardware drivers"
-	depends on ISDN_I4L
 
 source "drivers/isdn/hisax/Kconfig"
 
 
 menu "Active cards"
-	depends on ISDN_I4L!=n
 
 source "drivers/isdn/icn/Kconfig"
 
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index fcb99f5..89d15ee 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ICN
 	tristate "ICN 2B and 4B support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  This enables support for two kinds of ISDN-cards made by a German
 	  company called ICN.  2B is the standard version for a single ISDN
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index 0933881..ffba6ec 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_PCBIT
 	tristate "PCBIT-D support"
-	depends on ISDN_I4L && ISA && (BROKEN || X86)
+	depends on ISA && (BROKEN || X86)
 	help
 	  This enables support for the PCBIT ISDN-card.  This card is
 	  manufactured in Portugal by Octal.  For running this card,
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index 5346e33..e6510ca 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_SC
 	tristate "Spellcaster support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  This enables support for the Spellcaster BRI ISDN boards.  This
 	  driver currently builds only in a modularized version.
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 2f661e5..6cecc39 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -11,6 +11,7 @@
 config KVM
 	tristate "Kernel-based Virtual Machine (KVM) support"
 	depends on X86 && EXPERIMENTAL
+	select ANON_INODES
 	---help---
 	  Support hosting fully virtualized guest machines using hardware
 	  virtualization extensions.  You will need a fairly recent
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index a7c5e6b..3ac9cbc 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -121,7 +121,7 @@
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:18 - "access" - the user and writable bits of a huge page pde
+ *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
  */
 union kvm_mmu_page_role {
 	unsigned word;
@@ -131,7 +131,7 @@
 		unsigned quadrant : 2;
 		unsigned pad_for_nice_hex_output : 6;
 		unsigned metaphysical : 1;
-		unsigned hugepage_access : 2;
+		unsigned hugepage_access : 3;
 	};
 };
 
@@ -535,8 +535,8 @@
 int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
 		     unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1b206f1..bcbe683 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -238,23 +238,6 @@
 	kvm_arch_ops->vcpu_load(vcpu);
 }
 
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
-	struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
-	mutex_lock(&vcpu->mutex);
-	if (!vcpu->vmcs) {
-		mutex_unlock(&vcpu->mutex);
-		return NULL;
-	}
-	kvm_arch_ops->vcpu_load(vcpu);
-	return vcpu;
-}
-
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
 	kvm_arch_ops->vcpu_put(vcpu);
@@ -663,13 +646,6 @@
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
-	spin_lock(&vcpu->kvm->lock);
-	kvm_mmu_slot_remove_write_access(vcpu, slot);
-	spin_unlock(&vcpu->kvm->lock);
-}
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -792,20 +768,11 @@
 	*memslot = new;
 	++kvm->memory_config_version;
 
+	kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+	kvm_flush_remote_tlbs(kvm);
+
 	spin_unlock(&kvm->lock);
 
-	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-		struct kvm_vcpu *vcpu;
-
-		vcpu = vcpu_load_slot(kvm, i);
-		if (!vcpu)
-			continue;
-		if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
-			do_remove_write_access(vcpu, mem->slot);
-		kvm_mmu_reset_context(vcpu);
-		vcpu_put(vcpu);
-	}
-
 	kvm_free_physmem_slot(&old, &new);
 	return 0;
 
@@ -826,7 +793,6 @@
 	struct kvm_memory_slot *memslot;
 	int r, i;
 	int n;
-	int cleared;
 	unsigned long any = 0;
 
 	spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@
 	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
 		goto out;
 
-	if (any) {
-		cleared = 0;
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			struct kvm_vcpu *vcpu;
-
-			vcpu = vcpu_load_slot(kvm, i);
-			if (!vcpu)
-				continue;
-			if (!cleared) {
-				do_remove_write_access(vcpu, log->slot);
-				memset(memslot->dirty_bitmap, 0, n);
-				cleared = 1;
-			}
-			kvm_arch_ops->tlb_flush(vcpu);
-			vcpu_put(vcpu);
-		}
-	}
+	spin_lock(&kvm->lock);
+	kvm_mmu_slot_remove_write_access(kvm, log->slot);
+	kvm_flush_remote_tlbs(kvm);
+	memset(memslot->dirty_bitmap, 0, n);
+	spin_unlock(&kvm->lock);
 
 	r = 0;
 
@@ -920,13 +874,9 @@
 			break;
 	kvm->naliases = n;
 
-	spin_unlock(&kvm->lock);
+	kvm_mmu_zap_all(kvm);
 
-	vcpu_load(&kvm->vcpus[0]);
-	spin_lock(&kvm->lock);
-	kvm_mmu_zap_all(&kvm->vcpus[0]);
 	spin_unlock(&kvm->lock);
-	vcpu_put(&kvm->vcpus[0]);
 
 	return 0;
 
@@ -1567,7 +1517,7 @@
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
 	return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
@@ -1645,7 +1595,7 @@
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
 	return kvm_arch_ops->set_msr(vcpu, msr_index, data);
 }
@@ -2183,7 +2133,7 @@
  */
 static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 {
-	return set_msr(vcpu, index, *data);
+	return kvm_set_msr(vcpu, index, *data);
 }
 
 /*
@@ -2667,7 +2617,7 @@
 		break;
 	}
 	case KVM_GET_MSRS:
-		r = msr_io(vcpu, argp, get_msr, 1);
+		r = msr_io(vcpu, argp, kvm_get_msr, 1);
 		break;
 	case KVM_SET_MSRS:
 		r = msr_io(vcpu, argp, do_set_msr, 0);
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 1199d3f..1a87ba9 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -154,7 +154,6 @@
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
 static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@
 		kfree(mc->objects[--mc->nobjs]);
 }
 
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+				       int min, gfp_t gfp_flags)
+{
+	struct page *page;
+
+	if (cache->nobjs >= min)
+		return 0;
+	while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+		page = alloc_page(gfp_flags);
+		if (!page)
+			return -ENOMEM;
+		set_page_private(page, 0);
+		cache->objects[cache->nobjs++] = page_address(page);
+	}
+	return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+	while (mc->nobjs)
+		free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
 static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
 {
 	int r;
@@ -237,8 +259,7 @@
 				   rmap_desc_cache, 1, gfp_flags);
 	if (r)
 		goto out;
-	r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
-				   mmu_page_cache, 4, gfp_flags);
+	r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
 	if (r)
 		goto out;
 	r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -266,7 +287,7 @@
 {
 	mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
 	mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
-	mmu_free_memory_cache(&vcpu->mmu_page_cache);
+	mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
 	mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
 }
 
@@ -281,24 +302,15 @@
 	return p;
 }
 
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
-	if (mc->nobjs < KVM_NR_MEM_OBJS)
-		mc->objects[mc->nobjs++] = obj;
-	else
-		kfree(obj);
-}
-
 static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
 {
 	return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
 				      sizeof(struct kvm_pte_chain));
 }
 
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
-			       struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
 {
-	mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+	kfree(pc);
 }
 
 static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +319,9 @@
 				      sizeof(struct kvm_rmap_desc));
 }
 
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
-			       struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
 {
-	mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+	kfree(rd);
 }
 
 /*
@@ -355,8 +366,7 @@
 	}
 }
 
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
-				   struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
 				   struct kvm_rmap_desc *desc,
 				   int i,
 				   struct kvm_rmap_desc *prev_desc)
@@ -376,10 +386,10 @@
 			prev_desc->more = desc->more;
 		else
 			set_page_private(page,(unsigned long)desc->more | 1);
-	mmu_free_rmap_desc(vcpu, desc);
+	mmu_free_rmap_desc(desc);
 }
 
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
 {
 	struct page *page;
 	struct kvm_rmap_desc *desc;
@@ -407,7 +417,7 @@
 		while (desc) {
 			for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
 				if (desc->shadow_ptes[i] == spte) {
-					rmap_desc_remove_entry(vcpu, page,
+					rmap_desc_remove_entry(page,
 							       desc, i,
 							       prev_desc);
 					return;
@@ -442,7 +452,7 @@
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		BUG_ON(!(*spte & PT_WRITABLE_MASK));
 		rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-		rmap_remove(vcpu, spte);
+		rmap_remove(spte);
 		set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
 		kvm_flush_remote_tlbs(vcpu->kvm);
 	}
@@ -464,14 +474,14 @@
 }
 #endif
 
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
 			      struct kvm_mmu_page *page_head)
 {
 	ASSERT(is_empty_shadow_page(page_head->spt));
 	list_del(&page_head->link);
-	mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
-	mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
-	++vcpu->kvm->n_free_mmu_pages;
+	__free_page(virt_to_page(page_head->spt));
+	kfree(page_head);
+	++kvm->n_free_mmu_pages;
 }
 
 static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +547,7 @@
 	pte_chain->parent_ptes[0] = parent_pte;
 }
 
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
-				       struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
 				       u64 *parent_pte)
 {
 	struct kvm_pte_chain *pte_chain;
@@ -565,7 +574,7 @@
 			pte_chain->parent_ptes[i] = NULL;
 			if (i == 0) {
 				hlist_del(&pte_chain->link);
-				mmu_free_pte_chain(vcpu, pte_chain);
+				mmu_free_pte_chain(pte_chain);
 				if (hlist_empty(&page->parent_ptes)) {
 					page->multimapped = 0;
 					page->parent_pte = NULL;
@@ -643,7 +652,7 @@
 	return page;
 }
 
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
 					 struct kvm_mmu_page *page)
 {
 	unsigned i;
@@ -655,10 +664,10 @@
 	if (page->role.level == PT_PAGE_TABLE_LEVEL) {
 		for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
 			if (pt[i] & PT_PRESENT_MASK)
-				rmap_remove(vcpu, &pt[i]);
+				rmap_remove(&pt[i]);
 			pt[i] = 0;
 		}
-		kvm_flush_remote_tlbs(vcpu->kvm);
+		kvm_flush_remote_tlbs(kvm);
 		return;
 	}
 
@@ -669,19 +678,18 @@
 		if (!(ent & PT_PRESENT_MASK))
 			continue;
 		ent &= PT64_BASE_ADDR_MASK;
-		mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+		mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
 	}
-	kvm_flush_remote_tlbs(vcpu->kvm);
+	kvm_flush_remote_tlbs(kvm);
 }
 
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
-			     struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
 			     u64 *parent_pte)
 {
-	mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+	mmu_page_remove_parent_pte(page, parent_pte);
 }
 
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
 			     struct kvm_mmu_page *page)
 {
 	u64 *parent_pte;
@@ -697,15 +705,15 @@
 			parent_pte = chain->parent_ptes[0];
 		}
 		BUG_ON(!parent_pte);
-		kvm_mmu_put_page(vcpu, page, parent_pte);
+		kvm_mmu_put_page(page, parent_pte);
 		set_shadow_pte(parent_pte, 0);
 	}
-	kvm_mmu_page_unlink_children(vcpu, page);
+	kvm_mmu_page_unlink_children(kvm, page);
 	if (!page->root_count) {
 		hlist_del(&page->hash_link);
-		kvm_mmu_free_page(vcpu, page);
+		kvm_mmu_free_page(kvm, page);
 	} else
-		list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+		list_move(&page->link, &kvm->active_mmu_pages);
 }
 
 static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +732,7 @@
 		if (page->gfn == gfn && !page->role.metaphysical) {
 			pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
 				 page->role.word);
-			kvm_mmu_zap_page(vcpu, page);
+			kvm_mmu_zap_page(vcpu->kvm, page);
 			r = 1;
 		}
 	return r;
@@ -737,7 +745,7 @@
 	while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
 		pgprintk("%s: zap %lx %x\n",
 			 __FUNCTION__, gfn, page->role.word);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 }
 
@@ -1089,10 +1097,10 @@
 	pte = *spte;
 	if (is_present_pte(pte)) {
 		if (page->role.level == PT_PAGE_TABLE_LEVEL)
-			rmap_remove(vcpu, spte);
+			rmap_remove(spte);
 		else {
 			child = page_header(pte & PT64_BASE_ADDR_MASK);
-			mmu_page_remove_parent_pte(vcpu, child, spte);
+			mmu_page_remove_parent_pte(child, spte);
 		}
 	}
 	*spte = 0;
@@ -1161,7 +1169,7 @@
 			 */
 			pgprintk("misaligned: gpa %llx bytes %d role %x\n",
 				 gpa, bytes, page->role.word);
-			kvm_mmu_zap_page(vcpu, page);
+			kvm_mmu_zap_page(vcpu->kvm, page);
 			continue;
 		}
 		page_offset = offset;
@@ -1207,7 +1215,7 @@
 
 		page = container_of(vcpu->kvm->active_mmu_pages.prev,
 				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
@@ -1219,7 +1227,7 @@
 	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
 		page = container_of(vcpu->kvm->active_mmu_pages.next,
 				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 	free_page((unsigned long)vcpu->mmu.pae_root);
 }
@@ -1277,9 +1285,8 @@
 	mmu_free_memory_caches(vcpu);
 }
 
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
-	struct kvm *kvm = vcpu->kvm;
 	struct kvm_mmu_page *page;
 
 	list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1300,20 @@
 		for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
 			/* avoid RMW */
 			if (pt[i] & PT_WRITABLE_MASK) {
-				rmap_remove(vcpu, &pt[i]);
+				rmap_remove(&pt[i]);
 				pt[i] &= ~PT_WRITABLE_MASK;
 			}
 	}
 }
 
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
 {
-	destroy_kvm_mmu(vcpu);
+	struct kvm_mmu_page *page, *node;
 
-	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
-		struct kvm_mmu_page *page;
+	list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+		kvm_mmu_zap_page(kvm, page);
 
-		page = container_of(vcpu->kvm->active_mmu_pages.next,
-				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
-	}
-
-	mmu_free_memory_caches(vcpu);
-	kvm_flush_remote_tlbs(vcpu->kvm);
-	init_kvm_mmu(vcpu);
+	kvm_flush_remote_tlbs(kvm);
 }
 
 void kvm_mmu_module_exit(void)
@@ -1322,8 +1322,6 @@
 		kmem_cache_destroy(pte_chain_cache);
 	if (rmap_desc_cache)
 		kmem_cache_destroy(rmap_desc_cache);
-	if (mmu_page_cache)
-		kmem_cache_destroy(mmu_page_cache);
 	if (mmu_page_header_cache)
 		kmem_cache_destroy(mmu_page_header_cache);
 }
@@ -1341,12 +1339,6 @@
 	if (!rmap_desc_cache)
 		goto nomem;
 
-	mmu_page_cache = kmem_cache_create("kvm_mmu_page",
-					   PAGE_SIZE,
-					   PAGE_SIZE, 0, NULL);
-	if (!mmu_page_cache)
-		goto nomem;
-
 	mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
 						  sizeof(struct kvm_mmu_page),
 						  0, 0, NULL);
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index a7c5cb0..4b5391c 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -366,6 +366,8 @@
 			metaphysical = 1;
 			hugepage_access = *guest_ent;
 			hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+			if (*guest_ent & PT64_NX_MASK)
+				hugepage_access |= (1 << 2);
 			hugepage_access >>= PT_WRITABLE_SHIFT;
 			table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
 				>> PAGE_SHIFT;
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index f60012d..1b800fc 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -163,7 +163,7 @@
 	ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0x30 - 0x3F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0x40 - 0x47 */
 	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
 	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@
 	unsigned long modrm_ea;
 	int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
 	int no_wb = 0;
+	u64 msr_data;
 
 	/* Shadow copy of register state. Committed on successful emulation. */
 	unsigned long _regs[NR_VCPU_REGS];
@@ -1344,6 +1345,29 @@
 			goto cannot_emulate;
 		realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
 		break;
+	case 0x30:
+		/* wrmsr */
+		msr_data = (u32)_regs[VCPU_REGS_RAX]
+			| ((u64)_regs[VCPU_REGS_RDX] << 32);
+		rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+		if (rc) {
+			kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+			_eip = ctxt->vcpu->rip;
+		}
+		rc = X86EMUL_CONTINUE;
+		break;
+	case 0x32:
+		/* rdmsr */
+		rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+		if (rc) {
+			kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+			_eip = ctxt->vcpu->rip;
+		} else {
+			_regs[VCPU_REGS_RAX] = (u32)msr_data;
+			_regs[VCPU_REGS_RDX] = msr_data >> 32;
+		}
+		rc = X86EMUL_CONTINUE;
+		break;
 	case 0xc7:		/* Grp9 (cmpxchg8b) */
 		{
 			u64 old, new;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 87d2046..4468cb3 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,9 +1,6 @@
-
-menu "LED devices"
-	depends on HAS_IOMEM
-
-config NEW_LEDS
+menuconfig NEW_LEDS
 	bool "LED Support"
+	depends on HAS_IOMEM
 	help
 	  Say Y to enable Linux LED support.  This allows control of supported
 	  LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@
 	  This is not related to standard keyboard LEDs which are controlled
 	  via the input system.
 
+if NEW_LEDS
+
 config LEDS_CLASS
 	tristate "LED Class Support"
-	depends on NEW_LEDS
 	help
 	  This option enables the led sysfs class in /sys/class/leds.  You'll
 	  need this to do anything useful with LEDs.  If unsure, say N.
@@ -95,11 +93,18 @@
 	help
 	  This option enables support for the front LED on Cobalt Server
 
+config LEDS_GPIO
+	tristate "LED Support for GPIO connected LEDs"
+	depends on LEDS_CLASS && GENERIC_GPIO
+	help
+	  This option enables support for the LEDs connected to GPIO
+	  outputs. To be useful the particular board must have LEDs
+	  and they must be connected to the GPIO lines.
+
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
 	bool "LED Trigger support"
-	depends on NEW_LEDS
 	help
 	  This option enables trigger support for the leds class.
 	  These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +133,4 @@
 	  load average.
 	  If unsure, say Y.
 
-endmenu
-
+endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa2c18e..f8995c9 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)		+= leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT)		+= leds-cobalt.o
+obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c17112..4211293 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -2,7 +2,7 @@
  * LED Class Core
  *
  * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,9 +24,10 @@
 
 static struct class *leds_class;
 
-static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+static ssize_t led_brightness_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	ssize_t ret = 0;
 
 	/* no lock needed for this */
@@ -36,10 +37,10 @@
 	return ret;
 }
 
-static ssize_t led_brightness_store(struct class_device *dev,
-				const char *buf, size_t size)
+static ssize_t led_brightness_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	ssize_t ret = -EINVAL;
 	char *after;
 	unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@
 	return ret;
 }
 
-static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
-			led_brightness_store);
+static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
 #ifdef CONFIG_LEDS_TRIGGERS
-static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
 #endif
 
 /**
@@ -93,16 +93,15 @@
 {
 	int rc;
 
-	led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
-						parent, "%s", led_cdev->name);
-	if (unlikely(IS_ERR(led_cdev->class_dev)))
-		return PTR_ERR(led_cdev->class_dev);
+	led_cdev->dev = device_create(leds_class, parent, 0, "%s",
+					    led_cdev->name);
+	if (unlikely(IS_ERR(led_cdev->dev)))
+		return PTR_ERR(led_cdev->dev);
 
-	class_set_devdata(led_cdev->class_dev, led_cdev);
+	dev_set_drvdata(led_cdev->dev, led_cdev);
 
 	/* register the attributes */
-	rc = class_device_create_file(led_cdev->class_dev,
-				      &class_device_attr_brightness);
+	rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
 	if (rc)
 		goto err_out;
 
@@ -114,8 +113,7 @@
 #ifdef CONFIG_LEDS_TRIGGERS
 	rwlock_init(&led_cdev->trigger_lock);
 
-	rc = class_device_create_file(led_cdev->class_dev,
-				      &class_device_attr_trigger);
+	rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
 	if (rc)
 		goto err_out_led_list;
 
@@ -123,18 +121,17 @@
 #endif
 
 	printk(KERN_INFO "Registered led device: %s\n",
-			led_cdev->class_dev->class_id);
+			led_cdev->name);
 
 	return 0;
 
 #ifdef CONFIG_LEDS_TRIGGERS
 err_out_led_list:
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_brightness);
+	device_remove_file(led_cdev->dev, &dev_attr_brightness);
 	list_del(&led_cdev->node);
 #endif
 err_out:
-	class_device_unregister(led_cdev->class_dev);
+	device_unregister(led_cdev->dev);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@
  */
 void led_classdev_unregister(struct led_classdev *led_cdev)
 {
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_brightness);
+	device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_trigger);
+	device_remove_file(led_cdev->dev, &dev_attr_trigger);
 	write_lock(&led_cdev->trigger_lock);
 	if (led_cdev->trigger)
 		led_trigger_set(led_cdev, NULL);
 	write_unlock(&led_cdev->trigger_lock);
 #endif
 
-	class_device_unregister(led_cdev->class_dev);
+	device_unregister(led_cdev->dev);
 
 	write_lock(&leds_list_lock);
 	list_del(&led_cdev->node);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 454fb09..575368c 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,7 +1,7 @@
 /*
  * LED Triggers Core
  *
- * Copyright 2005-2006 Openedhand Ltd.
+ * Copyright 2005-2007 Openedhand Ltd.
  *
  * Author: Richard Purdie <rpurdie@openedhand.com>
  *
@@ -28,10 +28,10 @@
 static DEFINE_RWLOCK(triggers_list_lock);
 static LIST_HEAD(trigger_list);
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-			size_t count)
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	char trigger_name[TRIG_NAME_MAX];
 	struct led_trigger *trig;
 	size_t len;
@@ -67,9 +67,10 @@
 }
 
 
-ssize_t led_trigger_show(struct class_device *dev, char *buf)
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct led_trigger *trig;
 	int len = 0;
 
@@ -183,13 +184,20 @@
 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 {
 	struct led_trigger *trigger;
+	int err;
 
 	trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
 
 	if (trigger) {
 		trigger->name = name;
-		led_trigger_register(trigger);
-	}
+		err = led_trigger_register(trigger);
+		if (err < 0)
+			printk(KERN_WARNING "LED trigger %s failed to register"
+				" (%d)\n", name, err);
+	} else
+		printk(KERN_WARNING "LED trigger %s failed to register"
+			" (no memory)\n", name);
+
 	*tp = trigger;
 }
 
@@ -215,7 +223,8 @@
 
 void led_trigger_unregister_simple(struct led_trigger *trigger)
 {
-	led_trigger_unregister(trigger);
+	if (trigger)
+		led_trigger_unregister(trigger);
 	kfree(trigger);
 }
 
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 0000000..47d90db
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,199 @@
+/*
+ * LEDs driver for GPIOs
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#include <asm/gpio.h>
+
+struct gpio_led_data {
+	struct led_classdev cdev;
+	unsigned gpio;
+	struct work_struct work;
+	u8 new_level;
+	u8 can_sleep;
+	u8 active_low;
+};
+
+static void gpio_led_work(struct work_struct *work)
+{
+	struct gpio_led_data	*led_dat =
+		container_of(work, struct gpio_led_data, work);
+
+	gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+}
+
+static void gpio_led_set(struct led_classdev *led_cdev,
+	enum led_brightness value)
+{
+	struct gpio_led_data *led_dat =
+		container_of(led_cdev, struct gpio_led_data, cdev);
+	int level;
+
+	if (value == LED_OFF)
+		level = 0;
+	else
+		level = 1;
+
+	if (led_dat->active_low)
+		level = !level;
+
+	/* setting GPIOs with I2C/etc requires a preemptible task context */
+	if (led_dat->can_sleep) {
+		if (preempt_count()) {
+			led_dat->new_level = level;
+			schedule_work(&led_dat->work);
+		} else
+			gpio_set_value_cansleep(led_dat->gpio, level);
+	} else
+		gpio_set_value(led_dat->gpio, level);
+}
+
+static int __init gpio_led_probe(struct platform_device *pdev)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led *cur_led;
+	struct gpio_led_data *leds_data, *led_dat;
+	int i, ret = 0;
+
+	if (!pdata)
+		return -EBUSY;
+
+	leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
+				GFP_KERNEL);
+	if (!leds_data)
+		return -ENOMEM;
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		cur_led = &pdata->leds[i];
+		led_dat = &leds_data[i];
+
+		led_dat->cdev.name = cur_led->name;
+		led_dat->cdev.default_trigger = cur_led->default_trigger;
+		led_dat->gpio = cur_led->gpio;
+		led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+		led_dat->active_low = cur_led->active_low;
+		led_dat->cdev.brightness_set = gpio_led_set;
+		led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+
+		ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
+		if (ret < 0)
+			goto err;
+
+		gpio_direction_output(led_dat->gpio, led_dat->active_low);
+
+		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+		if (ret < 0) {
+			gpio_free(led_dat->gpio);
+			goto err;
+		}
+
+		INIT_WORK(&led_dat->work, gpio_led_work);
+	}
+
+	platform_set_drvdata(pdev, leds_data);
+
+	return 0;
+
+err:
+	if (i > 0) {
+		for (i = i - 1; i >= 0; i--) {
+			led_classdev_unregister(&leds_data[i].cdev);
+			gpio_free(leds_data[i].gpio);
+		}
+	}
+
+	flush_scheduled_work();
+	kfree(leds_data);
+
+	return ret;
+}
+
+static int __exit gpio_led_remove(struct platform_device *pdev)
+{
+	int i;
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		led_classdev_unregister(&leds_data[i].cdev);
+		gpio_free(leds_data[i].gpio);
+	}
+	
+	kfree(leds_data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+	int i;
+	
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++)
+		led_classdev_suspend(&leds_data[i].cdev);
+
+	return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+	int i;
+
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++)
+		led_classdev_resume(&leds_data[i].cdev);
+
+	return 0;
+}
+#else
+#define gpio_led_suspend NULL
+#define gpio_led_resume NULL
+#endif
+
+static struct platform_driver gpio_led_driver = {
+	.remove		= __exit_p(gpio_led_remove),
+	.suspend	= gpio_led_suspend,
+	.resume		= gpio_led_resume,
+	.driver		= {
+		.name	= "leds-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init gpio_led_init(void)
+{
+	return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+}
+
+static void __exit gpio_led_exit(void)
+{
+	platform_driver_unregister(&gpio_led_driver);
+}
+
+module_init(gpio_led_init);
+module_exit(gpio_led_exit);
+
+MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+MODULE_DESCRIPTION("GPIO LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 6f2d449..bfac499 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -19,7 +19,7 @@
 static void locomoled_brightness_set(struct led_classdev *led_cdev,
 				enum led_brightness value, int offset)
 {
-	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
 	unsigned long flags;
 
 	local_irq_save(flags);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index a715c4e..f2f3884 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -13,6 +13,7 @@
 #ifndef __LEDS_H_INCLUDED
 #define __LEDS_H_INCLUDED
 
+#include <linux/device.h>
 #include <linux/leds.h>
 
 static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@
 #define led_trigger_set(x, y) do {} while(0)
 #endif
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-			size_t count);
-ssize_t led_trigger_show(struct class_device *dev, char *buf);
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count);
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+			char *buf);
 
 #endif	/* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d756bdb..ed9ff02 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -52,9 +52,10 @@
 	mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
 }
 
-static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_on_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@
 	return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
-				size_t size)
+static ssize_t led_delay_on_store(struct device *dev, 
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 	int ret = -EINVAL;
 	char *after;
@@ -84,9 +85,10 @@
 	return ret;
 }
 
-static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_off_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@
 	return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
-				size_t size)
+static ssize_t led_delay_off_store(struct device *dev, 
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 	int ret = -EINVAL;
 	char *after;
@@ -116,10 +118,8 @@
 	return ret;
 }
 
-static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
-			led_delay_on_store);
-static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
-			led_delay_off_store);
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
 
 static void timer_trig_activate(struct led_classdev *led_cdev)
 {
@@ -136,18 +136,17 @@
 	timer_data->timer.function = led_timer_function;
 	timer_data->timer.data = (unsigned long) led_cdev;
 
-	rc = class_device_create_file(led_cdev->class_dev,
-				&class_device_attr_delay_on);
-	if (rc) goto err_out;
-	rc = class_device_create_file(led_cdev->class_dev,
-				&class_device_attr_delay_off);
-	if (rc) goto err_out_delayon;
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+	if (rc)
+		goto err_out;
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+	if (rc)
+		goto err_out_delayon;
 
 	return;
 
 err_out_delayon:
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_delay_on);
+	device_remove_file(led_cdev->dev, &dev_attr_delay_on);
 err_out:
 	led_cdev->trigger_data = NULL;
 	kfree(timer_data);
@@ -158,10 +157,8 @@
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	if (timer_data) {
-		class_device_remove_file(led_cdev->class_dev,
-					&class_device_attr_delay_on);
-		class_device_remove_file(led_cdev->class_dev,
-					&class_device_attr_delay_off);
+		device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+		device_remove_file(led_cdev->dev, &dev_attr_delay_off);
 		del_timer_sync(&timer_data->timer);
 		kfree(timer_data);
 	}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index d9de5bb..bee029b 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -38,12 +38,12 @@
 		ss = lg->regs->ss;
 	}
 
-	/* We use IF bit in eflags to indicate whether irqs were disabled
-	   (it's always 0, since irqs are enabled when guest is running). */
+	/* We use IF bit in eflags to indicate whether irqs were enabled
+	   (it's always 1, since irqs are enabled when guest is running). */
 	eflags = lg->regs->eflags;
-	if (get_user(irq_enable, &lg->lguest_data->irq_enabled))
-		irq_enable = 0;
-	eflags |= (irq_enable & X86_EFLAGS_IF);
+	if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+	    && !(irq_enable & X86_EFLAGS_IF))
+		eflags &= ~X86_EFLAGS_IF;
 
 	push_guest_stack(lg, &gstack, eflags);
 	push_guest_stack(lg, &gstack, lg->regs->cs);
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
index 06bdba2..c8eb792 100644
--- a/drivers/lguest/io.c
+++ b/drivers/lguest/io.c
@@ -187,7 +187,7 @@
 		/* FIXME: This is not completely portable, since
 		   archs do different things for copy_to_user_page. */
 		if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
-				   (void *__user)src->addr[si], len) != 0) {
+				   (void __user *)src->addr[si], len) != 0) {
 			kill_guest(srclg, "bad address in sending DMA");
 			totlen = 0;
 			break;
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
index b9a58b7..18dade0 100644
--- a/drivers/lguest/lguest.c
+++ b/drivers/lguest/lguest.c
@@ -39,7 +39,6 @@
 #include <asm/e820.h>
 #include <asm/mce.h>
 #include <asm/io.h>
-//#include <asm/sched-clock.h>
 
 /* Declarations for definitions in lguest_guest.S */
 extern char lguest_noirq_start[], lguest_noirq_end[];
@@ -57,6 +56,7 @@
 	.blocked_interrupts = { 1 }, /* Block timer interrupts */
 };
 struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
 
 static enum paravirt_lazy_mode lazy_mode;
 static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
@@ -363,6 +363,11 @@
 	.read		= lguest_clock_read,
 };
 
+static unsigned long long lguest_sched_clock(void)
+{
+	return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
 /* We also need a "struct clock_event_device": Linux asks us to set it to go
  * off some time in the future.  Actually, James Morris figured all this out, I
  * just applied the patch. */
@@ -393,6 +398,8 @@
 		break;
 	case CLOCK_EVT_MODE_PERIODIC:
 		BUG();
+	case CLOCK_EVT_MODE_RESUME:
+		break;
 	}
 }
 
@@ -439,6 +446,7 @@
 		lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8;
 		lguest_clock.mask = CLOCKSOURCE_MASK(32);
 	}
+	clock_base = lguest_clock_read();
 	clocksource_register(&lguest_clock);
 
 	/* We can't set cpumask in the initializer: damn C limitations! */
@@ -584,6 +592,7 @@
 	paravirt_ops.time_init = lguest_time_init;
 	paravirt_ops.set_lazy_mode = lguest_lazy_mode;
 	paravirt_ops.wbinvd = lguest_wbinvd;
+	paravirt_ops.sched_clock = lguest_sched_clock;
 
 	hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
 
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
index 00046c5..a3dbf22 100644
--- a/drivers/lguest/lguest_asm.S
+++ b/drivers/lguest/lguest_asm.S
@@ -2,9 +2,7 @@
 #include <linux/lguest.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
-
-/* FIXME: Once asm/processor-flags.h goes in, include that */
-#define X86_EFLAGS_IF 0x00000200
+#include <asm/processor-flags.h>
 
 /*
  * This is where we begin: we have a magic signature which the launcher looks
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 4177ff0..2c21d4f 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -30,7 +30,6 @@
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
-#include <asm/dbdma.h>
 #include <asm/macio.h>
 #include <asm/keylargo.h>
 
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index ba952a0..bdc52d6 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -920,6 +920,8 @@
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
 
+	flush_workqueue(_kcryptd_workqueue);
+
 	bioset_free(cc->bs);
 	mempool_destroy(cc->page_pool);
 	mempool_destroy(cc->io_pool);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c8dfdb3..d90ee14 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -493,12 +493,12 @@
 			if (frombio)
 				tx = async_memcpy(page, bio_page, page_offset,
 					b_offset, clen,
-					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+					ASYNC_TX_DEP_ACK,
 					tx, NULL, NULL);
 			else
 				tx = async_memcpy(bio_page, page, b_offset,
 					page_offset, clen,
-					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+					ASYNC_TX_DEP_ACK,
 					tx, NULL, NULL);
 		}
 		if (clen < len) /* hit end of page */
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fe447a0..a3292e9 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -345,8 +345,8 @@
 			}
 
 			/* Set/reset key-up timer */
-			timeout = current_jiffies + (500 + ir->rc5_key_timeout
-						     * HZ) / 1000;
+			timeout = current_jiffies +
+				  msecs_to_jiffies(ir->rc5_key_timeout);
 			mod_timer(&ir->timer_keyup, timeout);
 
 			/* Save code for repeat test */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 2cee9e3..8178832 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2267,7 +2267,7 @@
 		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index ce940b1..f0a67e9 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -63,7 +63,7 @@
 static void sleep_delay(long n)
 {
 	/* Sleep nicely for 'n' uS */
-	int d=n/(1000000/HZ);
+	int d=n/msecs_to_jiffies(1000);
 	if(!d)
 		udelay(n);
 	else
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8cf2e9d..34e317c 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -329,7 +329,7 @@
 	init_timer(&readtimer);
 	readtimer.function=cadet_handler;
 	readtimer.data=(unsigned long)0;
-	readtimer.expires=jiffies+(HZ/20);
+	readtimer.expires=jiffies+msecs_to_jiffies(50);
 	add_timer(&readtimer);
 }
 
@@ -349,7 +349,7 @@
 		init_timer(&readtimer);
 		readtimer.function=cadet_handler;
 		readtimer.data=(unsigned long)0;
-		readtimer.expires=jiffies+(HZ/20);
+		readtimer.expires=jiffies+msecs_to_jiffies(50);
 		add_timer(&readtimer);
 	}
 	if(rdsin==rdsout) {
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 4db05b2..99a3231 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -94,7 +94,6 @@
 
 	u32 iobase;
 	u32 length;
-	u16 model;
 
 	u32 current_frequency;
 	u8  mute;
@@ -413,8 +412,6 @@
 		goto err_pci;
 	}
 
-	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
 	pci_set_drvdata( pci_dev, card );
 
 	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 2e4cf1e..b767b09 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -257,7 +257,7 @@
 		printk(KERN_WARNING "%s: I/O error #%d "
 		       "(write 0x%02x/0x%02x)\n",
 		       encoder->i2c->name, err, encoder->addr, subaddr);
-		schedule_timeout_interruptible(HZ/10);
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
 	}
 	if (err == 3) {
 		printk(KERN_WARNING "%s: giving up\n",
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 2aea09c..387cb21 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -4209,7 +4209,7 @@
 	bus_low(btv,btv->mbox_clk);
 
 	udelay(10);
-	timeout= jiffies + HZ;
+	timeout= jiffies + msecs_to_jiffies(1000);
 
 	/* wait for DATA line to go low; error if it doesn't */
 	while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 94a13d0..4201552 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -153,7 +153,7 @@
 {
 	if (ir->polling) {
 		setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
-		ir->timer.expires  = jiffies + HZ;
+		ir->timer.expires  = jiffies + msecs_to_jiffies(1000);
 		add_timer(&ir->timer);
 	} else if (ir->rc5_gpio) {
 		/* set timer_end for code completion */
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index bd85f6d..5b25fac 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -284,8 +284,8 @@
 #define d2printk if (bttv_debug >= 2) printk
 
 #define BTTV_MAX_FBUF   0x208000
-#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE  (HZ)   /* one second */
+#define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
+#define BTTV_FREE_IDLE  msecs_to_jiffies(1000)   /* one second */
 
 
 struct bttv_pll_info {
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 925ff17..f76c6a6 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -95,7 +95,7 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
 		if (qcam_ready1(qcam) == value)
 			return 0;
 
@@ -120,7 +120,7 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
 		if (qcam_ready2(qcam) == value)
 			return 0;
 
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 98fa354..06b233a 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1881,8 +1881,14 @@
 	mutex_unlock(&core->lock);
 
 	/* start tvaudio thread */
-	if (core->tuner_type != TUNER_ABSENT)
+	if (core->tuner_type != TUNER_ABSENT) {
 		core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+		if (IS_ERR(core->kthread)) {
+			err = PTR_ERR(core->kthread);
+			printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
+			       err);
+		}
+	}
 	return 0;
 
 fail_unreg:
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c4f656e..8091268 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -259,7 +259,7 @@
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 /* buffer for one video frame */
 struct cx88_buffer {
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 1aaeaa0..e43beb2 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,7 @@
 config VIDEO_IVTV
 	tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
@@ -16,11 +17,11 @@
 	select VIDEO_UPD64031A
 	select VIDEO_UPD64083
 	---help---
-	  This is a video4linux driver for Conexant cx23416 or cx23416 based
+	  This is a video4linux driver for Conexant cx23416 or cx23415 based
 	  PCI personal video recorder devices.
 
 	  This is used in devices such as the Hauppauge PVR-150/250/350/500
-	  cards.
+	  cards. There is a driver homepage at <http://www.ivtvdriver.org>.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ivtv.
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 4c93466..d73d433 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -56,7 +56,6 @@
 #include "ivtv-gpio.h"
 #include "ivtv-yuv.h"
 
-#include <linux/vermagic.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-chip-ident.h>
 
@@ -276,9 +275,10 @@
 }
 
 /* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
 {
 	int ret;
+	int timeout = msecs_to_jiffies(msecs);
 
 	do {
 		set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -427,7 +427,7 @@
 	if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
 		itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
 		if (itv->options.newi2c) {
-		    IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+		    IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
 		    exit_ivtv_i2c(itv);
 		    init_ivtv_i2c(itv);
 		}
@@ -951,7 +951,7 @@
 
 	/* Make sure we've got a place for this card */
 	if (ivtv_cards_active == IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d).\n",
+		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
 			      ivtv_cards_active);
 		spin_unlock(&ivtv_cards_lock);
 		return -ENOMEM;
@@ -966,9 +966,7 @@
 	itv->dev = dev;
 	itv->num = ivtv_cards_active++;
 	snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
-	if (itv->num) {
-		printk(KERN_INFO "ivtv:  ======================  NEXT CARD  ======================\n");
-	}
+	IVTV_INFO("Initializing card #%d\n", itv->num);
 
 	spin_unlock(&ivtv_cards_lock);
 
@@ -1215,7 +1213,7 @@
 	if (itv->has_cx23415)
 		ivtv_set_osd_alpha(itv);
 
-	IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+	IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
 
 	return 0;
 
@@ -1248,15 +1246,15 @@
 {
 	struct ivtv *itv = pci_get_drvdata(pci_dev);
 
-	IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+	IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
 
 	/* Stop all captures */
-	IVTV_DEBUG_INFO(" Stopping all streams.\n");
+	IVTV_DEBUG_INFO("Stopping all streams\n");
 	if (atomic_read(&itv->capturing) > 0)
 		ivtv_stop_all_captures(itv);
 
 	/* Stop all decoding */
-	IVTV_DEBUG_INFO(" Stopping decoding.\n");
+	IVTV_DEBUG_INFO("Stopping decoding\n");
 	if (atomic_read(&itv->decoding) > 0) {
 		int type;
 
@@ -1269,30 +1267,30 @@
 	}
 
 	/* Interrupts */
-	IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+	IVTV_DEBUG_INFO("Disabling interrupts\n");
 	ivtv_set_irq_mask(itv, 0xffffffff);
 	del_timer_sync(&itv->dma_timer);
 
 	/* Stop all Work Queues */
-	IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+	IVTV_DEBUG_INFO("Stop Work Queues\n");
 	flush_workqueue(itv->irq_work_queues);
 	destroy_workqueue(itv->irq_work_queues);
 
-	IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+	IVTV_DEBUG_INFO("Stopping Firmware\n");
 	ivtv_halt_firmware(itv);
 
-	IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+	IVTV_DEBUG_INFO("Unregistering v4l devices\n");
 	ivtv_streams_cleanup(itv);
-	IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+	IVTV_DEBUG_INFO("Freeing dma resources\n");
 	ivtv_udma_free(itv);
 
 	exit_ivtv_i2c(itv);
 
-	IVTV_DEBUG_INFO(" Releasing irq.\n");
+	IVTV_DEBUG_INFO(" Releasing irq\n");
 	free_irq(itv->dev->irq, (void *)itv);
 	ivtv_iounmap(itv);
 
-	IVTV_DEBUG_INFO(" Releasing mem.\n");
+	IVTV_DEBUG_INFO(" Releasing mem\n");
 	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
 	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
 	if (itv->has_cx23415)
@@ -1313,28 +1311,27 @@
 
 static int module_start(void)
 {
-	printk(KERN_INFO "ivtv:  ==================== START INIT IVTV ====================\n");
-	printk(KERN_INFO "ivtv:  version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+	printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
 
 	memset(ivtv_cards, 0, sizeof(ivtv_cards));
 
 	/* Validate parameters */
 	if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  ivtv_first_minor must be between 0 and %d. Exiting...\n",
+		printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
 		     IVTV_MAX_CARDS - 1);
 		return -1;
 	}
 
 	if (ivtv_debug < 0 || ivtv_debug > 1023) {
 		ivtv_debug = 0;
-		printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 1023!\n");
+		printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 1023\n");
 	}
 
 	if (pci_register_driver(&ivtv_pci_driver)) {
 		printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
 		return -ENODEV;
 	}
-	printk(KERN_INFO "ivtv:  ====================  END INIT IVTV  ====================\n");
+	printk(KERN_INFO "ivtv:  End initialization\n");
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 6c1a85f..91b588d 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -848,7 +848,7 @@
 struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
 
 /* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
 
 /* Wait on queue, returns -EINTR if interrupted */
 int ivtv_waitq(wait_queue_head_t *waitq);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index ee7e884..8e97a93 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -218,7 +218,7 @@
 			/* Process pending program info updates and pending VBI data */
 			ivtv_update_pgm_info(itv);
 
-			if (jiffies - itv->dualwatch_jiffies > HZ) {
+			if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
 				itv->dualwatch_jiffies = jiffies;
 				ivtv_dualwatch(itv);
 			}
@@ -832,7 +832,7 @@
 	if (itv == NULL) {
 		/* Couldn't find a device registered
 		   on that minor, shouldn't happen! */
-		printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+		printk(KERN_WARNING "ivtv:  No ivtv device found on minor %d\n", minor);
 		return -ENXIO;
 	}
 
@@ -924,7 +924,7 @@
 	if (atomic_read(&itv->capturing) == 0)
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-	ivtv_sleep_timeout(HZ / 10, 0);
+	ivtv_msleep_timeout(100, 0);
 
 	if (atomic_read(&itv->capturing)) {
 		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index 2b6208a..d0feabf 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -36,7 +36,7 @@
 #define IVTV_CMD_SPU_STOP 		0x00000001
 #define IVTV_CMD_SDRAM_PRECHARGE_INIT 	0x0000001A
 #define IVTV_CMD_SDRAM_REFRESH_INIT 	0x80000640
-#define IVTV_SDRAM_SLEEPTIME 		(60 * HZ / 100)	/* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME 		600
 
 #define IVTV_DECODE_INIT_MPEG_FILENAME 	"v4l-cx2341x-init.mpg"
 #define IVTV_DECODE_INIT_MPEG_SIZE 	(152*1024)
@@ -61,7 +61,7 @@
 			   the wrong file was sometimes loaded. So we check filesizes to
 			   see if at least the right-sized file was loaded. If not, then we
 			   retry. */
-			IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+			IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
 			release_firmware(fw);
 			retries--;
 			goto retry;
@@ -73,11 +73,11 @@
 			src++;
 		}
 		release_firmware(fw);
-		IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+		IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
 		return size;
 	}
-	IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
-	IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+	IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+	IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
 	return -ENOMEM;
 }
 
@@ -89,7 +89,7 @@
 	if (itv->enc_mbox.mbox)
 		ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
 
-	ivtv_sleep_timeout(HZ / 100, 0);
+	ivtv_msleep_timeout(10, 0);
 	itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
 
 	IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -113,7 +113,7 @@
 	IVTV_DEBUG_INFO("Stopping SPU\n");
 	write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
 
-	ivtv_sleep_timeout(HZ / 100, 0);
+	ivtv_msleep_timeout(10, 0);
 
 	IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
 	write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -129,9 +129,8 @@
 		write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
 	}
 
-	IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
-		   (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
-	ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+	IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+	ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
 }
 
 void ivtv_firmware_versions(struct ivtv *itv)
@@ -204,12 +203,12 @@
 
 	/* start firmware */
 	write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
-	ivtv_sleep_timeout(HZ / 10, 0);
+	ivtv_msleep_timeout(100, 0);
 	if (itv->has_cx23415)
 		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
 	else
 		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
-	ivtv_sleep_timeout(HZ / 10, 0);
+	ivtv_msleep_timeout(100, 0);
 
 	/* find mailboxes and ping firmware */
 	itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -264,7 +263,7 @@
 				IVTV_DECODE_INIT_MPEG_FILENAME);
 	} else {
 		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
-		ivtv_sleep_timeout(HZ / 10, 0);
+		ivtv_msleep_timeout(100, 0);
 	}
 	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 676418c..6a5a7aa 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -130,7 +130,7 @@
 
 	if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
 		return -EINVAL;
-	IVTV_INFO("Resetting tuner.\n");
+	IVTV_INFO("Resetting tuner\n");
 	curout = read_reg(IVTV_REG_GPIO_OUT);
 	curdir = read_reg(IVTV_REG_GPIO_DIR);
 	curdir |= (1 << 12);  /* GPIO bit 12 */
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 50624c6..b355743 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -144,7 +144,7 @@
 		}
 	}
 	if (i == I2C_CLIENTS_MAX) {
-		IVTV_ERR("insufficient room for new I2C client!\n");
+		IVTV_ERR("Insufficient room for new I2C client\n");
 	}
 	return 0;
 }
@@ -236,7 +236,7 @@
 	int ret = 0;
 
 	if (ivtv_getscl(itv) == 1) {
-		IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+		IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
 			IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +263,7 @@
 {
 	int i, bit;
 
-	IVTV_DEBUG_I2C("write %x\n",byte);
+	IVTV_DEBUG_HI_I2C("write %x\n",byte);
 	for (i = 0; i < 8; ++i, byte<<=1) {
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +318,7 @@
 	ivtv_scldelay(itv);
 	ivtv_setscl(itv, 0);
 	ivtv_scldelay(itv);
-	IVTV_DEBUG_I2C("read %x\n",*byte);
+	IVTV_DEBUG_HI_I2C("read %x\n",*byte);
 	return 0;
 }
 
@@ -330,7 +330,7 @@
 
 	sda = ivtv_getsda(itv);
 	if (sda != 1) {
-		IVTV_DEBUG_I2C("SDA was low at start\n");
+		IVTV_DEBUG_HI_I2C("SDA was low at start\n");
 		ivtv_setsda(itv, 1);
 		if (!ivtv_waitsda(itv, 1)) {
 			IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +355,7 @@
 	int i;
 
 	if (ivtv_getscl(itv) != 0) {
-		IVTV_DEBUG_I2C("SCL not low when stopping\n");
+		IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
 			IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -569,7 +569,7 @@
 		}
 	}
 	if (cmd != VIDIOC_G_CHIP_IDENT)
-		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
 	return -ENODEV;
 }
 
@@ -640,7 +640,7 @@
 
 	addr = ivtv_i2c_hw_addr(itv, hw);
 	if (addr < 0) {
-		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
 			       hw, ivtv_i2c_hw_name(hw), cmd);
 		return addr;
 	}
@@ -655,7 +655,7 @@
 	addr = ivtv_i2c_id_addr(itv, id);
 	if (addr < 0) {
 		if (cmd != VIDIOC_G_CHIP_IDENT)
-			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
 				id, ivtv_i2c_id_name(id), cmd);
 		return addr;
 	}
@@ -696,7 +696,7 @@
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
 {
 	if (itv->i2c_adap.algo == NULL) {
-		IVTV_ERR("adapter is not set");
+		IVTV_ERR("Adapter is not set");
 		return;
 	}
 	i2c_clients_command(&itv->i2c_adap, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 1a3ee46..fcd6e7f 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -403,6 +403,11 @@
 	/* Mark last buffer size for Interrupt flag */
 	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
 
+	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+		set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+	else
+		clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+
 	if (ivtv_use_pio(s)) {
 		for (i = 0; i < s->SG_length; i++) {
 			s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
@@ -420,7 +425,7 @@
 		write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
 		set_bit(IVTV_F_I_DMA, &itv->i_flags);
 		itv->cur_dma_stream = s->type;
-		itv->dma_timer.expires = jiffies + HZ / 10;
+		itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
 		add_timer(&itv->dma_timer);
 	}
 }
@@ -437,7 +442,7 @@
 	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
 	set_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = s->type;
-	itv->dma_timer.expires = jiffies + HZ / 10;
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
 	add_timer(&itv->dma_timer);
 }
 
@@ -597,7 +602,6 @@
 				data[0], data[1], data[2]);
 		return;
 	}
-	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
 	s = &itv->streams[ivtv_stream_map[data[0]]];
 	if (!stream_enc_dma_append(s, data)) {
 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -634,7 +638,6 @@
 	   then start a DMA request for just the VBI data. */
 	if (!stream_enc_dma_append(s, data) &&
 			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
-		set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
 	}
 }
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 6ae42a3..814a673 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -37,6 +37,7 @@
 #define API_RESULT	 (1 << 1) 	/* Allow 1 second for this cmd to end */
 #define API_FAST_RESULT	 (3 << 1)	/* Allow 0.1 second for this cmd to end */
 #define API_DMA 	 (1 << 3)	/* DMA mailbox, has special handling */
+#define API_HIGH_VOL 	 (1 << 5)	/* High volume command (i.e. called during encoding or decoding) */
 #define API_NO_WAIT_MB 	 (1 << 4)	/* Command may not wait for a free mailbox */
 #define API_NO_WAIT_RES	 (1 << 5)	/* Command may not wait for the result */
 
@@ -77,11 +78,11 @@
 	API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
 	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, 	API_FAST_RESULT),
 	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, 	API_FAST_RESULT),
-	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA | API_HIGH_VOL),
 	API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, 	API_RESULT),
 	API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, 	API_CACHE),
 	API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, 		API_RESULT),
-	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB),
+	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB | API_HIGH_VOL),
 	API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, 		API_CACHE),
 	API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, 	API_RESULT),
 	API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, 	API_CACHE),
@@ -102,7 +103,7 @@
 	API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
 	API_ENTRY(CX2341X_DEC_GET_XFER_INFO, 		API_FAST_RESULT),
 	API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, 		API_FAST_RESULT),
-	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA | API_HIGH_VOL),
 	API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, 		API_RESULT),
 	API_ENTRY(CX2341X_DEC_HALT_FW, 			API_FAST_RESULT),
 	API_ENTRY(CX2341X_DEC_SET_STANDARD, 		API_CACHE),
@@ -175,9 +176,9 @@
 
 		/* Sleep before a retry, if not atomic */
 		if (!(flags & API_NO_WAIT_MB)) {
-			if (jiffies - then > retries * HZ / 100)
+			if (jiffies - then > msecs_to_jiffies(10*retries))
 			       break;
-			ivtv_sleep_timeout(HZ / 100, 0);
+			ivtv_msleep_timeout(10, 0);
 		}
 	}
 	return -ENODEV;
@@ -212,7 +213,7 @@
 {
 	struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
 	volatile struct ivtv_mailbox __iomem *mbox;
-	int api_timeout = HZ;
+	int api_timeout = msecs_to_jiffies(1000);
 	int flags, mb, i;
 	unsigned long then;
 
@@ -227,7 +228,12 @@
 		return -EINVAL;
 	}
 
-	IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+	if (api_info[cmd].flags & API_HIGH_VOL) {
+	    IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+	}
+	else {
+	    IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+	}
 
 	/* clear possibly uninitialized part of data array */
 	for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +243,7 @@
 	   data, then just return 0 as there is no need to issue this command again.
 	   Just an optimization to prevent unnecessary use of mailboxes. */
 	if (itv->api_cache[cmd].last_jiffies &&
-	    jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+	    jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
 	    !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
 		itv->api_cache[cmd].last_jiffies = jiffies;
 		return 0;
@@ -262,7 +268,7 @@
 	}
 
 	if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
-		api_timeout = HZ / 10;
+		api_timeout = msecs_to_jiffies(100);
 
 	mb = get_mailbox(itv, mbdata, flags);
 	if (mb < 0) {
@@ -295,11 +301,12 @@
 		if (flags & API_NO_WAIT_RES)
 			mdelay(1);
 		else
-			ivtv_sleep_timeout(HZ / 100, 0);
+			ivtv_msleep_timeout(10, 0);
 	}
-	if (jiffies - then > HZ / 10)
-		IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
-				api_info[cmd].name, jiffies - then, HZ);
+	if (jiffies - then > msecs_to_jiffies(100))
+		IVTV_DEBUG_WARN("%s took %u jiffies\n",
+				api_info[cmd].name,
+				jiffies_to_msecs(jiffies - then));
 
 	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
 		data[i] = readl(&mbox->data[i]);
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 2871171..322b347 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -565,7 +565,7 @@
 		/* Initialize Digitizer for Capture */
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-		ivtv_sleep_timeout(HZ / 10, 0);
+		ivtv_msleep_timeout(100, 0);
 	}
 
 	/* begin_capture */
@@ -781,8 +781,9 @@
 			set_current_state(TASK_INTERRUPTIBLE);
 
 			/* wait 2s for EOS interrupt */
-			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
-				schedule_timeout(HZ / 100);
+			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+				jiffies < then + msecs_to_jiffies (2000)) {
+				schedule_timeout(msecs_to_jiffies(10));
 			}
 
 			/* To convert jiffies to ms, we must multiply by 1000
@@ -821,7 +822,8 @@
 			} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
 				break;
 			}
-		} while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies);
+		} while (!ivtv_msleep_timeout(10, 1) &&
+			 then + msecs_to_jiffies(2000) > jiffies);
 
 		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&s->waitq, &wait);
@@ -892,7 +894,7 @@
 					break;
 				tmp = data[3];
 			}
-			if (ivtv_sleep_timeout(HZ/10, 1))
+			if (ivtv_msleep_timeout(100, 1))
 				break;
 		}
 	}
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f2a2f34..17f1e2e 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -86,9 +86,9 @@
 
 
 
-#define PAGE_WAIT (300*HZ/1000)			/* Time between requesting page and */
+#define PAGE_WAIT    msecs_to_jiffies(300)	/* Time between requesting page and */
 						/* checking status bits */
-#define PGBUF_EXPIRE (15*HZ)			/* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000)	/* Time to wait before retransmitting */
 						/* page regardless of infobits */
 typedef struct {
 	u8 pgbuf[VTX_VIRTUALSIZE];		/* Page-buffer */
@@ -115,8 +115,8 @@
 #define CCTWR 34		/* I²C write/read-address of vtx-chip */
 #define CCTRD 35
 #define NOACK_REPEAT 10		/* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20)	/* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000)	/* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY   msecs_to_jiffies(50)	/* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30)	/* Time to wait for ready signal of I2C-bus interface */
 #define INIT_DELAY 500		/* Time in usec to wait at initialization of CEA interface */
 #define START_DELAY 10		/* Time in usec to wait before starting write-cycle (CEA) */
 
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 676b997..061134a 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -208,7 +208,7 @@
 	saa7110_write_block(client, initseq, sizeof(initseq));
 	saa7110_selmux(client, decoder->input);
 	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/4);
+	schedule_timeout(msecs_to_jiffies(250));
 	finish_wait(&decoder->wq, &wait);
 	status = saa7110_read(client);
 	if (status & 0x40) {
@@ -249,7 +249,7 @@
 	//saa7110_write(client,0x2E,0x9A);
 
 	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/4);
+	schedule_timeout(msecs_to_jiffies(250));
 	finish_wait(&decoder->wq, &wait);
 
 	status = saa7110_read(client);
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index d32a856..3462554 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -314,7 +314,7 @@
 #define INTERLACE_ON           1
 #define INTERLACE_OFF          2
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 struct saa7134_dev;
 struct saa7134_dma;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 9da338d..cffb011 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -290,7 +290,7 @@
 		desc->checkmode(chip);
 
 		/* schedule next check */
-		mod_timer(&chip->wt, jiffies+2*HZ);
+		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 	}
 
 	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1770,7 @@
 			desc->setmode(chip,VIDEO_SOUND_MONO);
 			if (chip->prevmode != VIDEO_SOUND_MONO)
 				chip->prevmode = -1; /* reset previous mode */
-			mod_timer(&chip->wt, jiffies+2*HZ);
+			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 			/* the thread will call checkmode() later */
 		}
 		break;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 13ee550..d2915d3 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -939,16 +939,25 @@
    When no more controls are available 0 is returned. */
 u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 {
-	u32 ctrl_class;
+	u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
 	const u32 *pctrl;
 
-	/* if no query is desired, then just return the control ID */
-	if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
-		return id;
 	if (ctrl_classes == NULL)
 		return 0;
+
+	/* if no query is desired, then check if the ID is part of ctrl_classes */
+	if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+		/* find class */
+		while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+			ctrl_classes++;
+		if (*ctrl_classes == NULL)
+			return 0;
+		pctrl = *ctrl_classes;
+		/* find control ID */
+		while (*pctrl && *pctrl != id) pctrl++;
+		return *pctrl ? id : 0;
+	}
 	id &= V4L2_CTRL_ID_MASK;
-	ctrl_class = V4L2_CTRL_ID2CLASS(id);
 	id++;	/* select next control */
 	/* find first class that matches (or is greater than) the class of
 	   the ID */
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index e94a9a6..a0c1647 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2080,7 +2080,7 @@
 
 	/* to ensure that schedule_timeout will return immediately
 	 * if VINO interrupt was triggered meanwhile */
-	schedule_timeout_interruptible(HZ / 10);
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
 
 	if (signal_pending(current))
 		err = -EINTR;
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 8f6741a..1bf4cbe 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -321,12 +321,14 @@
 
 static int wm8739_detach(struct i2c_client *client)
 {
+	struct wm8739_state *state = i2c_get_clientdata(client);
 	int err;
 
 	err = i2c_detach_client(client);
 	if (err)
 		return err;
 
+	kfree(state);
 	kfree(client);
 	return 0;
 }
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 4df5d30..9f7e894 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -222,12 +222,14 @@
 
 static int wm8775_detach(struct i2c_client *client)
 {
+	struct wm8775_state *state = i2c_get_clientdata(client);
 	int err;
 
 	err = i2c_detach_client(client);
 	if (err) {
 		return err;
 	}
+	kfree(state);
 	kfree(client);
 
 	return 0;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1d516f2..aaaa61e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -150,6 +150,7 @@
 	depends on X86 && ACPI
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
+	select NVRAM
 	---help---
 	  This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
 	  support for Fn-Fx key combinations, Bluetooth control, video
@@ -196,4 +197,17 @@
 
 	  If you are not sure, say Y here.
 
+config THINKPAD_ACPI_INPUT_ENABLED
+	bool "Enable input layer support by default"
+	depends on THINKPAD_ACPI
+	default y
+	---help---
+	  Enables hot key handling over the input layer by default.  If unset,
+	  the driver does not enable any hot key handling by default, and also
+	  starts up with a mostly empty keymap.
+
+	  If you are not sure, say Y here.  Say N to retain the deprecated
+	  behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21.
+
+
 endif # MISC_DEVICES
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 9623eaf..303e48c 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -142,43 +142,124 @@
 	int key;
 };
 
-/* Correspondance table between sonypi events and input layer events */
-static struct {
-	int sonypiev;
-	int inputev;
-} sony_laptop_inputkeys[] = {
-	{ SONYPI_EVENT_CAPTURE_PRESSED,	 	KEY_CAMERA },
-	{ SONYPI_EVENT_FNKEY_ONLY, 		KEY_FN },
-	{ SONYPI_EVENT_FNKEY_ESC, 		KEY_FN_ESC },
-	{ SONYPI_EVENT_FNKEY_F1, 		KEY_FN_F1 },
-	{ SONYPI_EVENT_FNKEY_F2, 		KEY_FN_F2 },
-	{ SONYPI_EVENT_FNKEY_F3, 		KEY_FN_F3 },
-	{ SONYPI_EVENT_FNKEY_F4, 		KEY_FN_F4 },
-	{ SONYPI_EVENT_FNKEY_F5, 		KEY_FN_F5 },
-	{ SONYPI_EVENT_FNKEY_F6, 		KEY_FN_F6 },
-	{ SONYPI_EVENT_FNKEY_F7, 		KEY_FN_F7 },
-	{ SONYPI_EVENT_FNKEY_F8, 		KEY_FN_F8 },
-	{ SONYPI_EVENT_FNKEY_F9,		KEY_FN_F9 },
-	{ SONYPI_EVENT_FNKEY_F10,		KEY_FN_F10 },
-	{ SONYPI_EVENT_FNKEY_F11, 		KEY_FN_F11 },
-	{ SONYPI_EVENT_FNKEY_F12,		KEY_FN_F12 },
-	{ SONYPI_EVENT_FNKEY_1, 		KEY_FN_1 },
-	{ SONYPI_EVENT_FNKEY_2, 		KEY_FN_2 },
-	{ SONYPI_EVENT_FNKEY_D,			KEY_FN_D },
-	{ SONYPI_EVENT_FNKEY_E,			KEY_FN_E },
-	{ SONYPI_EVENT_FNKEY_F,			KEY_FN_F },
-	{ SONYPI_EVENT_FNKEY_S,			KEY_FN_S },
-	{ SONYPI_EVENT_FNKEY_B,			KEY_FN_B },
-	{ SONYPI_EVENT_BLUETOOTH_PRESSED, 	KEY_BLUE },
-	{ SONYPI_EVENT_BLUETOOTH_ON, 		KEY_BLUE },
-	{ SONYPI_EVENT_PKEY_P1, 		KEY_PROG1 },
-	{ SONYPI_EVENT_PKEY_P2, 		KEY_PROG2 },
-	{ SONYPI_EVENT_PKEY_P3, 		KEY_PROG3 },
-	{ SONYPI_EVENT_BACK_PRESSED, 		KEY_BACK },
-	{ SONYPI_EVENT_HELP_PRESSED, 		KEY_HELP },
-	{ SONYPI_EVENT_ZOOM_PRESSED, 		KEY_ZOOM },
-	{ SONYPI_EVENT_THUMBPHRASE_PRESSED, 	BTN_THUMB },
-	{ 0, 0 },
+/* Correspondance table between sonypi events
+ * and input layer indexes in the keymap
+ */
+static int sony_laptop_input_index[] = {
+	-1,	/* no event */
+	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN */
+	-1,	/* SONYPI_EVENT_JOGDIAL_UP */
+	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_RELEASED */
+	 0,	/* SONYPI_EVENT_CAPTURE_PRESSED */
+	 1,	/* SONYPI_EVENT_CAPTURE_RELEASED */
+	 2,	/* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+	 3,	/* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+	 4,	/* SONYPI_EVENT_FNKEY_ESC */
+	 5,	/* SONYPI_EVENT_FNKEY_F1 */
+	 6,	/* SONYPI_EVENT_FNKEY_F2 */
+	 7,	/* SONYPI_EVENT_FNKEY_F3 */
+	 8,	/* SONYPI_EVENT_FNKEY_F4 */
+	 9,	/* SONYPI_EVENT_FNKEY_F5 */
+	10,	/* SONYPI_EVENT_FNKEY_F6 */
+	11,	/* SONYPI_EVENT_FNKEY_F7 */
+	12,	/* SONYPI_EVENT_FNKEY_F8 */
+	13,	/* SONYPI_EVENT_FNKEY_F9 */
+	14,	/* SONYPI_EVENT_FNKEY_F10 */
+	15,	/* SONYPI_EVENT_FNKEY_F11 */
+	16,	/* SONYPI_EVENT_FNKEY_F12 */
+	17,	/* SONYPI_EVENT_FNKEY_1 */
+	18,	/* SONYPI_EVENT_FNKEY_2 */
+	19,	/* SONYPI_EVENT_FNKEY_D */
+	20,	/* SONYPI_EVENT_FNKEY_E */
+	21,	/* SONYPI_EVENT_FNKEY_F */
+	22,	/* SONYPI_EVENT_FNKEY_S */
+	23,	/* SONYPI_EVENT_FNKEY_B */
+	24,	/* SONYPI_EVENT_BLUETOOTH_PRESSED */
+	25,	/* SONYPI_EVENT_PKEY_P1 */
+	26,	/* SONYPI_EVENT_PKEY_P2 */
+	27,	/* SONYPI_EVENT_PKEY_P3 */
+	28,	/* SONYPI_EVENT_BACK_PRESSED */
+	-1,	/* SONYPI_EVENT_LID_CLOSED */
+	-1,	/* SONYPI_EVENT_LID_OPENED */
+	29,	/* SONYPI_EVENT_BLUETOOTH_ON */
+	30,	/* SONYPI_EVENT_BLUETOOTH_OFF */
+	31,	/* SONYPI_EVENT_HELP_PRESSED */
+	32,	/* SONYPI_EVENT_FNKEY_ONLY */
+	33,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+	34,	/* SONYPI_EVENT_JOGDIAL_FAST_UP */
+	35,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+	36,	/* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+	37,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+	38,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP */
+	39,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+	40,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+	41,	/* SONYPI_EVENT_ZOOM_PRESSED */
+	42,	/* SONYPI_EVENT_THUMBPHRASE_PRESSED */
+	43,	/* SONYPI_EVENT_MEYE_FACE */
+	44,	/* SONYPI_EVENT_MEYE_OPPOSITE */
+	45,	/* SONYPI_EVENT_MEMORYSTICK_INSERT */
+	46,	/* SONYPI_EVENT_MEMORYSTICK_EJECT */
+	-1,	/* SONYPI_EVENT_ANYBUTTON_RELEASED */
+	-1,	/* SONYPI_EVENT_BATTERY_INSERT */
+	-1,	/* SONYPI_EVENT_BATTERY_REMOVE */
+	-1,	/* SONYPI_EVENT_FNKEY_RELEASED */
+	47,	/* SONYPI_EVENT_WIRELESS_ON */
+	48,	/* SONYPI_EVENT_WIRELESS_OFF */
+};
+
+static int sony_laptop_input_keycode_map[] = {
+	KEY_CAMERA,	/*  0 SONYPI_EVENT_CAPTURE_PRESSED */
+	KEY_RESERVED,	/*  1 SONYPI_EVENT_CAPTURE_RELEASED */
+	KEY_RESERVED,	/*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+	KEY_RESERVED,	/*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+	KEY_FN_ESC,	/*  4 SONYPI_EVENT_FNKEY_ESC */
+	KEY_FN_F1,	/*  5 SONYPI_EVENT_FNKEY_F1 */
+	KEY_FN_F2,	/*  6 SONYPI_EVENT_FNKEY_F2 */
+	KEY_FN_F3,	/*  7 SONYPI_EVENT_FNKEY_F3 */
+	KEY_FN_F4,	/*  8 SONYPI_EVENT_FNKEY_F4 */
+	KEY_FN_F5,	/*  9 SONYPI_EVENT_FNKEY_F5 */
+	KEY_FN_F6,	/* 10 SONYPI_EVENT_FNKEY_F6 */
+	KEY_FN_F7,	/* 11 SONYPI_EVENT_FNKEY_F7 */
+	KEY_FN_F8,	/* 12 SONYPI_EVENT_FNKEY_F8 */
+	KEY_FN_F9,	/* 13 SONYPI_EVENT_FNKEY_F9 */
+	KEY_FN_F10,	/* 14 SONYPI_EVENT_FNKEY_F10 */
+	KEY_FN_F11,	/* 15 SONYPI_EVENT_FNKEY_F11 */
+	KEY_FN_F12,	/* 16 SONYPI_EVENT_FNKEY_F12 */
+	KEY_FN_F1,	/* 17 SONYPI_EVENT_FNKEY_1 */
+	KEY_FN_F2,	/* 18 SONYPI_EVENT_FNKEY_2 */
+	KEY_FN_D,	/* 19 SONYPI_EVENT_FNKEY_D */
+	KEY_FN_E,	/* 20 SONYPI_EVENT_FNKEY_E */
+	KEY_FN_F,	/* 21 SONYPI_EVENT_FNKEY_F */
+	KEY_FN_S,	/* 22 SONYPI_EVENT_FNKEY_S */
+	KEY_FN_B,	/* 23 SONYPI_EVENT_FNKEY_B */
+	KEY_BLUETOOTH,	/* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
+	KEY_PROG1,	/* 25 SONYPI_EVENT_PKEY_P1 */
+	KEY_PROG2,	/* 26 SONYPI_EVENT_PKEY_P2 */
+	KEY_PROG3,	/* 27 SONYPI_EVENT_PKEY_P3 */
+	KEY_BACK,	/* 28 SONYPI_EVENT_BACK_PRESSED */
+	KEY_BLUETOOTH,	/* 29 SONYPI_EVENT_BLUETOOTH_ON */
+	KEY_BLUETOOTH,	/* 30 SONYPI_EVENT_BLUETOOTH_OFF */
+	KEY_HELP,	/* 31 SONYPI_EVENT_HELP_PRESSED */
+	KEY_FN,		/* 32 SONYPI_EVENT_FNKEY_ONLY */
+	KEY_RESERVED,	/* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+	KEY_RESERVED,	/* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
+	KEY_RESERVED,	/* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+	KEY_RESERVED,	/* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+	KEY_RESERVED,	/* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+	KEY_RESERVED,	/* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+	KEY_RESERVED,	/* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+	KEY_RESERVED,	/* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+	KEY_ZOOM,	/* 41 SONYPI_EVENT_ZOOM_PRESSED */
+	BTN_THUMB,	/* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+	KEY_RESERVED,	/* 43 SONYPI_EVENT_MEYE_FACE */
+	KEY_RESERVED,	/* 44 SONYPI_EVENT_MEYE_OPPOSITE */
+	KEY_RESERVED,	/* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
+	KEY_RESERVED,	/* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
+	KEY_WLAN,	/* 47 SONYPI_EVENT_WIRELESS_ON */
+	KEY_WLAN,	/* 48 SONYPI_EVENT_WIRELESS_OFF */
 };
 
 /* release buttons after a short delay if pressed */
@@ -202,7 +283,6 @@
 	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
 	struct input_dev *key_dev = sony_laptop_input.key_dev;
 	struct sony_laptop_keypress kp = { NULL };
-	int i;
 
 	if (event == SONYPI_EVENT_FNKEY_RELEASED) {
 		/* Nothing, not all VAIOs generate this event */
@@ -231,17 +311,22 @@
 		break;
 
 	default:
-		for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-			if (event == sony_laptop_inputkeys[i].sonypiev) {
+		if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+			break;
+		}
+		if (sony_laptop_input_index[event] != -1) {
+			kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+			if (kp.key != KEY_UNKNOWN)
 				kp.dev = key_dev;
-				kp.key = sony_laptop_inputkeys[i].inputev;
-				break;
-			}
+		}
 		break;
 	}
 
 	if (kp.dev) {
 		input_report_key(kp.dev, kp.key, 1);
+		/* we emit the scancode so we can always remap the key */
+		input_event(kp.dev, EV_MSC, MSC_SCAN, event);
 		input_sync(kp.dev);
 		kfifo_put(sony_laptop_input.fifo,
 			  (unsigned char *)&kp, sizeof(kp));
@@ -296,11 +381,18 @@
 	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
 
 	/* Initialize the Input Drivers: special keys */
-	key_dev->evbit[0] = BIT(EV_KEY);
-	for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-		if (sony_laptop_inputkeys[i].inputev)
-			set_bit(sony_laptop_inputkeys[i].inputev,
-					key_dev->keybit);
+	set_bit(EV_KEY, key_dev->evbit);
+	set_bit(EV_MSC, key_dev->evbit);
+	set_bit(MSC_SCAN, key_dev->mscbit);
+	key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
+	key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
+	key_dev->keycode = &sony_laptop_input_keycode_map;
+	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
+		if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
+			set_bit(sony_laptop_input_keycode_map[i],
+				key_dev->keybit);
+		}
+	}
 
 	error = input_register_device(key_dev);
 	if (error)
@@ -487,6 +579,14 @@
 SNC_HANDLE_NAMES(lanpower_get, "GLNP");
 SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 
+SNC_HANDLE_NAMES(lidstate_get, "GLID");
+
+SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
+SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
+
+SNC_HANDLE_NAMES(gainbass_get, "GMGB");
+SNC_HANDLE_NAMES(gainbass_set, "CMGB");
+
 SNC_HANDLE_NAMES(PID_get, "GPID");
 
 SNC_HANDLE_NAMES(CTR_get, "GCTR");
@@ -507,6 +607,12 @@
 			boolean_validate, 0),
 	SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
 			boolean_validate, 1),
+	SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
+			boolean_validate, 0),
+	SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
+			boolean_validate, 0),
+	SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
+			boolean_validate, 0),
 	/* unknown methods */
 	SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
 	SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
@@ -689,13 +795,116 @@
 };
 
 /*
+ * New SNC-only Vaios event mapping to driver known keys
+ */
+struct sony_nc_event {
+	u8	data;
+	u8	event;
+};
+
+static struct sony_nc_event *sony_nc_events;
+
+/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
+ * for Fn keys
+ */
+static int sony_nc_C_enable(struct dmi_system_id *id)
+{
+	int result = 0;
+
+	printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
+
+	sony_nc_events = id->driver_data;
+
+	if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
+		printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
+				"functionalities may be missing\n");
+		return 1;
+	}
+	return 0;
+}
+
+static struct sony_nc_event sony_C_events[] = {
+	{ 0x81, SONYPI_EVENT_FNKEY_F1 },
+	{ 0x01, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x85, SONYPI_EVENT_FNKEY_F5 },
+	{ 0x05, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x86, SONYPI_EVENT_FNKEY_F6 },
+	{ 0x06, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x87, SONYPI_EVENT_FNKEY_F7 },
+	{ 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x8A, SONYPI_EVENT_FNKEY_F10 },
+	{ 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x8C, SONYPI_EVENT_FNKEY_F12 },
+	{ 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0, 0 },
+};
+
+/* SNC-only model map */
+struct dmi_system_id sony_nc_ids[] = {
+		{
+			.ident = "Sony Vaio FE Series",
+			.callback = sony_nc_C_enable,
+			.driver_data = sony_C_events,
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
+			},
+		},
+		{
+			.ident = "Sony Vaio C Series",
+			.callback = sony_nc_C_enable,
+			.driver_data = sony_C_events,
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
+			},
+		},
+		{ }
+};
+
+/*
  * ACPI callbacks
  */
 static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
-	dprintk("sony_acpi_notify, event: %d\n", event);
-	sony_laptop_report_input_event(event);
-	acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
+	struct sony_nc_event *evmap;
+	u32 ev = event;
+	int result;
+
+	if (ev == 0x92) {
+		/* read the key pressed from EC.GECR
+		 * A call to SN07 with 0x0202 will do it as well respecting
+		 * the current protocol on different OSes
+		 *
+		 * Note: the path for GECR may be
+		 *   \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
+		 *   \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
+		 *
+		 * TODO: we may want to do the same for the older GHKE -need
+		 *       dmi list- so this snippet may become one more callback.
+		 */
+		if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
+			dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
+		else
+			ev = result & 0xFF;
+	}
+
+	if (sony_nc_events)
+		for (evmap = sony_nc_events; evmap->event; evmap++) {
+			if (evmap->data == ev) {
+				ev = evmap->event;
+				break;
+			}
+		}
+
+	dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
+	sony_laptop_report_input_event(ev);
+	acpi_bus_generate_event(sony_nc_acpi_device, 1, ev);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -732,6 +941,10 @@
 			break;
 		}
 	}
+
+	/* re-initialize models with specific requirements */
+	dmi_check_system(sony_nc_ids);
+
 	return 0;
 }
 
@@ -750,6 +963,15 @@
 
 	sony_nc_acpi_handle = device->handle;
 
+	/* read device status */
+	result = acpi_bus_get_status(device);
+	/* bail IFF the above call was successful and the device is not present */
+	if (!result && !device->status.present) {
+		dprintk("Device not present\n");
+		result = -ENODEV;
+		goto outwalk;
+	}
+
 	if (debug) {
 		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
 					     1, sony_walk_callback, NULL, NULL);
@@ -760,6 +982,15 @@
 		}
 	}
 
+	/* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
+	 * should be respected as we already checked for the device presence above */
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
+		dprintk("Invoking _INI\n");
+		if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
+						NULL, NULL)))
+			dprintk("_INI Method failed\n");
+	}
+
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input();
 	if (result) {
@@ -772,7 +1003,7 @@
 					     ACPI_DEVICE_NOTIFY,
 					     sony_acpi_notify, NULL);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
+		printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
 		result = -ENODEV;
 		goto outinput;
 	}
@@ -795,6 +1026,9 @@
 
 	}
 
+	/* initialize models with specific requirements */
+	dmi_check_system(sony_nc_ids);
+
 	result = sony_pf_add();
 	if (result)
 		goto outbacklight;
@@ -908,7 +1142,9 @@
 #define SONYPI_DEVICE_TYPE2	0x00000002
 #define SONYPI_DEVICE_TYPE3	0x00000004
 
-#define SONY_PIC_EV_MASK	0xff
+#define SONYPI_TYPE1_OFFSET	0x04
+#define SONYPI_TYPE2_OFFSET	0x12
+#define SONYPI_TYPE3_OFFSET	0x12
 
 struct sony_pic_ioport {
 	struct acpi_resource_io	io;
@@ -922,6 +1158,7 @@
 
 struct sony_pic_dev {
 	int			model;
+	u16			evport_offset;
 	u8			camera_power;
 	u8			bluetooth_power;
 	u8			wwan_power;
@@ -1999,20 +2236,17 @@
 static irqreturn_t sony_pic_irq(int irq, void *dev_id)
 {
 	int i, j;
-	u32 port_val = 0;
 	u8 ev = 0;
 	u8 data_mask = 0;
 	u8 device_event = 0;
 
 	struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
 
-	acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
-			dev->cur_ioport->io.address_length);
-	ev = port_val & SONY_PIC_EV_MASK;
-	data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+	ev = inb_p(dev->cur_ioport->io.minimum);
+	data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
 
-	dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
-			port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+	dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+			ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
 
 	if (ev == 0x00 || ev == 0xff)
 		return IRQ_HANDLED;
@@ -2103,6 +2337,20 @@
 	spic_dev.model = sony_pic_detect_device_type();
 	mutex_init(&spic_dev.lock);
 
+	/* model specific characteristics */
+	switch(spic_dev.model) {
+		case SONYPI_DEVICE_TYPE1:
+			spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
+			break;
+		case SONYPI_DEVICE_TYPE3:
+			spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
+			break;
+		case SONYPI_DEVICE_TYPE2:
+		default:
+			spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
+			break;
+	}
+
 	/* read _PRS resources */
 	result = sony_pic_possible_resources(device);
 	if (result) {
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 95c0b96..f15a58f 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,8 +21,8 @@
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.14"
-#define TPACPI_SYSFS_VERSION 0x000100
+#define IBM_VERSION "0.15"
+#define TPACPI_SYSFS_VERSION 0x010000
 
 /*
  *  Changelog:
@@ -92,6 +92,29 @@
 /* Please remove this in year 2009 */
 MODULE_ALIAS("ibm_acpi");
 
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+	MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
 #define __unused __attribute__ ((unused))
 
 /****************************************************************************
@@ -106,7 +129,7 @@
  * ACPI basic handles
  */
 
-static acpi_handle root_handle = NULL;
+static acpi_handle root_handle;
 
 #define IBM_HANDLE(object, parent, paths...)			\
 	static acpi_handle  object##_handle;			\
@@ -487,19 +510,36 @@
 /****************************************************************************
  ****************************************************************************
  *
- * Device model: hwmon and platform
+ * Device model: input, hwmon and platform
  *
  ****************************************************************************
  ****************************************************************************/
 
-static struct platform_device *tpacpi_pdev = NULL;
-static struct class_device *tpacpi_hwmon = NULL;
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct input_dev *tpacpi_inputdev;
+
+
+static int tpacpi_resume_handler(struct platform_device *pdev)
+{
+	struct ibm_struct *ibm, *itmp;
+
+	list_for_each_entry_safe(ibm, itmp,
+				 &tpacpi_all_drivers,
+				 all_drivers) {
+		if (ibm->resume)
+			(ibm->resume)();
+	}
+
+	return 0;
+}
 
 static struct platform_driver tpacpi_pdriver = {
 	.driver = {
 		.name = IBM_DRVR_NAME,
 		.owner = THIS_MODULE,
 	},
+	.resume = tpacpi_resume_handler,
 };
 
 
@@ -677,9 +717,19 @@
 	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
 	printk(IBM_INFO "%s\n", IBM_URL);
 
-	if (ibm_thinkpad_ec_found)
-		printk(IBM_INFO "ThinkPad EC firmware %s\n",
-		       ibm_thinkpad_ec_found);
+	printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+		(thinkpad_id.bios_version_str) ?
+			thinkpad_id.bios_version_str : "unknown",
+		(thinkpad_id.ec_version_str) ?
+			thinkpad_id.ec_version_str : "unknown");
+
+	if (thinkpad_id.vendor && thinkpad_id.model_str)
+		printk(IBM_INFO "%s %s\n",
+			(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+				"IBM" : ((thinkpad_id.vendor ==
+						PCI_VENDOR_ID_LENOVO) ?
+					"Lenovo" : "Unknown vendor"),
+			thinkpad_id.model_str);
 
 	return 0;
 }
@@ -704,16 +754,28 @@
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
+static u32 hotkey_all_mask;
+static u32 hotkey_reserved_mask;
 
-static struct attribute_set *hotkey_dev_attributes = NULL;
+static u16 *hotkey_keycode_map;
+
+static struct attribute_set *hotkey_dev_attributes;
+
+static int hotkey_get_wlsw(int *status)
+{
+	if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+		return -EIO;
+	return 0;
+}
 
 /* sysfs hotkey enable ------------------------------------------------- */
 static ssize_t hotkey_enable_show(struct device *dev,
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	res = hotkey_get(&status, &mask);
 	if (res)
@@ -727,7 +789,8 @@
 			    const char *buf, size_t count)
 {
 	unsigned long t;
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	if (parse_strtoul(buf, 1, &t))
 		return -EINVAL;
@@ -748,13 +811,14 @@
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	res = hotkey_get(&status, &mask);
 	if (res)
 		return res;
 
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
 }
 
 static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +826,10 @@
 			    const char *buf, size_t count)
 {
 	unsigned long t;
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
-	if (parse_strtoul(buf, 0xffff, &t))
+	if (parse_strtoul(buf, 0xffffffffUL, &t))
 		return -EINVAL;
 
 	res = hotkey_get(&status, &mask);
@@ -794,26 +859,123 @@
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
 }
 
 static struct device_attribute dev_attr_hotkey_bios_mask =
 	__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
 
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_all_mask_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_all_mask =
+	__ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
+
+/* sysfs hotkey recommended_mask --------------------------------------- */
+static ssize_t hotkey_recommended_mask_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+			hotkey_all_mask & ~hotkey_reserved_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_recommended_mask =
+	__ATTR(hotkey_recommended_mask, S_IRUGO,
+		hotkey_recommended_mask_show, NULL);
+
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res, s;
+	res = hotkey_get_wlsw(&s);
+	if (res < 0)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+	__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
 /* --------------------------------------------------------------------- */
 
 static struct attribute *hotkey_mask_attributes[] = {
 	&dev_attr_hotkey_mask.attr,
 	&dev_attr_hotkey_bios_enabled.attr,
 	&dev_attr_hotkey_bios_mask.attr,
+	&dev_attr_hotkey_all_mask.attr,
+	&dev_attr_hotkey_recommended_mask.attr,
 };
 
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
-	int res;
+
+	static u16 ibm_keycode_map[] __initdata = {
+		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+		KEY_FN_F1,	KEY_FN_F2,	KEY_COFFEE,	KEY_SLEEP,
+		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,
+		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */
+		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */
+		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */
+		KEY_RESERVED,	/* 0x0F: FN+HOME (brightness up) */
+		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+		KEY_RESERVED,	/* 0x10: FN+END (brightness down) */
+		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
+		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
+		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
+		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
+		/* (assignments unknown, please report if found) */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+	};
+	static u16 lenovo_keycode_map[] __initdata = {
+		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+		KEY_FN_F1,	KEY_COFFEE,	KEY_BATTERY,	KEY_SLEEP,
+		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,
+		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */
+		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */
+		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */
+		KEY_BRIGHTNESSUP,	/* 0x0F: FN+HOME (brightness up) */
+		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+		KEY_BRIGHTNESSDOWN,	/* 0x10: FN+END (brightness down) */
+		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
+		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
+		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
+		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
+		/* (assignments unknown, please report if found) */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+	};
+
+#define TPACPI_HOTKEY_MAP_LEN		ARRAY_SIZE(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_SIZE		sizeof(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_TYPESIZE	sizeof(ibm_keycode_map[0])
+
+	int res, i;
+	int status;
 
 	vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
 
+	BUG_ON(!tpacpi_inputdev);
+
 	IBM_ACPIHANDLE_INIT(hkey);
 	mutex_init(&hotkey_mutex);
 
@@ -824,7 +986,7 @@
 		str_supported(tp_features.hotkey));
 
 	if (tp_features.hotkey) {
-		hotkey_dev_attributes = create_attr_set(4, NULL);
+		hotkey_dev_attributes = create_attr_set(7, NULL);
 		if (!hotkey_dev_attributes)
 			return -ENOMEM;
 		res = add_to_attr_set(hotkey_dev_attributes,
@@ -840,19 +1002,92 @@
 		vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
 			str_supported(tp_features.hotkey_mask));
 
+		if (tp_features.hotkey_mask) {
+			/* MHKA available in A31, R40, R40e, T4x, X31, and later */
+			if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+					"MHKA", "qd"))
+				hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+		}
+
 		res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
 		if (!res && tp_features.hotkey_mask) {
 			res = add_many_to_attr_set(hotkey_dev_attributes,
 				hotkey_mask_attributes,
 				ARRAY_SIZE(hotkey_mask_attributes));
 		}
+
+		/* Not all thinkpads have a hardware radio switch */
+		if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+			tp_features.hotkey_wlsw = 1;
+			printk(IBM_INFO
+				"radio switch found; radios are %s\n",
+				enabled(status, 0));
+			res = add_to_attr_set(hotkey_dev_attributes,
+					&dev_attr_hotkey_radio_sw.attr);
+		}
+
 		if (!res)
 			res = register_attr_set_with_sysfs(
 					hotkey_dev_attributes,
 					&tpacpi_pdev->dev.kobj);
-
 		if (res)
 			return res;
+
+		/* Set up key map */
+
+		hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+						GFP_KERNEL);
+		if (!hotkey_keycode_map) {
+			printk(IBM_ERR "failed to allocate memory for key map\n");
+			return -ENOMEM;
+		}
+
+		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+			dbg_printk(TPACPI_DBG_INIT,
+				   "using Lenovo default hot key map\n");
+			memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+				TPACPI_HOTKEY_MAP_SIZE);
+		} else {
+			dbg_printk(TPACPI_DBG_INIT,
+				   "using IBM default hot key map\n");
+			memcpy(hotkey_keycode_map, &ibm_keycode_map,
+				TPACPI_HOTKEY_MAP_SIZE);
+		}
+
+#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+		for (i = 0; i < 12; i++)
+			hotkey_keycode_map[i] = KEY_UNKNOWN;
+#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
+
+		set_bit(EV_KEY, tpacpi_inputdev->evbit);
+		set_bit(EV_MSC, tpacpi_inputdev->evbit);
+		set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+		tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+		tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+		tpacpi_inputdev->keycode = hotkey_keycode_map;
+		for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+			if (hotkey_keycode_map[i] != KEY_RESERVED) {
+				set_bit(hotkey_keycode_map[i],
+					tpacpi_inputdev->keybit);
+			} else {
+				if (i < sizeof(hotkey_reserved_mask)*8)
+					hotkey_reserved_mask |= 1 << i;
+			}
+		}
+
+		if (tp_features.hotkey_wlsw) {
+			set_bit(EV_SW, tpacpi_inputdev->evbit);
+			set_bit(SW_RADIO, tpacpi_inputdev->swbit);
+		}
+
+#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+		dbg_printk(TPACPI_DBG_INIT,
+				"enabling hot key handling\n");
+		res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
+					| hotkey_orig_mask);
+		if (res)
+			return res;
+#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
 	}
 
 	return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1110,101 @@
 	}
 }
 
+static void tpacpi_input_send_key(unsigned int scancode,
+				  unsigned int keycode)
+{
+	if (keycode != KEY_RESERVED) {
+		input_report_key(tpacpi_inputdev, keycode, 1);
+		if (keycode == KEY_UNKNOWN)
+			input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+				    scancode);
+		input_sync(tpacpi_inputdev);
+
+		input_report_key(tpacpi_inputdev, keycode, 0);
+		if (keycode == KEY_UNKNOWN)
+			input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+				    scancode);
+		input_sync(tpacpi_inputdev);
+	}
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+	int wlsw;
+
+	if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+		input_report_switch(tpacpi_inputdev,
+				    SW_RADIO, !!wlsw);
+}
+
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
-	int hkey;
+	u32 hkey;
+	unsigned int keycode, scancode;
+	int sendacpi = 1;
 
-	if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
-		acpi_bus_generate_event(ibm->acpi->device, event, hkey);
-	else {
-		printk(IBM_ERR "unknown hotkey event %d\n", event);
+	if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+		if (tpacpi_inputdev->users > 0) {
+			switch (hkey >> 12) {
+			case 1:
+				/* 0x1000-0x1FFF: key presses */
+				scancode = hkey & 0xfff;
+				if (scancode > 0 && scancode < 0x21) {
+					scancode--;
+					keycode = hotkey_keycode_map[scancode];
+					tpacpi_input_send_key(scancode, keycode);
+					sendacpi = (keycode == KEY_RESERVED
+						|| keycode == KEY_UNKNOWN);
+				} else {
+					printk(IBM_ERR
+					       "hotkey 0x%04x out of range for keyboard map\n",
+					       hkey);
+				}
+				break;
+			case 5:
+				/* 0x5000-0x5FFF: LID */
+				/* we don't handle it through this path, just
+				 * eat up known LID events */
+				if (hkey != 0x5001 && hkey != 0x5002) {
+					printk(IBM_ERR
+						"unknown LID-related hotkey event: 0x%04x\n",
+						hkey);
+				}
+				break;
+			case 7:
+				/* 0x7000-0x7FFF: misc */
+				if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+						tpacpi_input_send_radiosw();
+						sendacpi = 0;
+					break;
+				}
+				/* fallthrough to default */
+			default:
+				/* case 2: dock-related */
+				/*	0x2305 - T43 waking up due to bay lever eject while aslept */
+				/* case 3: ultra-bay related. maybe bay in dock? */
+				/*	0x3003 - T43 after wake up by bay lever eject (0x2305) */
+				printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
+			}
+		}
+
+		if (sendacpi)
+			acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+	} else {
+		printk(IBM_ERR "unknown hotkey notification event %d\n", event);
 		acpi_bus_generate_event(ibm->acpi->device, event, 0);
 	}
 }
 
+static void hotkey_resume(void)
+{
+	tpacpi_input_send_radiosw();
+}
+
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_get(int *status, int *mask)
+static int hotkey_get(int *status, u32 *mask)
 {
 	if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
 		return -EIO;
@@ -905,7 +1219,7 @@
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_set(int status, int mask)
+static int hotkey_set(int status, u32 mask)
 {
 	int i;
 
@@ -926,7 +1240,8 @@
 /* procfs -------------------------------------------------------------- */
 static int hotkey_read(char *p)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 	int len = 0;
 
 	if (!tp_features.hotkey) {
@@ -944,7 +1259,7 @@
 
 	len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
 	if (tp_features.hotkey_mask) {
-		len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+		len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
 		len += sprintf(p + len,
 			       "commands:\tenable, disable, reset, <mask>\n");
 	} else {
@@ -957,7 +1272,8 @@
 
 static int hotkey_write(char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 	char *cmd;
 	int do_cmd = 0;
 
@@ -1012,6 +1328,7 @@
 	.read = hotkey_read,
 	.write = hotkey_write,
 	.exit = hotkey_exit,
+	.resume = hotkey_resume,
 	.acpi = &ibm_hotkey_acpidriver,
 };
 
@@ -1770,7 +2087,10 @@
 	 .type = ACPI_SYSTEM_NOTIFY,
 	},
 	{
-	 .hid = IBM_PCI_HID,
+	/* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
+	 * We just use it to get notifications of dock hotplug
+	 * in very old thinkpads */
+	 .hid = PCI_ROOT_HID_STRING,
 	 .notify = dock_notify,
 	 .handle = &pci_handle,
 	 .type = ACPI_SYSTEM_NOTIFY,
@@ -1829,7 +2149,7 @@
 static void dock_notify(struct ibm_struct *ibm, u32 event)
 {
 	int docked = dock_docked();
-	int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+	int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
 
 	if (event == 1 && !pci)	/* 570 */
 		acpi_bus_generate_event(ibm->acpi->device, event, 1);	/* button */
@@ -2389,7 +2709,7 @@
 
 	acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
-	if (ibm_thinkpad_ec_found && experimental) {
+	if (thinkpad_id.ec_model) {
 		/*
 		 * Direct EC access mode: sensors at registers
 		 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
@@ -2533,6 +2853,8 @@
 			snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
 			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
 				return -EIO;
+			if (t > 127 || t < -127)
+				t = TP_EC_THERMAL_TMP_NA;
 			*value = t * 1000;
 			return 0;
 		}
@@ -2671,22 +2993,39 @@
  * Backlight/brightness subdriver
  */
 
-static struct backlight_device *ibm_backlight_device = NULL;
+static struct backlight_device *ibm_backlight_device;
 
 static struct backlight_ops ibm_backlight_data = {
         .get_brightness = brightness_get,
         .update_status  = brightness_update_status,
 };
 
+static struct mutex brightness_mutex;
+
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
 	int b;
 
 	vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
 
+	mutex_init(&brightness_mutex);
+
+	if (!brightness_mode) {
+		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+			brightness_mode = 2;
+		else
+			brightness_mode = 3;
+
+		dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+			brightness_mode);
+	}
+
+	if (brightness_mode > 3)
+		return -EINVAL;
+
 	b = brightness_get(NULL);
 	if (b < 0)
-		return b;
+		return 1;
 
 	ibm_backlight_device = backlight_device_register(
 					TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3061,79 @@
 				bd->props.brightness : 0);
 }
 
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
 static int brightness_get(struct backlight_device *bd)
 {
-	u8 level;
-	if (!acpi_ec_read(brightness_offset, &level))
-		return -EIO;
+	u8 lec = 0, lcmos = 0, level = 0;
 
-	level &= 0x7;
+	if (brightness_mode & 1) {
+		if (!acpi_ec_read(brightness_offset, &lec))
+			return -EIO;
+		lec &= 7;
+		level = lec;
+	};
+	if (brightness_mode & 2) {
+		lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+			 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+			>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+		level = lcmos;
+	}
+
+	if (brightness_mode == 3 && lec != lcmos) {
+		printk(IBM_ERR
+			"CMOS NVRAM (%u) and EC (%u) do not agree "
+			"on display brightness level\n",
+			(unsigned int) lcmos,
+			(unsigned int) lec);
+		return -EIO;
+	}
 
 	return level;
 }
 
 static int brightness_set(int value)
 {
-	int cmos_cmd, inc, i;
-	int current_value = brightness_get(NULL);
+	int cmos_cmd, inc, i, res;
+	int current_value;
 
-	value &= 7;
+	if (value > 7)
+		return -EINVAL;
 
-	cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
-	inc = value > current_value ? 1 : -1;
-	for (i = current_value; i != value; i += inc) {
-		if (issue_thinkpad_cmos_command(cmos_cmd))
-			return -EIO;
-		if (!acpi_ec_write(brightness_offset, i + inc))
-			return -EIO;
+	res = mutex_lock_interruptible(&brightness_mutex);
+	if (res < 0)
+		return res;
+
+	current_value = brightness_get(NULL);
+	if (current_value < 0) {
+		res = current_value;
+		goto errout;
 	}
 
-	return 0;
+	cmos_cmd = value > current_value ?
+			TP_CMOS_BRIGHTNESS_UP :
+			TP_CMOS_BRIGHTNESS_DOWN;
+	inc = value > current_value ? 1 : -1;
+
+	res = 0;
+	for (i = current_value; i != value; i += inc) {
+		if ((brightness_mode & 2) &&
+		    issue_thinkpad_cmos_command(cmos_cmd)) {
+			res = -EIO;
+			goto errout;
+		}
+		if ((brightness_mode & 1) &&
+		    !acpi_ec_write(brightness_offset, i + inc)) {
+			res = -EIO;
+			goto errout;;
+		}
+	}
+
+errout:
+	mutex_unlock(&brightness_mutex);
+	return res;
 }
 
 static int brightness_read(char *p)
@@ -3273,20 +3657,19 @@
 			 * Enable for TP-1Y (T43), TP-78 (R51e),
 			 * TP-76 (R52), TP-70 (T43, R52), which are known
 			 * to be buggy. */
-			if (fan_control_initial_status == 0x07 &&
-			    ibm_thinkpad_ec_found &&
-			    ((ibm_thinkpad_ec_found[0] == '1' &&
-			      ibm_thinkpad_ec_found[1] == 'Y') ||
-			     (ibm_thinkpad_ec_found[0] == '7' &&
-			      (ibm_thinkpad_ec_found[1] == '6' ||
-			       ibm_thinkpad_ec_found[1] == '8' ||
-			       ibm_thinkpad_ec_found[1] == '0'))
-			    )) {
-				printk(IBM_NOTICE
-				       "fan_init: initial fan status is "
-				       "unknown, assuming it is in auto "
-				       "mode\n");
-				tp_features.fan_ctrl_status_undef = 1;
+			if (fan_control_initial_status == 0x07) {
+				switch (thinkpad_id.ec_model) {
+				case 0x5931: /* TP-1Y */
+				case 0x3837: /* TP-78 */
+				case 0x3637: /* TP-76 */
+				case 0x3037: /* TP-70 */
+					printk(IBM_NOTICE
+					       "fan_init: initial fan status is "
+					       "unknown, assuming it is in auto "
+					       "mode\n");
+					tp_features.fan_ctrl_status_undef = 1;
+					;;
+				}
 			}
 		} else {
 			printk(IBM_ERR
@@ -3474,7 +3857,7 @@
 
 static void fan_watchdog_reset(void)
 {
-	static int fan_watchdog_active = 0;
+	static int fan_watchdog_active;
 
 	if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
 		return;
@@ -3877,7 +4260,7 @@
  ****************************************************************************/
 
 /* /proc support */
-static struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir;
 
 /* Subdriver registry */
 static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4403,30 @@
 
 /* Probing */
 
-static char *ibm_thinkpad_ec_found = NULL;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 {
 	struct dmi_device *dev = NULL;
 	char ec_fw_string[18];
 
+	if (!tp)
+		return;
+
+	memset(tp, 0, sizeof(*tp));
+
+	if (dmi_name_in_vendors("IBM"))
+		tp->vendor = PCI_VENDOR_ID_IBM;
+	else if (dmi_name_in_vendors("LENOVO"))
+		tp->vendor = PCI_VENDOR_ID_LENOVO;
+	else
+		return;
+
+	tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+					GFP_KERNEL);
+	if (!tp->bios_version_str)
+		return;
+	tp->bios_model = tp->bios_version_str[0]
+			 | (tp->bios_version_str[1] << 8);
+
 	/*
 	 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
 	 * X32 or newer, all Z series;  Some models must have an
@@ -4040,10 +4440,20 @@
 			   ec_fw_string) == 1) {
 			ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
 			ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-			return kstrdup(ec_fw_string, GFP_KERNEL);
+
+			tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+			tp->ec_model = ec_fw_string[0]
+					| (ec_fw_string[1] << 8);
+			break;
 		}
 	}
-	return NULL;
+
+	tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+					GFP_KERNEL);
+	if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+		kfree(tp->model_str);
+		tp->model_str = NULL;
+	}
 }
 
 static int __init probe_for_thinkpad(void)
@@ -4057,7 +4467,7 @@
 	 * Non-ancient models have better DMI tagging, but very old models
 	 * don't.
 	 */
-	is_thinkpad = dmi_name_in_vendors("ThinkPad");
+	is_thinkpad = (thinkpad_id.model_str != NULL);
 
 	/* ec is required because many other handles are relative to it */
 	IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4483,7 @@
 	 * false positives a damn great deal
 	 */
 	if (!is_thinkpad)
-		is_thinkpad = dmi_name_in_vendors("IBM");
+		is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
 
 	if (!is_thinkpad && !force_load)
 		return -ENODEV;
@@ -4185,10 +4595,13 @@
 module_param_named(debug, dbg_level, uint, 0);
 
 static int force_load;
-module_param(force_load, int, 0);
+module_param(force_load, bool, 0);
 
 static int fan_control_allowed;
-module_param_named(fan_control, fan_control_allowed, int, 0);
+module_param_named(fan_control, fan_control_allowed, bool, 0);
+
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
 
 #define IBM_PARAM(feature) \
 	module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4216,12 +4629,16 @@
 	int ret, i;
 
 	/* Driver-level probe */
+
+	get_thinkpad_model_data(&thinkpad_id);
 	ret = probe_for_thinkpad();
-	if (ret)
+	if (ret) {
+		thinkpad_acpi_module_exit();
 		return ret;
+	}
 
 	/* Driver initialization */
-	ibm_thinkpad_ec_found = check_dmi_for_ec();
+
 	IBM_ACPIHANDLE_INIT(ecrd);
 	IBM_ACPIHANDLE_INIT(ecwr);
 
@@ -4265,6 +4682,22 @@
 		thinkpad_acpi_module_exit();
 		return ret;
 	}
+	tpacpi_inputdev = input_allocate_device();
+	if (!tpacpi_inputdev) {
+		printk(IBM_ERR "unable to allocate input device\n");
+		thinkpad_acpi_module_exit();
+		return -ENOMEM;
+	} else {
+		/* Prepare input device, but don't register */
+		tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+		tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+		tpacpi_inputdev->id.bustype = BUS_HOST;
+		tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+						thinkpad_id.vendor :
+						PCI_VENDOR_ID_IBM;
+		tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+		tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+	}
 	for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
 		ret = ibm_init(&ibms_init[i]);
 		if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4707,14 @@
 			return ret;
 		}
 	}
+	ret = input_register_device(tpacpi_inputdev);
+	if (ret < 0) {
+		printk(IBM_ERR "unable to register input device\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	} else {
+		tp_features.input_device_registered = 1;
+	}
 
 	return 0;
 }
@@ -4290,6 +4731,13 @@
 
 	dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
 
+	if (tpacpi_inputdev) {
+		if (tp_features.input_device_registered)
+			input_unregister_device(tpacpi_inputdev);
+		else
+			input_free_device(tpacpi_inputdev);
+	}
+
 	if (tpacpi_hwmon)
 		hwmon_device_unregister(tpacpi_hwmon);
 
@@ -4302,7 +4750,9 @@
 	if (proc_dir)
 		remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
 
-	kfree(ibm_thinkpad_ec_found);
+	kfree(thinkpad_id.bios_version_str);
+	kfree(thinkpad_id.ec_version_str);
+	kfree(thinkpad_id.model_str);
 }
 
 module_init(thinkpad_acpi_module_init);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 72d62f2..b7a4a88 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 
+#include <linux/nvram.h>
 #include <linux/proc_fs.h>
 #include <linux/sysfs.h>
 #include <linux/backlight.h>
@@ -39,6 +40,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
 #include <asm/uaccess.h>
 
 #include <linux/dmi.h>
@@ -48,6 +50,7 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acnamesp.h>
 
+#include <linux/pci_ids.h>
 
 /****************************************************************************
  * Main driver
@@ -78,6 +81,11 @@
 #define TP_CMOS_BRIGHTNESS_UP	4
 #define TP_CMOS_BRIGHTNESS_DOWN	5
 
+/* ThinkPad CMOS NVRAM constants */
+#define TP_NVRAM_ADDR_BRIGHTNESS       0x5e
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
+
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@
 #define vdbg_printk(a_dbg_level, format, arg...)
 #endif
 
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_VENDOR	PCI_VENDOR_ID_IBM
+#define TPACPI_HKEY_INPUT_PRODUCT	0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION	0x4101
+
 /* ACPI HIDs */
 #define IBM_HKEY_HID    "IBM0068"
-#define IBM_PCI_HID     "PNP0A03"
 
 /* ACPI helpers */
 static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@
 static struct platform_device *tpacpi_pdev;
 static struct class_device *tpacpi_hwmon;
 static struct platform_driver tpacpi_pdriver;
+static struct input_dev *tpacpi_inputdev;
 static int tpacpi_create_driver_attributes(struct device_driver *drv);
 static void tpacpi_remove_driver_attributes(struct device_driver *drv);
 
@@ -168,9 +181,7 @@
 static int experimental;
 static u32 dbg_level;
 static int force_load;
-static char *ibm_thinkpad_ec_found;
 
-static char* check_dmi_for_ec(void);
 static int thinkpad_acpi_module_init(void);
 static void thinkpad_acpi_module_exit(void);
 
@@ -197,6 +208,7 @@
 	int (*read) (char *);
 	int (*write) (char *);
 	void (*exit) (void);
+	void (*resume) (void);
 
 	struct list_head all_drivers;
 
@@ -228,12 +240,29 @@
 	u16 bluetooth:1;
 	u16 hotkey:1;
 	u16 hotkey_mask:1;
+	u16 hotkey_wlsw:1;
 	u16 light:1;
 	u16 light_status:1;
 	u16 wan:1;
 	u16 fan_ctrl_status_undef:1;
+	u16 input_device_registered:1;
 } tp_features;
 
+struct thinkpad_id_data {
+	unsigned int vendor;	/* ThinkPad vendor:
+				 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+	char *bios_version_str;	/* Something like 1ZET51WW (1.03z) */
+	char *ec_version_str;	/* Something like 1ZHT51WW-1.04a */
+
+	u16 bios_model;		/* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+	u16 ec_model;
+
+	char *model_str;
+};
+
+static struct thinkpad_id_data thinkpad_id;
+
 static struct list_head tpacpi_all_drivers;
 
 static struct ibm_init_struct ibms_init[];
@@ -300,6 +329,7 @@
 
 static struct backlight_device *ibm_backlight_device;
 static int brightness_offset = 0x31;
+static int brightness_mode;
 
 static int brightness_init(struct ibm_init_struct *iibm);
 static void brightness_exit(void);
@@ -415,14 +445,14 @@
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
 
 static struct mutex hotkey_mutex;
 
 static int hotkey_init(struct ibm_init_struct *iibm);
 static void hotkey_exit(void);
-static int hotkey_get(int *status, int *mask);
-static int hotkey_set(int status, int mask);
+static int hotkey_get(int *status, u32 *mask);
+static int hotkey_set(int status, u32 mask);
 static void hotkey_notify(struct ibm_struct *ibm, u32 event);
 static int hotkey_read(char *p);
 static int hotkey_write(char *buf);
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 28c8818..15aab37 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -903,8 +903,10 @@
 	/*
 	 * Add host to MMC layer
 	 */
-	if (host->board->det_pin)
+	if (host->board->det_pin) {
 		host->present = !at91_get_gpio_value(host->board->det_pin);
+		device_init_wakeup(&pdev->dev, 1);
+	}
 	else
 		host->present = -1;
 
@@ -940,6 +942,7 @@
 	host = mmc_priv(mmc);
 
 	if (host->present != -1) {
+		device_init_wakeup(&pdev->dev, 0);
 		free_irq(host->board->det_pin, host);
 		cancel_delayed_work(&host->mmc->detect);
 	}
@@ -966,8 +969,12 @@
 static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct at91mci_host *host = mmc_priv(mmc);
 	int ret = 0;
 
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(host->board->det_pin);
+
 	if (mmc)
 		ret = mmc_suspend_host(mmc, state);
 
@@ -977,8 +984,12 @@
 static int at91_mci_resume(struct platform_device *pdev)
 {
 	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct at91mci_host *host = mmc_priv(mmc);
 	int ret = 0;
 
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(host->board->det_pin);
+
 	if (mmc)
 		ret = mmc_resume_host(mmc);
 
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 10d15c3..4a24db0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1024,6 +1024,8 @@
 
 	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
 
+	intmask &= ~SDHCI_INT_ERROR;
+
 	if (intmask & SDHCI_INT_BUS_POWER) {
 		printk(KERN_ERR "%s: Card is consuming too much power!\n",
 			mmc_hostname(host->mmc));
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7400f4b..a6c8704 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -107,6 +107,7 @@
 #define  SDHCI_INT_CARD_INSERT	0x00000040
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
 #define  SDHCI_INT_CRC		0x00020000
 #define  SDHCI_INT_END_BIT	0x00040000
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3073f67..f8a602c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -5,6 +5,7 @@
 
 menuconfig NETDEVICES
 	default y if UML
+	depends on NET
 	bool "Network device support"
 	---help---
 	  You can say N here if you don't intend to connect your Linux box to
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 829da9a..2098d0a 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -155,6 +155,15 @@
 	  To compile it as a module, choose M here: the module will be called
 	  kingsun-sir.
 
+config EP7211_DONGLE
+	tristate "EP7211 I/R support"
+	depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+	help
+	  Say Y here if you want to build support for the Cirrus logic
+	  EP7211 chipset's infrared module.
+
+
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
@@ -355,7 +364,7 @@
 
 config TOSHIBA_FIR
 	tristate "Toshiba Type-O IR Port"
-	depends on IRDA && PCI && !64BIT
+	depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
 	help
 	  Say Y here if you want to build support for the Toshiba Type-O IR
 	  and Donau oboe chipsets. These chipsets are used by the Toshiba
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 233a2f9..2808ef5 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_ACT200L_DONGLE)	+= act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)	+= ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)	+= toim3232-sir.o
+obj-$(CONFIG_EP7211_DONGLE)	+= ep7211-sir.o
 obj-$(CONFIG_KINGSUN_DONGLE)	+= kingsun-sir.o
 
 # The SIR helper module
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
new file mode 100644
index 0000000..8315724
--- /dev/null
+++ b/drivers/net/irda/ep7211-sir.c
@@ -0,0 +1,89 @@
+/*
+ * IR port driver for the Cirrus Logic EP7211 processor.
+ *
+ * Copyright 2001, Blue Mug Inc.  All rights reserved.
+ * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "sir-dev.h"
+
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000   /* 1 ms */
+
+static int ep7211_open(struct sir_dev *dev);
+static int ep7211_close(struct sir_dev *dev);
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed);
+static int ep7211_reset(struct sir_dev *dev);
+
+static struct dongle_driver ep7211 = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "EP7211 IR driver",
+	.type		= IRDA_EP7211_DONGLE,
+	.open		= ep7211_open,
+	.close		= ep7211_close,
+	.reset		= ep7211_reset,
+	.set_speed	= ep7211_change_speed,
+};
+
+static int __init ep7211_sir_init(void)
+{
+	return irda_register_dongle(&ep7211);
+}
+
+static void __exit ep7211_sir_cleanup(void)
+{
+	irda_unregister_dongle(&ep7211);
+}
+
+static int ep7211_open(struct sir_dev *dev)
+{
+	unsigned int syscon;
+
+	/* Turn on the SIR encoder. */
+	syscon = clps_readl(SYSCON1);
+	syscon |= SYSCON1_SIREN;
+	clps_writel(syscon, SYSCON1);
+
+	return 0;
+}
+
+static int ep7211_close(struct sir_dev *dev)
+{
+	unsigned int syscon;
+
+	/* Turn off the SIR encoder. */
+	syscon = clps_readl(SYSCON1);
+	syscon &= ~SYSCON1_SIREN;
+	clps_writel(syscon, SYSCON1);
+
+	return 0;
+}
+
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	return 0;
+}
+
+static int ep7211_reset(struct sir_dev *dev)
+{
+	return 0;
+}
+
+MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
+MODULE_DESCRIPTION("EP7211 IR dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
+
+module_init(ep7211_sir_init);
+module_exit(ep7211_sir_cleanup);
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 26a3b45..62c1c62 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -608,7 +608,7 @@
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 MODULE_LICENSE("GPL");
 
-int
+int __init
 init_module(void)
 {
 	net_debug = debug;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a2f3215..13f08a3 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -692,6 +692,7 @@
 {
 	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
 	u16 reg;
+	u32 rx_reg;
 	int i;
 	const u8 *addr = hw->dev[port]->dev_addr;
 
@@ -768,11 +769,11 @@
 
 	/* Configure Rx MAC FIFO */
 	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-	reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+	rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
 	if (hw->chip_id == CHIP_ID_YUKON_EX)
-		reg |= GMF_RX_OVER_ON;
+		rx_reg |= GMF_RX_OVER_ON;
 
-	sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+	sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
 
 	/* Flush Rx MAC FIFO on any flow control or error */
 	sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index b801e3b..61f9825 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -459,6 +459,22 @@
 	return 0;
 }
 
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+	struct vio_net_mcast_info *pkt = msgbuf;
+
+	if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+		printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+		       "[%02x:%02x:%04x:%08x]\n",
+		       port->vp->dev->name,
+		       pkt->tag.type,
+		       pkt->tag.stype,
+		       pkt->tag.stype_env,
+		       pkt->tag.sid);
+
+	return 0;
+}
+
 static void maybe_tx_wakeup(struct vnet *vp)
 {
 	struct net_device *dev = vp->dev;
@@ -544,7 +560,10 @@
 				err = vnet_nack(port, &msgbuf);
 			}
 		} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
-			err = vio_control_pkt_engine(vio, &msgbuf);
+			if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+				err = handle_mcast(port, &msgbuf);
+			else
+				err = vio_control_pkt_engine(vio, &msgbuf);
 			if (err)
 				break;
 		} else {
@@ -731,9 +750,122 @@
 	return 0;
 }
 
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+	struct vnet_mcast_entry *m;
+
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (!memcmp(m->addr, addr, ETH_ALEN))
+			return m;
+	}
+	return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+	struct dev_addr_list *p;
+
+	for (p = dev->mc_list; p; p = p->next) {
+		struct vnet_mcast_entry *m;
+
+		m = __vnet_mc_find(vp, p->dmi_addr);
+		if (m) {
+			m->hit = 1;
+			continue;
+		}
+
+		if (!m) {
+			m = kzalloc(sizeof(*m), GFP_ATOMIC);
+			if (!m)
+				continue;
+			memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+			m->hit = 1;
+
+			m->next = vp->mcast_list;
+			vp->mcast_list = m;
+		}
+	}
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+	struct vio_net_mcast_info info;
+	struct vnet_mcast_entry *m, **pp;
+	int n_addrs;
+
+	memset(&info, 0, sizeof(info));
+
+	info.tag.type = VIO_TYPE_CTRL;
+	info.tag.stype = VIO_SUBTYPE_INFO;
+	info.tag.stype_env = VNET_MCAST_INFO;
+	info.tag.sid = vio_send_sid(&port->vio);
+	info.set = 1;
+
+	n_addrs = 0;
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (m->sent)
+			continue;
+		m->sent = 1;
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+
+	info.set = 0;
+
+	n_addrs = 0;
+	pp = &vp->mcast_list;
+	while ((m = *pp) != NULL) {
+		if (m->hit) {
+			m->hit = 0;
+			pp = &m->next;
+			continue;
+		}
+
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+
+		*pp = m->next;
+		kfree(m);
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+}
+
 static void vnet_set_rx_mode(struct net_device *dev)
 {
-	/* XXX Implement multicast support XXX */
+	struct vnet *vp = netdev_priv(dev);
+	struct vnet_port *port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vp->lock, flags);
+	if (!list_empty(&vp->port_list)) {
+		port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+		if (port->switch_port) {
+			__update_mc_list(vp, dev);
+			__send_mc_list(vp, port);
+		}
+	}
+	spin_unlock_irqrestore(&vp->lock, flags);
 }
 
 static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -1070,6 +1202,7 @@
 	switch_port = 0;
 	if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
 		switch_port = 1;
+	port->switch_port = switch_port;
 
 	spin_lock_irqsave(&vp->lock, flags);
 	if (switch_port)
@@ -1136,7 +1269,7 @@
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
 
 static struct vio_driver vnet_port_driver = {
 	.id_table	= vnet_port_match,
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 7d3a0ca..d347a5b 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -30,6 +30,8 @@
 
 	struct hlist_node	hash;
 	u8			raddr[ETH_ALEN];
+	u8			switch_port;
+	u8			__pad;
 
 	struct vnet		*vp;
 
@@ -53,6 +55,13 @@
 	return val & (VNET_PORT_HASH_MASK);
 }
 
+struct vnet_mcast_entry {
+	u8			addr[ETH_ALEN];
+	u8			sent;
+	u8			hit;
+	struct vnet_mcast_entry	*next;
+};
+
 struct vnet {
 	/* Protects port_list and port_hash.  */
 	spinlock_t		lock;
@@ -65,6 +74,8 @@
 
 	struct hlist_head	port_hash[VNET_PORT_HASH_SIZE];
 
+	struct vnet_mcast_entry	*mcast_list;
+
 	struct list_head	list;
 	u64			local_mac;
 };
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 0000000..c03072b
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,3 @@
+config OF_DEVICE
+	def_bool y
+	depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 0000000..ab9be5d
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 0000000..9377f3b
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+	const int *ip;
+
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = of_get_property(np, "#address-cells", NULL);
+		if (ip)
+			return *ip;
+	} while (np->parent);
+	/* No #address-cells property for the root node */
+	return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+	const int *ip;
+
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = of_get_property(np, "#size-cells", NULL);
+		if (ip)
+			return *ip;
+	} while (np->parent);
+	/* No #size-cells property for the root node */
+	return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+				  const char *name,
+				  int *lenp)
+{
+	struct property *pp;
+
+	read_lock(&devtree_lock);
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		if (of_prop_cmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			break;
+		}
+	}
+	read_unlock(&devtree_lock);
+
+	return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+			 int *lenp)
+{
+	struct property *pp = of_find_property(np, name, lenp);
+
+	return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+		const char *compat)
+{
+	const char* cp;
+	int cplen, l;
+
+	cp = of_get_property(device, "compatible", &cplen);
+	if (cp == NULL)
+		return 0;
+	while (cplen > 0) {
+		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+			return 1;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ *	of_get_parent - Get a node's parent if any
+ *	@node:	Node to get parent
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+	struct device_node *np;
+
+	if (!node)
+		return NULL;
+
+	read_lock(&devtree_lock);
+	np = of_node_get(node->parent);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ *	of_get_next_child - Iterate a node childs
+ *	@node:	parent node
+ *	@prev:	previous child of the parent node, or NULL to get first
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+	struct device_node *prev)
+{
+	struct device_node *next;
+
+	read_lock(&devtree_lock);
+	next = prev ? prev->sibling : node->child;
+	for (; next; next = next->sibling)
+		if (of_node_get(next))
+			break;
+	of_node_put(prev);
+	read_unlock(&devtree_lock);
+	return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ *	of_find_node_by_path - Find a node matching a full OF path
+ *	@path:	The full path to match
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+	struct device_node *np = allnodes;
+
+	read_lock(&devtree_lock);
+	for (; np; np = np->allnext) {
+		if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+		    && of_node_get(np))
+			break;
+	}
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ *	of_find_node_by_name - Find a node by its "name" property
+ *	@from:	The node to start searching from or NULL, the node
+ *		you pass will not be searched, only the next one
+ *		will; typically, you pass what the previous call
+ *		returned. of_node_put() will be called on it
+ *	@name:	The name string to match against
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+	const char *name)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext)
+		if (np->name && (of_node_cmp(np->name, name) == 0)
+		    && of_node_get(np))
+			break;
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ *	of_find_node_by_type - Find a node by its "device_type" property
+ *	@from:	The node to start searching from, or NULL to start searching
+ *		the entire device tree. The node you pass will not be
+ *		searched, only the next one will; typically, you pass
+ *		what the previous call returned. of_node_put() will be
+ *		called on from for you.
+ *	@type:	The type string to match against
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+	const char *type)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext)
+		if (np->type && (of_node_cmp(np->type, type) == 0)
+		    && of_node_get(np))
+			break;
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ *	of_find_compatible_node - Find a node based on type and one of the
+ *                                tokens in its "compatible" property
+ *	@from:		The node to start searching from or NULL, the node
+ *			you pass will not be searched, only the next one
+ *			will; typically, you pass what the previous call
+ *			returned. of_node_put() will be called on it
+ *	@type:		The type string to match "device_type" or NULL to ignore
+ *	@compatible:	The string to match to one of the tokens in the device
+ *			"compatible" list.
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+	const char *type, const char *compatible)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext) {
+		if (type
+		    && !(np->type && (of_node_cmp(np->type, type) == 0)))
+			continue;
+		if (of_device_is_compatible(np, compatible) && of_node_get(np))
+			break;
+	}
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644
index 0000000..6245f06
--- /dev/null
+++ b/drivers/of/device.c
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+					 const struct device_node *node)
+{
+	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+		int match = 1;
+		if (matches->name[0])
+			match &= node->name
+				&& !strcmp(matches->name, node->name);
+		if (matches->type[0])
+			match &= node->type
+				&& !strcmp(matches->type, node->type);
+		if (matches->compatible[0])
+			match &= of_device_is_compatible(node,
+						matches->compatible);
+		if (match)
+			return matches;
+		matches++;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+					const struct of_device *dev)
+{
+	if (!dev->node)
+		return NULL;
+	return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+	struct device *tmp;
+
+	if (!dev)
+		return NULL;
+	tmp = get_device(&dev->dev);
+	if (tmp)
+		return to_of_device(tmp);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct of_device *ofdev;
+
+	ofdev = to_of_device(dev);
+	return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+	struct of_device *ofdev;
+
+	ofdev = to_of_device(dev);
+	of_node_put(ofdev->node);
+	kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+	int rc;
+
+	BUG_ON(ofdev->node == NULL);
+
+	rc = device_register(&ofdev->dev);
+	if (rc)
+		return rc;
+
+	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+	if (rc)
+		device_unregister(&ofdev->dev);
+
+	return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+	device_remove_file(&ofdev->dev, &dev_attr_devspec);
+	device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644
index 0000000..864f09f
--- /dev/null
+++ b/drivers/of/platform.c
@@ -0,0 +1,96 @@
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@kernel.crashing.org>
+ *    and		 Arnd Bergmann, IBM Corp.
+ *    Merged from powerpc/kernel/of_platform.c and
+ *    sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ *  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/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+	const struct of_device_id *matches = of_drv->match_table;
+
+	if (!matches)
+		return 0;
+
+	return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct of_platform_driver *drv;
+	struct of_device *of_dev;
+	const struct of_device_id *match;
+
+	drv = to_of_platform_driver(dev->driver);
+	of_dev = to_of_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	of_dev_get(of_dev);
+
+	match = of_match_device(drv->match_table, of_dev);
+	if (match)
+		error = drv->probe(of_dev, match);
+	if (error)
+		of_dev_put(of_dev);
+
+	return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(of_dev);
+	return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(of_dev, state);
+	return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(of_dev);
+	return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+	bus->name = name;
+	bus->match = of_platform_bus_match;
+	bus->probe = of_platform_device_probe;
+	bus->remove = of_platform_device_remove;
+	bus->suspend = of_platform_device_suspend;
+	bus->resume = of_platform_device_resume;
+	return bus_register(bus);
+}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index edd6de9..8134c7e 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
 #include <linux/profile.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/oprofile.h>
 #include <linux/sched.h>
- 
+
 #include "oprofile_stats.h"
 #include "event_buffer.h"
 #include "cpu_buffer.h"
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 9b6a4eb..5076ed1 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@
  
 /* wake up the process sleeping on the event file */
 void wake_up_buffer_waiter(void);
- 
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE			~0UL
-#define CTX_SWITCH_CODE 		1
-#define CPU_SWITCH_CODE 		2
-#define COOKIE_SWITCH_CODE 		3
-#define KERNEL_ENTER_SWITCH_CODE	4
-#define KERNEL_EXIT_SWITCH_CODE		5
-#define MODULE_LOADED_CODE		6
-#define CTX_TGID_CODE			7
-#define TRACE_BEGIN_CODE		8
-#define TRACE_END_CODE			9
- 
+
 #define INVALID_COOKIE ~0UL
 #define NO_COOKIE 0UL
 
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
- 
 extern const struct file_operations event_buffer_fops;
  
 /* mutex between sync_cpu_buffers() and the
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index e5162a6..2c64517 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@
 	 * us missing task deaths and eventually oopsing
 	 * when trying to process the event buffer.
 	 */
+	if (oprofile_ops.sync_start) {
+		int sync_ret = oprofile_ops.sync_start();
+		switch (sync_ret) {
+		case 0:
+			goto post_sync;
+		case 1:
+			goto do_generic;
+		case -1:
+			goto out3;
+		default:
+			goto out3;
+		}
+	}
+do_generic:
 	if ((err = sync_start()))
 		goto out3;
 
+post_sync:
 	is_setup = 1;
 	mutex_unlock(&start_mutex);
 	return 0;
@@ -118,7 +133,20 @@
 void oprofile_shutdown(void)
 {
 	mutex_lock(&start_mutex);
+	if (oprofile_ops.sync_stop) {
+		int sync_ret = oprofile_ops.sync_stop();
+		switch (sync_ret) {
+		case 0:
+			goto post_sync;
+		case 1:
+			goto do_generic;
+		default:
+			goto post_sync;
+		}
+	}
+do_generic:
 	sync_stop();
+post_sync:
 	if (oprofile_ops.shutdown)
 		oprofile_ops.shutdown();
 	is_setup = 0;
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 09c93ff9..d449b15 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -35,7 +35,7 @@
 
 config PARPORT_PC
 	tristate "PC-style hardware"
-	depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+	depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
 	---help---
 	  You should say Y here if you have a PC-style parallel port. All
 	  IBM PC compatible computers and some Alphas have PC-style
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 3c45142..b019854 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1316,7 +1316,7 @@
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-	.name = (char *)driver_name,
+	.name = driver_name,
 	.match_table = m8xx_pcmcia_match,
 	.probe = m8xx_probe,
 	.remove = m8xx_remove,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cea401f..9d8d40d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -38,6 +38,9 @@
 	  clock, usually rtc0.  Initialization is done when the system
 	  starts up, and when it resumes from a low power state.
 
+	  The driver for this RTC device must be loaded before late_initcall
+	  functions run, so it must usually be statically linked.
+
 	  This clock should be battery-backed, so that it reads the correct
 	  time when the system boots from a power-off state.  Otherwise, your
 	  system will need an external clock source (like an NTP server).
@@ -305,6 +308,16 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1553.
 
+config RTC_DRV_STK17TA8
+	tristate "Simtek STK17TA8"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Simtek STK17TA8 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-stk17ta8.
+
 config RTC_DRV_DS1742
 	tristate "Dallas DS1742/1743"
 	depends on RTC_CLASS
@@ -394,7 +407,7 @@
 
 config RTC_DRV_SH
 	tristate "SuperH On-Chip RTC"
-	depends on RTC_CLASS && SUPERH
+	depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4)
 	help
 	  Say Y here to enable support for the on-chip RTC found in
 	  most SuperH processors.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 3109af9..7ede9e7 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -32,6 +32,7 @@
 obj-$(CONFIG_RTC_DRV_M41T80)	+= rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
+obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index f98a83a1..46da571 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -407,7 +407,7 @@
 
 static __exit void ds1553_exit(void)
 {
-	return platform_driver_unregister(&ds1553_rtc_driver);
+	platform_driver_unregister(&ds1553_rtc_driver);
 }
 
 module_init(ds1553_init);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index d1778ae..b2e5481 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -263,7 +263,7 @@
 
 static __exit void ds1742_exit(void)
 {
-	return platform_driver_unregister(&ds1742_rtc_driver);
+	platform_driver_unregister(&ds1742_rtc_driver);
 }
 
 module_init(ds1742_init);
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index eee4ee5..a1cd448 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -31,17 +31,24 @@
 #define MAX6900_REG_DW			5	/* day of week	 1-7  */
 #define MAX6900_REG_YR			6	/* year		00-99 */
 #define MAX6900_REG_CT			7	/* control */
-#define MAX6900_REG_LEN			8
+						/* register 8 is undocumented */
+#define MAX6900_REG_CENTURY		9	/* century */
+#define MAX6900_REG_LEN			10
+
+#define MAX6900_BURST_LEN		8	/* can burst r/w first 8 regs */
 
 #define MAX6900_REG_CT_WP		(1 << 7)	/* Write Protect */
 
+
 /*
  * register read/write commands
  */
 #define MAX6900_REG_CONTROL_WRITE	0x8e
-#define MAX6900_REG_BURST_READ		0xbf
-#define MAX6900_REG_BURST_WRITE		0xbe
+#define MAX6900_REG_CENTURY_WRITE	0x92
+#define MAX6900_REG_CENTURY_READ	0x93
 #define MAX6900_REG_RESERVED_READ	0x96
+#define MAX6900_REG_BURST_WRITE		0xbe
+#define MAX6900_REG_BURST_READ		0xbf
 
 #define MAX6900_IDLE_TIME_AFTER_WRITE	3	/* specification says 2.5 mS */
 
@@ -58,19 +65,32 @@
 
 static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
 {
-	u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
-	struct i2c_msg msgs[2] = {
+	u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
+	u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
+	struct i2c_msg msgs[4] = {
 		{
 			.addr	= client->addr,
 			.flags	= 0, /* write */
-			.len	= sizeof(reg_addr),
-			.buf	= reg_addr
+			.len	= sizeof(reg_burst_read),
+			.buf	= reg_burst_read
 		},
 		{
 			.addr	= client->addr,
 			.flags	= I2C_M_RD,
-			.len	= MAX6900_REG_LEN,
+			.len	= MAX6900_BURST_LEN,
 			.buf	= buf
+		},
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= sizeof(reg_century_read),
+			.buf	= reg_century_read
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= sizeof(buf[MAX6900_REG_CENTURY]),
+			.buf	= &buf[MAX6900_REG_CENTURY]
 		}
 	};
 	int rc;
@@ -86,33 +106,58 @@
 
 static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
 {
-	u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
-	struct i2c_msg msgs[1] = {
+	u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
+	struct i2c_msg century_msgs[1] = {
 		{
 			.addr	= client->addr,
 			.flags	= 0, /* write */
-			.len	= MAX6900_REG_LEN + 1,
-			.buf	= i2c_buf
+			.len	= sizeof(i2c_century_buf),
+			.buf	= i2c_century_buf
+		}
+	};
+	u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+	struct i2c_msg burst_msgs[1] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= sizeof(i2c_burst_buf),
+			.buf	= i2c_burst_buf
 		}
 	};
 	int rc;
 
-	memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
-
-	rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-	if (rc != ARRAY_SIZE(msgs)) {
-		dev_err(&client->dev, "%s: register write failed\n",
-			__FUNCTION__);
-		return -EIO;
-	}
+	/*
+	 * We have to make separate calls to i2c_transfer because of
+	 * the need to delay after each write to the chip.  Also,
+	 * we write the century byte first, since we set the write-protect
+	 * bit as part of the burst write.
+	 */
+	i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+	rc = i2c_transfer(client->adapter, century_msgs,
+			  ARRAY_SIZE(century_msgs));
+	if (rc != ARRAY_SIZE(century_msgs))
+		goto write_failed;
 	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
+	memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
+
+	rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
+	if (rc != ARRAY_SIZE(burst_msgs))
+		goto write_failed;
+	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
 	return 0;
+
+write_failed:
+	dev_err(&client->dev, "%s: register write failed\n",
+		__FUNCTION__);
+	return -EIO;
 }
 
 static int max6900_i2c_validate_client(struct i2c_client *client)
 {
 	u8 regs[MAX6900_REG_LEN];
-	u8 zero_mask[MAX6900_REG_LEN] = {
+	u8 zero_mask[] = {
 		0x80,	/* seconds */
 		0x80,	/* minutes */
 		0x40,	/* hours */
@@ -134,7 +179,7 @@
 	if (rc < 0)
 		return rc;
 
-	for (i = 0; i < MAX6900_REG_LEN; ++i) {
+	for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
 		if (regs[i] & zero_mask[i])
 			return -ENODEV;
 	}
@@ -156,7 +201,8 @@
 	tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
 	tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
 	tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
-	tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+	tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
+		      BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
 	tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
 
 	return 0;
@@ -189,9 +235,11 @@
 	regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
 	regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
 	regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
-	regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
 	regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
-	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;	/* set write protect */
+	regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
+	regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+	/* set write protect */
+	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
 
 	rc = max6900_i2c_write_regs(client, regs);
 	if (rc < 0)
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
new file mode 100644
index 0000000..f10d3fa
--- /dev/null
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -0,0 +1,420 @@
+/*
+ * A RTC driver for the Simtek STK17TA8
+ *
+ * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ *
+ * Based on the DS1553 driver from
+ * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE		0x20000
+#define RTC_OFFSET		0x1fff0
+
+#define RTC_FLAGS		(RTC_OFFSET + 0)
+#define RTC_CENTURY		(RTC_OFFSET + 1)
+#define RTC_SECONDS_ALARM	(RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM	(RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM		(RTC_OFFSET + 4)
+#define RTC_DATE_ALARM		(RTC_OFFSET + 5)
+#define RTC_INTERRUPTS		(RTC_OFFSET + 6)
+#define RTC_WATCHDOG		(RTC_OFFSET + 7)
+#define RTC_CALIBRATION		(RTC_OFFSET + 8)
+#define RTC_SECONDS		(RTC_OFFSET + 9)
+#define RTC_MINUTES		(RTC_OFFSET + 10)
+#define RTC_HOURS		(RTC_OFFSET + 11)
+#define RTC_DAY			(RTC_OFFSET + 12)
+#define RTC_DATE		(RTC_OFFSET + 13)
+#define RTC_MONTH		(RTC_OFFSET + 14)
+#define RTC_YEAR		(RTC_OFFSET + 15)
+
+#define RTC_SECONDS_MASK	0x7f
+#define RTC_DAY_MASK		0x07
+#define RTC_CAL_MASK		0x3f
+
+/* Bits in the Calibration register */
+#define RTC_STOP		0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF		0x40
+#define RTC_FLAGS_PF		0x20
+#define RTC_WRITE		0x02
+#define RTC_READ		0x01
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AIE		0x40
+
+struct rtc_plat_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	unsigned long baseaddr;
+	unsigned long last_jiffies;
+	int irq;
+	unsigned int irqen;
+	int alrm_sec;
+	int alrm_min;
+	int alrm_hour;
+	int alrm_mday;
+};
+
+static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u8 flags;
+
+	flags = readb(pdata->ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+
+	writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+	writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+	writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+	writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+	writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+	writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+	writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+	writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+
+	writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+	return 0;
+}
+
+static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned int year, month, day, hour, minute, second, week;
+	unsigned int century;
+	u8 flags;
+
+	/* give enough time to update RTC in case of continuous read */
+	if (pdata->last_jiffies == jiffies)
+		msleep(1);
+	pdata->last_jiffies = jiffies;
+
+	flags = readb(pdata->ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
+	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+	minute = readb(ioaddr + RTC_MINUTES);
+	hour = readb(ioaddr + RTC_HOURS);
+	day = readb(ioaddr + RTC_DATE);
+	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+	month = readb(ioaddr + RTC_MONTH);
+	year = readb(ioaddr + RTC_YEAR);
+	century = readb(ioaddr + RTC_CENTURY);
+	writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
+	tm->tm_sec = BCD2BIN(second);
+	tm->tm_min = BCD2BIN(minute);
+	tm->tm_hour = BCD2BIN(hour);
+	tm->tm_mday = BCD2BIN(day);
+	tm->tm_wday = BCD2BIN(week);
+	tm->tm_mon = BCD2BIN(month) - 1;
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, tm);
+	}
+	return 0;
+}
+
+static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long irqflags;
+	u8 flags;
+
+	spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
+
+	flags = readb(ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+
+	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_mday),
+	       ioaddr + RTC_DATE_ALARM);
+	writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_hour),
+	       ioaddr + RTC_HOURS_ALARM);
+	writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_min),
+	       ioaddr + RTC_MINUTES_ALARM);
+	writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_sec),
+	       ioaddr + RTC_SECONDS_ALARM);
+	writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
+	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */
+	writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+	spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
+}
+
+static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	pdata->alrm_mday = alrm->time.tm_mday;
+	pdata->alrm_hour = alrm->time.tm_hour;
+	pdata->alrm_min = alrm->time.tm_min;
+	pdata->alrm_sec = alrm->time.tm_sec;
+	if (alrm->enabled)
+		pdata->irqen |= RTC_AF;
+	stk17ta8_rtc_update_alarm(pdata);
+	return 0;
+}
+
+static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+	alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+	alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+	alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+	alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+	return 0;
+}
+
+static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long events = RTC_IRQF;
+
+	/* read and clear interrupt */
+	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+		return IRQ_NONE;
+	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+		events |= RTC_UF;
+	else
+		events |= RTC_AF;
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+static void stk17ta8_rtc_release(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq >= 0) {
+		pdata->irqen = 0;
+		stk17ta8_rtc_update_alarm(pdata);
+	}
+}
+
+static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+	switch (cmd) {
+	case RTC_AIE_OFF:
+		pdata->irqen &= ~RTC_AF;
+		stk17ta8_rtc_update_alarm(pdata);
+		break;
+	case RTC_AIE_ON:
+		pdata->irqen |= RTC_AF;
+		stk17ta8_rtc_update_alarm(pdata);
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct rtc_class_ops stk17ta8_rtc_ops = {
+	.read_time	= stk17ta8_rtc_read_time,
+	.set_time	= stk17ta8_rtc_set_time,
+	.read_alarm	= stk17ta8_rtc_read_alarm,
+	.set_alarm	= stk17ta8_rtc_set_alarm,
+	.release	= stk17ta8_rtc_release,
+	.ioctl		= stk17ta8_rtc_ioctl,
+};
+
+static ssize_t stk17ta8_nvram_read(struct kobject *kobj, char *buf,
+				 loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		*buf++ = readb(ioaddr + pos++);
+	return count;
+}
+
+static ssize_t stk17ta8_nvram_write(struct kobject *kobj, char *buf,
+				  loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		writeb(*buf++, ioaddr + pos++);
+	return count;
+}
+
+static struct bin_attribute stk17ta8_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUGO | S_IWUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = RTC_OFFSET,
+	.read = stk17ta8_nvram_read,
+	.write = stk17ta8_nvram_write,
+};
+
+static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	struct resource *res;
+	unsigned int cal;
+	unsigned int flags;
+	struct rtc_plat_data *pdata;
+	void __iomem *ioaddr = NULL;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	pdata->irq = -1;
+	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	pdata->baseaddr = res->start;
+	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+	if (!ioaddr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	pdata->ioaddr = ioaddr;
+	pdata->irq = platform_get_irq(pdev, 0);
+
+	/* turn RTC on if it was not on */
+	cal = readb(ioaddr + RTC_CALIBRATION);
+	if (cal & RTC_STOP) {
+		cal &= RTC_CAL_MASK;
+		flags = readb(ioaddr + RTC_FLAGS);
+		writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+		writeb(cal, ioaddr + RTC_CALIBRATION);
+		writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+	}
+	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
+		dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+	if (pdata->irq >= 0) {
+		writeb(0, ioaddr + RTC_INTERRUPTS);
+		if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
+				IRQF_DISABLED | IRQF_SHARED,
+				pdev->name, pdev) < 0) {
+			dev_warn(&pdev->dev, "interrupt not available.\n");
+			pdata->irq = -1;
+		}
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				  &stk17ta8_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		ret = PTR_ERR(rtc);
+		goto out;
+	}
+	pdata->rtc = rtc;
+	pdata->last_jiffies = jiffies;
+	platform_set_drvdata(pdev, pdata);
+	ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+	if (ret)
+		goto out;
+	return 0;
+ out:
+	if (pdata->rtc)
+		rtc_device_unregister(pdata->rtc);
+	if (pdata->irq >= 0)
+		free_irq(pdata->irq, pdev);
+	if (ioaddr)
+		iounmap(ioaddr);
+	if (pdata->baseaddr)
+		release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return ret;
+}
+
+static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+	rtc_device_unregister(pdata->rtc);
+	if (pdata->irq >= 0) {
+		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+		free_irq(pdata->irq, pdev);
+	}
+	iounmap(pdata->ioaddr);
+	release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return 0;
+}
+
+static struct platform_driver stk17ta8_rtc_driver = {
+	.probe		= stk17ta8_rtc_probe,
+	.remove		= __devexit_p(stk17ta8_rtc_remove),
+	.driver		= {
+		.name	= "stk17ta8",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int stk17ta8_init(void)
+{
+	return platform_driver_register(&stk17ta8_rtc_driver);
+}
+
+static __exit void stk17ta8_exit(void)
+{
+	return platform_driver_unregister(&stk17ta8_rtc_driver);
+}
+
+module_init(stk17ta8_init);
+module_exit(stk17ta8_exit);
+
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 0026433..2553629 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@
 
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
+	struct dev_archdata *sd;
 	unsigned long base;
 	const void *pval;
 	int len, err;
@@ -67,6 +68,10 @@
 
 	sbus_fill_device_irq(sdev);
 
+	sd = &sdev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &sdev->ofdev;
+
 	sdev->ofdev.node = dp;
 	if (sdev->parent)
 		sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3727231..a947257 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -483,7 +483,7 @@
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
 	tristate "Adaptec I2O RAID support "
-	depends on !64BIT && SCSI && PCI
+	depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
 	help
 	  This driver supports all of Adaptec's I2O based RAID controllers as 
 	  well as the DPT SmartRaid V cards.  This is an Adaptec maintained
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 0f86895..86a7ba7 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -132,6 +132,7 @@
 obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
+obj-$(CONFIG_PS3_ROM)		+= ps3rom.o
 
 obj-$(CONFIG_ARM)		+= arm/
 
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 773d11d..79b4df1 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -95,6 +95,8 @@
 /* The master ring of all esp hosts we are managing in this driver. */
 static struct NCR_ESP *espchain;
 int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
 
 irqreturn_t esp_intr(int irq, void *dev_id);
 
@@ -524,6 +526,7 @@
 	/* Eat any bitrot in the chip and we are done... */
 	trash = esp_read(eregs->esp_intrpt);
 }
+EXPORT_SYMBOL(esp_bootup_reset);
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
@@ -772,6 +775,7 @@
 		panic("Bogon ESP revision");
 	};
 }
+EXPORT_SYMBOL(esp_info);
 
 /* From Wolfgang Stanglmeier's NCR scsi driver. */
 struct info_str
@@ -902,6 +906,7 @@
 		*start = buffer;
 	return esp_host_info(esp, buffer, offset, length);
 }
+EXPORT_SYMBOL(esp_proc_info);
 
 static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
@@ -3535,6 +3540,7 @@
 	if(esp->dma_irq_exit)
 		esp->dma_irq_exit(esp);
 }
+EXPORT_SYMBOL(esp_handle);
 
 #ifndef CONFIG_SMP
 irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3631,6 +3637,7 @@
 	esps_in_use--;
 	esps_running = esps_in_use;
 }
+EXPORT_SYMBOL(esp_release);
 #endif
 
 EXPORT_SYMBOL(esp_abort);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index aebcd5f..7829ab1 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1885,7 +1885,7 @@
 	struct sockaddr_in *sin;
 	int rc = 0, len;
 
-	addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+	addr = kmalloc(sizeof(*addr), GFP_KERNEL);
 	if (!addr)
 		return -ENOMEM;
 
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
new file mode 100644
index 0000000..b50f1e1
--- /dev/null
+++ b/drivers/scsi/ps3rom.c
@@ -0,0 +1,533 @@
+/*
+ * PS3 BD/DVD/CD-ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdrom.h>
+#include <linux/highmem.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME			"ps3rom"
+
+#define BOUNCE_SIZE			(64*1024)
+
+#define PS3ROM_MAX_SECTORS		(BOUNCE_SIZE / CD_FRAMESIZE)
+
+
+struct ps3rom_private {
+	struct ps3_storage_device *dev;
+	struct scsi_cmnd *curr_cmd;
+};
+
+
+#define LV1_STORAGE_SEND_ATAPI_COMMAND	(1)
+
+struct lv1_atapi_cmnd_block {
+	u8	pkt[32];	/* packet command block           */
+	u32	pktlen;		/* should be 12 for ATAPI 8020    */
+	u32	blocks;
+	u32	block_size;
+	u32	proto;		/* transfer mode                  */
+	u32	in_out;		/* transfer direction             */
+	u64	buffer;		/* parameter except command block */
+	u32	arglen;		/* length above                   */
+};
+
+enum lv1_atapi_proto {
+	NON_DATA_PROTO     = 0,
+	PIO_DATA_IN_PROTO  = 1,
+	PIO_DATA_OUT_PROTO = 2,
+	DMA_PROTO = 3
+};
+
+enum lv1_atapi_in_out {
+	DIR_WRITE = 0,		/* memory -> device */
+	DIR_READ = 1		/* device -> memory */
+};
+
+
+static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
+{
+	struct ps3rom_private *priv = shost_priv(scsi_dev->host);
+	struct ps3_storage_device *dev = priv->dev;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
+		__LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
+
+	/*
+	 * ATAPI SFF8020 devices use MODE_SENSE_10,
+	 * so we can prohibit MODE_SENSE_6
+	 */
+	scsi_dev->use_10_for_ms = 1;
+
+	/* we don't support {READ,WRITE}_6 */
+	scsi_dev->use_10_for_rw = 1;
+
+	return 0;
+}
+
+/*
+ * copy data from device into scatter/gather buffer
+ */
+static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
+{
+	int k, req_len, act_len, len, active;
+	void *kaddr;
+	struct scatterlist *sgpnt;
+	unsigned int buflen;
+
+	buflen = cmd->request_bufflen;
+	if (!buflen)
+		return 0;
+
+	if (!cmd->request_buffer)
+		return -1;
+
+	sgpnt = cmd->request_buffer;
+	active = 1;
+	for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+		if (active) {
+			kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+			len = sgpnt->length;
+			if ((req_len + len) > buflen) {
+				active = 0;
+				len = buflen - req_len;
+			}
+			memcpy(kaddr + sgpnt->offset, buf + req_len, len);
+			flush_kernel_dcache_page(sgpnt->page);
+			kunmap_atomic(kaddr, KM_IRQ0);
+			act_len += len;
+		}
+		req_len += sgpnt->length;
+	}
+	cmd->resid = req_len - act_len;
+	return 0;
+}
+
+/*
+ * copy data from scatter/gather into device's buffer
+ */
+static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
+{
+	int k, req_len, len, fin;
+	void *kaddr;
+	struct scatterlist *sgpnt;
+	unsigned int buflen;
+
+	buflen = cmd->request_bufflen;
+	if (!buflen)
+		return 0;
+
+	if (!cmd->request_buffer)
+		return -1;
+
+	sgpnt = cmd->request_buffer;
+	for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+		kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+		len = sgpnt->length;
+		if ((req_len + len) > buflen) {
+			len = buflen - req_len;
+			fin = 1;
+		}
+		memcpy(buf + req_len, kaddr + sgpnt->offset, len);
+		kunmap_atomic(kaddr, KM_IRQ0);
+		if (fin)
+			return req_len + len;
+		req_len += sgpnt->length;
+	}
+	return req_len;
+}
+
+static int ps3rom_atapi_request(struct ps3_storage_device *dev,
+				struct scsi_cmnd *cmd)
+{
+	struct lv1_atapi_cmnd_block atapi_cmnd;
+	unsigned char opcode = cmd->cmnd[0];
+	int res;
+	u64 lpar;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
+		__LINE__, opcode);
+
+	memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
+	memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
+	atapi_cmnd.pktlen = 12;
+	atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
+	atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+	atapi_cmnd.buffer = dev->bounce_lpar;
+
+	switch (cmd->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		if (cmd->request_bufflen >= CD_FRAMESIZE)
+			atapi_cmnd.proto = DMA_PROTO;
+		else
+			atapi_cmnd.proto = PIO_DATA_IN_PROTO;
+		atapi_cmnd.in_out = DIR_READ;
+		break;
+
+	case DMA_TO_DEVICE:
+		if (cmd->request_bufflen >= CD_FRAMESIZE)
+			atapi_cmnd.proto = DMA_PROTO;
+		else
+			atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
+		atapi_cmnd.in_out = DIR_WRITE;
+		res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+		if (res < 0)
+			return DID_ERROR << 16;
+		break;
+
+	default:
+		atapi_cmnd.proto = NON_DATA_PROTO;
+		break;
+	}
+
+	lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
+	res = lv1_storage_send_device_command(dev->sbd.dev_id,
+					      LV1_STORAGE_SEND_ATAPI_COMMAND,
+					      lpar, sizeof(atapi_cmnd),
+					      atapi_cmnd.buffer,
+					      atapi_cmnd.arglen, &dev->tag);
+	if (res == LV1_DENIED_BY_POLICY) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: ATAPI command 0x%02x denied by policy\n",
+			__func__, __LINE__, opcode);
+		return DID_ERROR << 16;
+	}
+
+	if (res) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
+			__LINE__, opcode, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
+{
+	return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
+	       cmd->cmnd[5];
+}
+
+static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
+{
+	return cmd->cmnd[7] << 8 | cmd->cmnd[8];
+}
+
+static int ps3rom_read_request(struct ps3_storage_device *dev,
+			       struct scsi_cmnd *cmd, u32 start_sector,
+			       u32 sectors)
+{
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
+		__func__, __LINE__, sectors, start_sector);
+
+	res = lv1_storage_read(dev->sbd.dev_id,
+			       dev->regions[dev->region_idx].id, start_sector,
+			       sectors, 0, dev->bounce_lpar, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
+			__LINE__, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static int ps3rom_write_request(struct ps3_storage_device *dev,
+				struct scsi_cmnd *cmd, u32 start_sector,
+				u32 sectors)
+{
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
+		__func__, __LINE__, sectors, start_sector);
+
+	res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+	if (res < 0)
+		return DID_ERROR << 16;
+
+	res = lv1_storage_write(dev->sbd.dev_id,
+				dev->regions[dev->region_idx].id, start_sector,
+				sectors, 0, dev->bounce_lpar, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
+			__LINE__, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+			       void (*done)(struct scsi_cmnd *))
+{
+	struct ps3rom_private *priv = shost_priv(cmd->device->host);
+	struct ps3_storage_device *dev = priv->dev;
+	unsigned char opcode;
+	int res;
+
+#ifdef DEBUG
+	scsi_print_command(cmd);
+#endif
+
+	priv->curr_cmd = cmd;
+	cmd->scsi_done = done;
+
+	opcode = cmd->cmnd[0];
+	/*
+	 * While we can submit READ/WRITE SCSI commands as ATAPI commands,
+	 * it's recommended for various reasons (performance, error handling,
+	 * ...) to use lv1_storage_{read,write}() instead
+	 */
+	switch (opcode) {
+	case READ_10:
+		res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
+					  srb10_len(cmd));
+		break;
+
+	case WRITE_10:
+		res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
+					   srb10_len(cmd));
+		break;
+
+	default:
+		res = ps3rom_atapi_request(dev, cmd);
+		break;
+	}
+
+	if (res) {
+		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+		cmd->result = res;
+		cmd->sense_buffer[0] = 0x70;
+		cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+		priv->curr_cmd = NULL;
+		cmd->scsi_done(cmd);
+	}
+
+	return 0;
+}
+
+static int decode_lv1_status(u64 status, unsigned char *sense_key,
+			     unsigned char *asc, unsigned char *ascq)
+{
+	if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
+		return -1;
+
+	*sense_key = (status >> 16) & 0xff;
+	*asc       = (status >>  8) & 0xff;
+	*ascq      =  status        & 0xff;
+	return 0;
+}
+
+static irqreturn_t ps3rom_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	struct Scsi_Host *host;
+	struct ps3rom_private *priv;
+	struct scsi_cmnd *cmd;
+	int res;
+	u64 tag, status;
+	unsigned char sense_key, asc, ascq;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+	/*
+	 * status = -1 may mean that ATAPI transport completed OK, but
+	 * ATAPI command itself resulted CHECK CONDITION
+	 * so, upper layer should issue REQUEST_SENSE to check the sense data
+	 */
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+		return IRQ_HANDLED;
+	}
+
+	host = dev->sbd.core.driver_data;
+	priv = shost_priv(host);
+	cmd = priv->curr_cmd;
+
+	if (!status) {
+		/* OK, completed */
+		if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+			res = fill_from_dev_buffer(cmd, dev->bounce_buf);
+			if (res) {
+				cmd->result = DID_ERROR << 16;
+				goto done;
+			}
+		}
+		cmd->result = DID_OK << 16;
+		goto done;
+	}
+
+	if (cmd->cmnd[0] == REQUEST_SENSE) {
+		/* SCSI spec says request sense should never get error */
+		dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
+			__func__, __LINE__);
+		cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
+		goto done;
+	}
+
+	if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
+		cmd->result = DID_ERROR << 16;
+		goto done;
+	}
+
+	cmd->sense_buffer[0]  = 0x70;
+	cmd->sense_buffer[2]  = sense_key;
+	cmd->sense_buffer[7]  = 16 - 6;
+	cmd->sense_buffer[12] = asc;
+	cmd->sense_buffer[13] = ascq;
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+done:
+	priv->curr_cmd = NULL;
+	cmd->scsi_done(cmd);
+	return IRQ_HANDLED;
+}
+
+static struct scsi_host_template ps3rom_host_template = {
+	.name =			DEVICE_NAME,
+	.slave_configure =	ps3rom_slave_configure,
+	.queuecommand =		ps3rom_queuecommand,
+	.can_queue =		1,
+	.this_id =		7,
+	.sg_tablesize =		SG_ALL,
+	.cmd_per_lun =		1,
+	.emulated =             1,		/* only sg driver uses this */
+	.max_sectors =		PS3ROM_MAX_SECTORS,
+	.use_clustering =	ENABLE_CLUSTERING,
+	.module =		THIS_MODULE,
+};
+
+
+static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	int error;
+	struct Scsi_Host *host;
+	struct ps3rom_private *priv;
+
+	if (dev->blk_size != CD_FRAMESIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: cannot handle block size %lu\n", __func__,
+			__LINE__, dev->blk_size);
+		return -EINVAL;
+	}
+
+	dev->bounce_size = BOUNCE_SIZE;
+	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+	if (!dev->bounce_buf)
+		return -ENOMEM;
+
+	error = ps3stor_setup(dev, ps3rom_interrupt);
+	if (error)
+		goto fail_free_bounce;
+
+	host = scsi_host_alloc(&ps3rom_host_template,
+			       sizeof(struct ps3rom_private));
+	if (!host) {
+		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
+			__func__, __LINE__);
+		goto fail_teardown;
+	}
+
+	priv = shost_priv(host);
+	dev->sbd.core.driver_data = host;
+	priv->dev = dev;
+
+	/* One device/LUN per SCSI bus */
+	host->max_id = 1;
+	host->max_lun = 1;
+
+	error = scsi_add_host(host, &dev->sbd.core);
+	if (error) {
+		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
+			__func__, __LINE__, error);
+		error = -ENODEV;
+		goto fail_host_put;
+	}
+
+	scsi_scan_host(host);
+	return 0;
+
+fail_host_put:
+	scsi_host_put(host);
+	dev->sbd.core.driver_data = NULL;
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_bounce:
+	kfree(dev->bounce_buf);
+	return error;
+}
+
+static int ps3rom_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct Scsi_Host *host = dev->sbd.core.driver_data;
+
+	scsi_remove_host(host);
+	ps3stor_teardown(dev);
+	scsi_host_put(host);
+	dev->sbd.core.driver_data = NULL;
+	kfree(dev->bounce_buf);
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3rom = {
+	.match_id	= PS3_MATCH_ID_STOR_ROM,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3rom_probe,
+	.remove		= ps3rom_remove
+};
+
+
+static int __init ps3rom_init(void)
+{
+	return ps3_system_bus_driver_register(&ps3rom);
+}
+
+static void __exit ps3rom_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3rom);
+}
+
+module_init(ps3rom_init);
+module_exit(ps3rom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba53..70a09a3 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/serial_core.h>
 #include <linux/init.h>
 
-#include <asm/oplib.h>
+#include <asm/prom.h>
 
 #include "suncore.h"
 
@@ -26,92 +27,60 @@
 
 EXPORT_SYMBOL(sunserial_current_minor);
 
+int sunserial_console_match(struct console *con, struct device_node *dp,
+			    struct uart_driver *drv, int line)
+{
+	int off;
+
+	if (!con || of_console_device != dp)
+		return 0;
+
+	off = 0;
+	if (of_console_options &&
+	    *of_console_options == 'b')
+		off = 1;
+
+	if ((line & 1) != off)
+		return 0;
+
+	con->index = line;
+	drv->cons = con;
+	add_preferred_console(con->name, line, NULL);
+
+	return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
+
 void
 sunserial_console_termios(struct console *con)
 {
-	char mode[16], buf[16], *s;
+	struct device_node *dp;
+	const char *od, *mode, *s;
 	char mode_prop[] = "ttyX-mode";
-	char cd_prop[]   = "ttyX-ignore-cd";
-	char dtr_prop[]  = "ttyX-rts-dtr-off";
-	char *ssp_console_modes_prop = "ssp-console-modes";
 	int baud, bits, stop, cflag;
 	char parity;
-	int carrier = 0;
-	int rtsdtr = 1;
-	int topnd, nd;
 
-	if (!serial_console)
-		return;
+	dp = of_find_node_by_path("/options");
+	od = of_get_property(dp, "output-device", NULL);
+	if (!strcmp(od, "rsc")) {
+		mode = of_get_property(of_console_device,
+				       "ssp-console-modes", NULL);
+		if (!mode)
+			mode = "115200,8,n,1,-";
+	} else {
+		char c;
 
-	switch (serial_console) {
-	case PROMDEV_OTTYA:
-		mode_prop[3] = 'a';
-		cd_prop[3] = 'a';
-		dtr_prop[3] = 'a';
-		break;
+		c = 'a';
+		if (of_console_options)
+			c = *of_console_options;
 
-	case PROMDEV_OTTYB:
-		mode_prop[3] = 'b';
-		cd_prop[3] = 'b';
-		dtr_prop[3] = 'b';
-		break;
+		mode_prop[3] = c;
 
-	case PROMDEV_ORSC:
-
-		nd = prom_pathtoinode("rsc");
-		if (!nd) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		memset(mode, 0, sizeof(mode));
-		prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
-		goto no_options;
-
-	default:
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
+		mode = of_get_property(dp, mode_prop, NULL);
+		if (!mode)
+			mode = "9600,8,n,1,-";
 	}
 
-	topnd = prom_getchild(prom_root_node);
-	nd = prom_searchsiblings(topnd, "options");
-	if (!nd) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	if (!prom_node_has_property(nd, mode_prop)) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	memset(mode, 0, sizeof(mode));
-	prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
-	if (prom_node_has_property(nd, cd_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, cd_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			carrier = 1;
-
-		/* XXX: this is unused below. */
-	}
-
-	if (prom_node_has_property(nd, dtr_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, dtr_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			rtsdtr = 0;
-
-		/* XXX: this is unused below. */
-	}
-
-no_options:
 	cflag = CREAD | HUPCL | CLOCAL;
 
 	s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a..829d7d6 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@
 
 extern int sunserial_current_minor;
 
+extern int sunserial_console_match(struct console *, struct device_node *,
+				   struct uart_driver *, int);
 extern void sunserial_console_termios(struct console *);
 
 #endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index d82be42..8ff900b 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -520,16 +520,6 @@
 	.data	=	&sunhv_reg,
 };
 
-static inline struct console *SUNHV_CONSOLE(void)
-{
-	if (con_is_present())
-		return NULL;
-
-	sunhv_console.index = 0;
-
-	return &sunhv_console;
-}
-
 static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct uart_port *port;
@@ -582,7 +572,8 @@
 	sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
 	sunserial_current_minor += 1;
 
-	sunhv_reg.cons = SUNHV_CONSOLE();
+	sunserial_console_match(&sunhv_console, op->node,
+				&sunhv_reg, port->line);
 
 	err = uart_add_one_port(&sunhv_reg, port);
 	if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8a0f9e4..bca57bb 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -968,22 +968,6 @@
 
 static inline struct console *SUNSAB_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_channels; i++) {
-		int this_minor = sunsab_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_channels)
-		return NULL;
-
-	sunsab_console.index = i;
-
 	return &sunsab_console;
 }
 #else
@@ -1080,7 +1064,12 @@
 		return err;
 	}
 
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[0].port.line);
 	uart_add_one_port(&sunsab_reg, &up[0].port);
+
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[1].port.line);
 	uart_add_one_port(&sunsab_reg, &up[1].port);
 
 	dev_set_drvdata(&op->dev, &up[0]);
@@ -1164,7 +1153,6 @@
 		}
 
 		sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
-		sunsab_reg.cons = SUNSAB_CONSOLE();
 		sunserial_current_minor += num_channels;
 	}
 
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 26d720b..79b1368 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1371,28 +1371,12 @@
  *	Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_uart; i++) {
-		int this_minor = sunsu_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_uart)
-		return NULL;
-
-	sunsu_console.index = i;
-
 	return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)		(NULL)
+#define SUNSU_CONSOLE()			(NULL)
 #define sunsu_serial_console_init()	do { } while (0)
 #endif
 
@@ -1482,6 +1466,8 @@
 
 	up->port.ops = &sunsu_pops;
 
+	sunserial_console_match(SUNSU_CONSOLE(), dp,
+				&sunsu_reg, up->port.line);
 	err = uart_add_one_port(&sunsu_reg, &up->port);
 	if (err)
 		goto out_unmap;
@@ -1572,7 +1558,6 @@
 			return err;
 		sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
 		sunserial_current_minor += num_uart;
-		sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
 	}
 
 	err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 0a3e10a..1d262c0 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1226,23 +1226,6 @@
 
 static inline struct console *SUNZILOG_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		int this_minor = sunzilog_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == NUM_CHANNELS)
-		return NULL;
-
-	sunzilog_console_ops.index = i;
-	sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
 	return &sunzilog_console_ops;
 }
 
@@ -1428,12 +1411,18 @@
 	sunzilog_init_hw(&up[1]);
 
 	if (!keyboard_mouse) {
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[0].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[0].port);
 		if (err) {
 			of_iounmap(&op->resource[0],
 				   rp, sizeof(struct zilog_layout));
 			return err;
 		}
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[1].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[1].port);
 		if (err) {
 			uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1531,7 +1520,6 @@
 			goto out_free_tables;
 
 		sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-		sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
 		sunserial_current_minor += uart_count;
 	}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 018884d..b05de30 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -303,8 +303,7 @@
  * creates board info from kernel command lines
  */
 
-static void __init_or_module
-scan_boardinfo(struct spi_master *master)
+static void scan_boardinfo(struct spi_master *master)
 {
 	struct boardinfo	*bi;
 	struct device		*dev = master->cdev.dev;
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 1bc8840..02c52f8 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -456,7 +456,7 @@
 				 int* actual_length)
 {
 	struct timer_list timer;
-	int status;
+	int status = urb->status;
 
 	init_timer(&timer);
 	timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,7 +464,6 @@
 	timer.function = cxacru_timeout_kill;
 	add_timer(&timer);
 	wait_for_completion(done);
-	status = urb->status;
 	del_timer_sync(&timer);
 
 	if (actual_length)
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 638b800..eb0615a 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -612,7 +612,8 @@
 	struct speedtch_instance_data *instance = int_urb->context;
 	struct usbatm_data *usbatm = instance->usbatm;
 	unsigned int count = int_urb->actual_length;
-	int ret = int_urb->status;
+	int status = int_urb->status;
+	int ret;
 
 	/* The magic interrupt for "up state" */
 	static const unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +622,8 @@
 
 	atm_dbg(usbatm, "%s entered\n", __func__);
 
-	if (ret < 0) {
-		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+	if (status < 0) {
+		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
 		goto fail;
 	}
 
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 8f04665..a1a1c9d 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1308,11 +1308,13 @@
 {
 	struct uea_softc *sc = urb->context;
 	struct intr_pkt *intr = urb->transfer_buffer;
+	int status = urb->status;
+
 	uea_enters(INS_TO_USBDEV(sc));
 
-	if (unlikely(urb->status < 0)) {
+	if (unlikely(status < 0)) {
 		uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
-		       urb->status);
+		       status);
 		return;
 	}
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 11e9b15..e717f5b 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -257,9 +257,10 @@
 {
 	struct usbatm_channel *channel = urb->context;
 	unsigned long flags;
+	int status = urb->status;
 
 	vdbg("%s: urb 0x%p, status %d, actual_length %d",
-	     __func__, urb, urb->status, urb->actual_length);
+	     __func__, urb, status, urb->actual_length);
 
 	/* usually in_interrupt(), but not always */
 	spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@
 
 	spin_unlock_irqrestore(&channel->lock, flags);
 
-	if (unlikely(urb->status) &&
+	if (unlikely(status) &&
 			(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
-			 urb->status != -EILSEQ ))
+			 status != -EILSEQ ))
 	{
-		if (urb->status == -ESHUTDOWN)
+		if (status == -ESHUTDOWN)
 			return;
 
 		if (printk_ratelimit())
 			atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
-				__func__, urb, urb->status);
+				__func__, urb, status);
 		/* throttle processing in case of an error */
 		mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
 	} else
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index cd51520c..fe940e0 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -257,9 +257,10 @@
 	struct usb_cdc_notification *dr = urb->transfer_buffer;
 	unsigned char *data;
 	int newctrl;
-	int status;
+	int retval;
+	int status = urb->status;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -267,10 +268,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
 		goto exit;
 	}
 
@@ -311,10 +312,10 @@
 			break;
 	}
 exit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, status);
+		     __FUNCTION__, retval);
 }
 
 /* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@
 	struct acm_ru *rcv = urb->context;
 	struct acm *acm = rcv->instance;
 	int status = urb->status;
-	dbg("Entering acm_read_bulk with status %d", urb->status);
+
+	dbg("Entering acm_read_bulk with status %d", status);
 
 	if (!ACM_READY(acm))
 		return;
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 9a14789..5192cd9 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -289,16 +289,17 @@
 static void usblp_bulk_read(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
+	int status = urb->status;
 
 	if (usblp->present && usblp->used) {
-		if (urb->status)
+		if (status)
 			printk(KERN_WARNING "usblp%d: "
 			    "nonzero read bulk status received: %d\n",
-			    usblp->minor, urb->status);
+			    usblp->minor, status);
 	}
 	spin_lock(&usblp->lock);
-	if (urb->status < 0)
-		usblp->rstatus = urb->status;
+	if (status < 0)
+		usblp->rstatus = status;
 	else
 		usblp->rstatus = urb->actual_length;
 	usblp->rcomplete = 1;
@@ -311,16 +312,17 @@
 static void usblp_bulk_write(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
+	int status = urb->status;
 
 	if (usblp->present && usblp->used) {
-		if (urb->status)
+		if (status)
 			printk(KERN_WARNING "usblp%d: "
 			    "nonzero write bulk status received: %d\n",
-			    usblp->minor, urb->status);
+			    usblp->minor, status);
 	}
 	spin_lock(&usblp->lock);
-	if (urb->status < 0)
-		usblp->wstatus = urb->status;
+	if (status < 0)
+		usblp->wstatus = status;
 	else
 		usblp->wstatus = urb->actual_length;
 	usblp->wcomplete = 1;
@@ -741,10 +743,11 @@
 		 */
 		rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
 		if (rv < 0) {
-			/*
-			 * If interrupted, we simply leave the URB to dangle,
-			 * so the ->release will call usb_kill_urb().
-			 */
+			if (rv == -EAGAIN) {
+				/* Presume that it's going to complete well. */
+				writecount += transfer_length;
+			}
+			/* Leave URB dangling, to be cleaned on close. */
 			goto collect_error;
 		}
 
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 963520f..42ef1d5 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -99,12 +99,17 @@
 /* used for controlling access to virtual root hubs */
 static DEFINE_SPINLOCK(hcd_root_hub_lock);
 
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
 
 /* wait queue for synchronous unlinks */
 DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
 
+static inline int is_root_hub(struct usb_device *udev)
+{
+	return (udev->parent == NULL);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -906,14 +911,13 @@
 static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
 {
 	unsigned long		flags;
-	int at_root_hub = (urb->dev == hcd->self.root_hub);
 
 	/* clear all state linking urb to this dev (and hcd) */
-	spin_lock_irqsave (&hcd_data_lock, flags);
+	spin_lock_irqsave(&hcd_urb_list_lock, flags);
 	list_del_init (&urb->urb_list);
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
+	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
 
-	if (hcd->self.uses_dma && !at_root_hub) {
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
 		if (usb_pipecontrol (urb->pipe)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -955,7 +959,7 @@
 
 	// FIXME:  verify that quiescing hc works right (RH cleans up)
 
-	spin_lock_irqsave (&hcd_data_lock, flags);
+	spin_lock_irqsave(&hcd_urb_list_lock, flags);
 	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
 			[usb_pipeendpoint(urb->pipe)];
 	if (unlikely (!ep))
@@ -972,7 +976,7 @@
 		status = -ESHUTDOWN;
 		break;
 	}
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
+	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
 	if (status) {
 		INIT_LIST_HEAD (&urb->urb_list);
 		usbmon_urb_submit_error(&hcd->self, urb, status);
@@ -986,7 +990,7 @@
 	urb = usb_get_urb (urb);
 	atomic_inc (&urb->use_count);
 
-	if (urb->dev == hcd->self.root_hub) {
+	if (is_root_hub(urb->dev)) {
 		/* NOTE:  requirement on hub callers (usbfs and the hub
 		 * driver, for now) that URBs' urb->transfer_buffer be
 		 * valid and usb_buffer_{sync,unmap}() not be needed, since
@@ -1033,18 +1037,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
-{
-	struct usb_hcd	*hcd = bus_to_hcd(udev->bus);
-
-	if (!HC_IS_RUNNING (hcd->state))
-		return -ESHUTDOWN;
-	return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* this makes the hcd giveback() the urb more quickly, by kicking it
  * off hardware queues (which may take a while) and returning it as
  * soon as practical.  we've already set up the urb's return status,
@@ -1055,7 +1047,7 @@
 {
 	int		value;
 
-	if (urb->dev == hcd->self.root_hub)
+	if (is_root_hub(urb->dev))
 		value = usb_rh_urb_dequeue (hcd, urb);
 	else {
 
@@ -1103,11 +1095,11 @@
 	 * that it was submitted.  But as a rule it can't know whether or
 	 * not it's already been unlinked ... so we respect the reversed
 	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
-	 * (urb lock, then hcd_data_lock) in case some other CPU is now
+	 * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
 	 * unlinking it.
 	 */
 	spin_lock_irqsave (&urb->lock, flags);
-	spin_lock (&hcd_data_lock);
+	spin_lock(&hcd_urb_list_lock);
 
 	sys = &urb->dev->dev;
 	hcd = bus_to_hcd(urb->dev->bus);
@@ -1139,17 +1131,16 @@
 	 * finish unlinking the initial failed usb_set_address()
 	 * or device descriptor fetch.
 	 */
-	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
-	    && hcd->self.root_hub != urb->dev) {
+	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+			!is_root_hub(urb->dev)) {
 		dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-			"Controller is probably using the wrong IRQ."
-			"\n");
+			"Controller is probably using the wrong IRQ.\n");
 		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 	}
 
 	urb->status = status;
 
-	spin_unlock (&hcd_data_lock);
+	spin_unlock(&hcd_urb_list_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 
 	retval = unlink1 (hcd, urb);
@@ -1158,7 +1149,7 @@
 	return retval;
 
 done:
-	spin_unlock (&hcd_data_lock);
+	spin_unlock(&hcd_urb_list_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 	if (retval != -EIDRM && sys && sys->driver)
 		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1167,6 +1158,35 @@
 
 /*-------------------------------------------------------------------------*/
 
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+	urb_unlink(hcd, urb);
+	usbmon_urb_complete (&hcd->self, urb);
+	usb_unanchor_urb(urb);
+
+	/* pass ownership to the completion handler */
+	urb->complete (urb);
+	atomic_dec (&urb->use_count);
+	if (unlikely (urb->reject))
+		wake_up (&usb_kill_urb_queue);
+	usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
 /* disables the endpoint: cancels any pending urbs, then synchronizes with
  * the hcd to make sure all endpoint state is gone from hardware, and then
  * waits until the endpoint's queue is completely drained. use for
@@ -1186,7 +1206,7 @@
 
 	/* ep is already gone from udev->ep_{in,out}[]; no more submits */
 rescan:
-	spin_lock (&hcd_data_lock);
+	spin_lock(&hcd_urb_list_lock);
 	list_for_each_entry (urb, &ep->urb_list, urb_list) {
 		int	tmp;
 
@@ -1194,7 +1214,7 @@
 		if (urb->status != -EINPROGRESS)
 			continue;
 		usb_get_urb (urb);
-		spin_unlock (&hcd_data_lock);
+		spin_unlock(&hcd_urb_list_lock);
 
 		spin_lock (&urb->lock);
 		tmp = urb->status;
@@ -1223,7 +1243,7 @@
 		/* list contents may have changed */
 		goto rescan;
 	}
-	spin_unlock (&hcd_data_lock);
+	spin_unlock(&hcd_urb_list_lock);
 	local_irq_enable ();
 
 	/* synchronize with the hardware, so old configuration state
@@ -1240,7 +1260,7 @@
 	 * endpoint_disable methods.
 	 */
 	while (!list_empty (&ep->urb_list)) {
-		spin_lock_irq (&hcd_data_lock);
+		spin_lock_irq(&hcd_urb_list_lock);
 
 		/* The list may have changed while we acquired the spinlock */
 		urb = NULL;
@@ -1249,7 +1269,7 @@
 					urb_list);
 			usb_get_urb (urb);
 		}
-		spin_unlock_irq (&hcd_data_lock);
+		spin_unlock_irq(&hcd_urb_list_lock);
 
 		if (urb) {
 			usb_kill_urb (urb);
@@ -1260,6 +1280,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+	struct usb_hcd	*hcd = bus_to_hcd(udev->bus);
+
+	if (!HC_IS_RUNNING (hcd->state))
+		return -ESHUTDOWN;
+	return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
 #ifdef	CONFIG_PM
 
 int hcd_bus_suspend(struct usb_device *rhdev)
@@ -1395,35 +1427,6 @@
 /*-------------------------------------------------------------------------*/
 
 /**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function.  The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
-	urb_unlink(hcd, urb);
-	usbmon_urb_complete (&hcd->self, urb);
-	usb_unanchor_urb(urb);
-
-	/* pass ownership to the completion handler */
-	urb->complete (urb);
-	atomic_dec (&urb->use_count);
-	if (unlikely (urb->reject))
-		wake_up (&usb_kill_urb_queue);
-	usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
-/**
  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
  * @irq: the IRQ being raised
  * @__hcd: pointer to the HCD whose IRQ is being signaled
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index fd74c50..e341a1d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1335,6 +1335,10 @@
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+	/* Increment the parent's count of unsuspended children */
+	if (udev->parent)
+		usb_autoresume_device(udev->parent);
+
 	/* Register the device.  The device driver is responsible
 	 * for adding the device files to sysfs and for configuring
 	 * the device.
@@ -1342,13 +1346,11 @@
 	err = device_add(&udev->dev);
 	if (err) {
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
+		if (udev->parent)
+			usb_autosuspend_device(udev->parent);
 		goto fail;
 	}
 
-	/* Increment the parent's count of unsuspended children */
-	if (udev->parent)
-		usb_autoresume_device(udev->parent);
-
 exit:
 	return err;
 
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 530e854..25f63f1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -34,13 +34,14 @@
 { 
 	struct completion done;
 	unsigned long expire;
-	int status;
+	int retval;
+	int status = urb->status;
 
 	init_completion(&done); 	
 	urb->context = &done;
 	urb->actual_length = 0;
-	status = usb_submit_urb(urb, GFP_NOIO);
-	if (unlikely(status))
+	retval = usb_submit_urb(urb, GFP_NOIO);
+	if (unlikely(retval))
 		goto out;
 
 	expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
@@ -55,15 +56,15 @@
 			urb->transfer_buffer_length);
 
 		usb_kill_urb(urb);
-		status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+		retval = status == -ENOENT ? -ETIMEDOUT : status;
 	} else
-		status = urb->status;
+		retval = status;
 out:
 	if (actual_length)
 		*actual_length = urb->actual_length;
 
 	usb_free_urb(urb);
-	return status;
+	return retval;
 }
 
 /*-------------------------------------------------------------------*/
@@ -250,6 +251,7 @@
 static void sg_complete (struct urb *urb)
 {
 	struct usb_sg_request	*io = urb->context;
+	int status = urb->status;
 
 	spin_lock (&io->lock);
 
@@ -265,21 +267,21 @@
 	 */
 	if (io->status
 			&& (io->status != -ECONNRESET
-				|| urb->status != -ECONNRESET)
+				|| status != -ECONNRESET)
 			&& urb->actual_length) {
 		dev_err (io->dev->bus->controller,
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			io->dev->devpath,
 			usb_pipeendpoint (urb->pipe),
 			usb_pipein (urb->pipe) ? "in" : "out",
-			urb->status, io->status);
+			status, io->status);
 		// BUG ();
 	}
 
-	if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
-		int		i, found, status;
+	if (io->status == 0 && status && status != -ECONNRESET) {
+		int i, found, retval;
 
-		io->status = urb->status;
+		io->status = status;
 
 		/* the previous urbs, and this one, completed already.
 		 * unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +292,13 @@
 			if (!io->urbs [i] || !io->urbs [i]->dev)
 				continue;
 			if (found) {
-				status = usb_unlink_urb (io->urbs [i]);
-				if (status != -EINPROGRESS
-						&& status != -ENODEV
-						&& status != -EBUSY)
+				retval = usb_unlink_urb (io->urbs [i]);
+				if (retval != -EINPROGRESS &&
+				    retval != -ENODEV &&
+				    retval != -EBUSY)
 					dev_err (&io->dev->dev,
 						"%s, unlink --> %d\n",
-						__FUNCTION__, status);
+						__FUNCTION__, retval);
 			} else if (urb == io->urbs [i])
 				found = 1;
 		}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d47ae89..2ab222b 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -441,6 +441,54 @@
 	.attrs = dev_attrs,
 };
 
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+		char *buf, loff_t off, size_t count)
+{
+	struct usb_device *udev = to_usb_device(
+			container_of(kobj, struct device, kobj));
+	size_t nleft = count;
+	size_t srclen, n;
+
+	usb_lock_device(udev);
+
+	/* The binary attribute begins with the device descriptor */
+	srclen = sizeof(struct usb_device_descriptor);
+	if (off < srclen) {
+		n = min_t(size_t, nleft, srclen - off);
+		memcpy(buf, off + (char *) &udev->descriptor, n);
+		nleft -= n;
+		buf += n;
+		off = 0;
+	} else {
+		off -= srclen;
+	}
+
+	/* Then follows the raw descriptor entry for the current
+	 * configuration (config plus subsidiary descriptors).
+	 */
+	if (udev->actconfig) {
+		int cfgno = udev->actconfig - udev->config;
+
+		srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+		if (off < srclen) {
+			n = min_t(size_t, nleft, srclen - off);
+			memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+			nleft -= n;
+		}
+	}
+	usb_unlock_device(udev);
+	return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+	.attr = {.name = "descriptors", .mode = 0444},
+	.read = read_descriptors,
+	.size = 18 + 65535,	/* dev descr + max-size raw descriptor */
+};
+
 int usb_create_sysfs_dev_files(struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
@@ -450,6 +498,10 @@
 	if (retval)
 		return retval;
 
+	retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+	if (retval)
+		goto error;
+
 	retval = add_persist_attributes(dev);
 	if (retval)
 		goto error;
@@ -492,6 +544,7 @@
 	device_remove_file(dev, &dev_attr_serial);
 	remove_power_attributes(dev);
 	remove_persist_attributes(dev);
+	device_remove_bin_file(dev, &dev_bin_attr_descriptors);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 52ec44b..be63022 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -440,55 +440,57 @@
  * @urb: pointer to urb describing a previously submitted request,
  *	may be NULL
  *
- * This routine cancels an in-progress request.  URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
+ * This routine cancels an in-progress request.  URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
  *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver.  When it is called, the completion
- * function will see urb->status == -ECONNRESET.  Failure is indicated
- * by any other return value.  Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This request is always asynchronous.  Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver.  When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
  *
  * Unlinking and Endpoint Queues:
  *
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
  * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
  * hardware processes each request.  But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns.  It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns.  Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns.  It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns.  The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
  *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO.  Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors.  Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates.  Such queues do not stop when an URB
+ * encounters an error or is unlinked.  An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
  *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set.  By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
  *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates.  Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets.  It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
  */
 int usb_unlink_urb(struct urb *urb)
 {
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 45e01e2..767aed5 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -82,6 +82,27 @@
 	   Many controller drivers are platform-specific; these
 	   often need board-specific hooks.
 
+config USB_GADGET_AMD5536UDC
+	boolean "AMD5536 UDC"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	   The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+	   It is a USB Highspeed DMA capable USB device controller. Beside ep0
+	   it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+	   The UDC port supports OTG operation, and may be used as a host port
+	   if it's not being used to implement peripheral or OTG roles.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "amd5536udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+	tristate
+	depends on USB_GADGET_AMD5536UDC
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on MPC834x || PPC_MPC831x
@@ -156,6 +177,24 @@
 	default y if USB_ETH
 	default y if USB_G_SERIAL
 
+config USB_GADGET_M66592
+	boolean "Renesas M66592 USB Peripheral Controller"
+	select USB_GADGET_DUALSPEED
+	help
+	   M66592 is a discrete USB peripheral controller chip that
+	   supports both full and high speed USB 2.0 data transfers.
+	   It has seven configurable endpoints, and endpoint zero.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "m66592_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_M66592
+	tristate
+	depends on USB_GADGET_M66592
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_GOKU
 	boolean "Toshiba TC86C001 'Goku-S'"
 	depends on PCI
@@ -261,24 +300,6 @@
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 
-config USB_GADGET_M66592
-	boolean "M66592 driver"
-	select USB_GADGET_DUALSPEED
-	help
-	   M66592 is a USB 2.0 peripheral controller.
-
-	   It has seven configurable endpoints, and endpoint zero.
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "m66592_udc" and force all
-	   gadget drivers to also be dynamically linked.
-
-config USB_M66592
-	tristate
-	depends on USB_GADGET_M66592
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 8ae76f7..1bc0f03 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -7,6 +7,7 @@
 
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
+obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 0000000..714156c
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION		"AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING	"01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+				unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde  0 == do not touch RDE, do no start the RDE timer
+ * set_rde  1 == timer function will look whether FIFO has data
+ * set_rde  2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+		(unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+	ep0_string,
+	"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+	"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+	"ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+	"ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+	"ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+	"ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+	"ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+	"true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+	DBG(dev, "------- Device registers -------\n");
+	DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
+	DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
+	DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
+	DBG(dev, "\n");
+	DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
+	DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
+	DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "USE DMA        = %d\n", use_dma);
+	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
+			"WITHOUT desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+	} else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBDU (packet per buffer "
+			"WITH desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+	}
+	if (use_dma && use_dma_bufferfill_mode) {
+		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+	}
+	if (!use_dma) {
+		dev_info(&dev->pdev->dev, "FIFO mode\n");
+	}
+	DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	/* mask all dev interrupts */
+	tmp =	AMD_BIT(UDC_DEVINT_SVC) |
+		AMD_BIT(UDC_DEVINT_ENUM) |
+		AMD_BIT(UDC_DEVINT_US) |
+		AMD_BIT(UDC_DEVINT_UR) |
+		AMD_BIT(UDC_DEVINT_ES) |
+		AMD_BIT(UDC_DEVINT_SI) |
+		AMD_BIT(UDC_DEVINT_SOF)|
+		AMD_BIT(UDC_DEVINT_SC);
+	writel(tmp, &dev->regs->irqmsk);
+
+	/* mask all ep interrupts */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	/* enable ep0 irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+		& AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "enable device interrupts for setup data\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->irqmsk);
+
+	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_UR)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+	writel(tmp, &dev->regs->irqmsk);
+
+	return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+	struct udc	*dev;
+	u32 tmp;
+	int i;
+
+	if (!ep || !(ep->in))
+		return -EINVAL;
+
+	dev = ep->dev;
+	ep->txfifo = dev->txfifo;
+
+	/* traverse ep's */
+	for (i = 0; i < ep->num; i++) {
+		if (dev->ep[i].regs) {
+			/* read fifo size */
+			tmp = readl(&dev->ep[i].regs->bufin_framenum);
+			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+			ep->txfifo += tmp;
+		}
+	}
+	return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+	if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+		DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+		cnak_pending |= 1 << (num);
+		ep->naking = 1;
+	} else
+		cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+	struct udc_ep		*ep;
+	struct udc		*dev;
+	u32			tmp;
+	unsigned long		iflags;
+	u8 udc_csr_epix;
+
+	if (!usbep
+			|| usbep->name == ep0_string
+			|| !desc
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+
+	DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	ep->desc = desc;
+
+	ep->halted = 0;
+
+	/* set traffic type */
+	tmp = readl(&dev->ep[ep->num].regs->ctl);
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+	writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+	/* set max packet size */
+	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+	ep->ep.maxpacket = desc->wMaxPacketSize;
+	writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+	/* IN ep */
+	if (ep->in) {
+
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num;
+
+		/* set buffer size (tx fifo entries) */
+		tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+		/* double buffering: fifo size = 2 x max packet size */
+		tmp = AMD_ADDBITS(
+				tmp,
+				desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+						/ UDC_DWORD_BYTES,
+				UDC_EPIN_BUFF_SIZE);
+		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+		/* calc. tx fifo base addr */
+		udc_set_txfifo_addr(ep);
+
+		/* flush fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	/* OUT ep */
+	} else {
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+		/* set max packet size UDC CSR	*/
+		tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+		tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+					UDC_CSR_NE_MAX_PKT);
+		writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+		if (use_dma && !ep->in) {
+			/* alloc and init BNA dummy request */
+			ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+			ep->bna_occurred = 0;
+		}
+
+		if (ep->num != UDC_EP0OUT_IX)
+			dev->data_ep_enabled = 1;
+	}
+
+	/* set ep values */
+	tmp = readl(&dev->csr->ne[udc_csr_epix]);
+	/* max packet */
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+	/* ep number */
+	tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+	/* ep direction */
+	tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+	/* ep type */
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+	/* ep config */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+	/* ep interface */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+	/* ep alt */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+	/* write reg */
+	writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+	/* enable ep irq */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	tmp &= AMD_UNMASK_BIT(ep->num);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	/*
+	 * clear NAK by writing CNAK
+	 * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+	 */
+	if (!use_dma || ep->in) {
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(tmp, &ep->regs->ctl);
+		ep->naking = 0;
+		UDC_QUEUE_CNAK(ep, ep->num);
+	}
+	tmp = desc->bEndpointAddress;
+	DBG(dev, "%s enabled\n", usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+	u32		tmp;
+
+	VDBG(ep->dev, "ep-%d reset\n", ep->num);
+	ep->desc = NULL;
+	ep->ep.ops = &udc_ep_ops;
+	INIT_LIST_HEAD(&ep->queue);
+
+	ep->ep.maxpacket = (u16) ~0;
+	/* set NAK */
+	tmp = readl(&ep->regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+	writel(tmp, &ep->regs->ctl);
+	ep->naking = 1;
+
+	/* disable interrupt */
+	tmp = readl(&regs->ep_irqmsk);
+	tmp |= AMD_BIT(ep->num);
+	writel(tmp, &regs->ep_irqmsk);
+
+	if (ep->in) {
+		/* unset P and IN bit of potential former DMA */
+		tmp = readl(&ep->regs->ctl);
+		tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+		writel(tmp, &ep->regs->ctl);
+
+		tmp = readl(&ep->regs->sts);
+		tmp |= AMD_BIT(UDC_EPSTS_IN);
+		writel(tmp, &ep->regs->sts);
+
+		/* flush the fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	}
+	/* reset desc pointer */
+	writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+	struct udc_ep	*ep = NULL;
+	unsigned long	iflags;
+
+	if (!usbep)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (usbep->name == ep0_string || !ep->desc)
+		return -EINVAL;
+
+	DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+	empty_req_queue(ep);
+	ep_init(ep->dev->regs, ep);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+	return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+	struct udc_request	*req;
+	struct udc_data_dma	*dma_desc;
+	struct udc_ep	*ep;
+
+	if (!usbep)
+		return NULL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+
+	VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+	req = kzalloc(sizeof(struct udc_request), gfp);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_DONT_USE;
+	INIT_LIST_HEAD(&req->queue);
+
+	if (ep->dma) {
+		/* ep0 in requests are allocated from data pool here */
+		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+						&req->td_phys);
+		if (!dma_desc) {
+			kfree(req);
+			return NULL;
+		}
+
+		VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+				"td_phys = %lx\n",
+				req, dma_desc,
+				(unsigned long)req->td_phys);
+		/* prevent from using desc. - set HOST BUSY */
+		dma_desc->status = AMD_ADDBITS(dma_desc->status,
+						UDC_DMA_STP_STS_BS_HOST_BUSY,
+						UDC_DMA_STP_STS_BS);
+		dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+		req->td_data = dma_desc;
+		req->td_data_last = NULL;
+		req->chain_len = 1;
+	}
+
+	return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep	*ep;
+	struct udc_request	*req;
+
+	if (!usbep || !usbreq)
+		return;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	req = container_of(usbreq, struct udc_request, req);
+	VDBG(ep->dev, "free_req req=%p\n", req);
+	BUG_ON(!list_empty(&req->queue));
+	if (req->td_data) {
+		VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+		/* free dma chain if created */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+
+		pci_pool_free(ep->dev->data_requests, req->td_data,
+							req->td_phys);
+	}
+	kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+	if (req) {
+		/* set last bit */
+		req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* set next pointer to itself */
+		req->td_data->next = req->td_phys;
+		/* set HOST BUSY */
+		req->td_data->status
+			= AMD_ADDBITS(req->td_data->status,
+					UDC_DMA_STP_STS_BS_DMA_DONE,
+					UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+		pr_debug("bna desc = %p, sts = %08x\n",
+			req->td_data, req->td_data->status);
+#endif
+	}
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+	struct udc_request *req = NULL;
+	struct usb_request *_req = NULL;
+
+	/* alloc the dummy request */
+	_req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+	if (_req) {
+		req = container_of(_req, struct udc_request, req);
+		ep->bna_dummy_req = req;
+		udc_init_bna_dummy(req);
+	}
+	return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+	u8			*req_buf;
+	u32			*buf;
+	int			i, j;
+	unsigned		bytes = 0;
+	unsigned		remaining = 0;
+
+	if (!req || !ep)
+		return;
+
+	req_buf = req->buf + req->actual;
+	prefetch(req_buf);
+	remaining = req->length - req->actual;
+
+	buf = (u32 *) req_buf;
+
+	bytes = ep->ep.maxpacket;
+	if (bytes > remaining)
+		bytes = remaining;
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		writel(*(buf + i), ep->txfifo);
+	}
+
+	/* remaining bytes must be written by byte access */
+	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+		writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+							ep->txfifo);
+	}
+
+	/* dummy write confirm */
+	writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+	int i;
+
+	VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+	for (i = 0; i < dwords; i++) {
+		*(buf + i) = readl(dev->rxfifo);
+	}
+	return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+	int i, j;
+	u32 tmp;
+
+	VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+	}
+
+	/* remaining bytes must be read by byte access */
+	if (bytes % UDC_DWORD_BYTES) {
+		tmp = readl(dev->rxfifo);
+		for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+			*(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+			tmp = tmp >> UDC_BITS_PER_BYTE;
+		}
+	}
+
+	return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+	u8 *buf;
+	unsigned buf_space;
+	unsigned bytes = 0;
+	unsigned finished = 0;
+
+	/* received number bytes */
+	bytes = readl(&ep->regs->sts);
+	bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+	buf_space = req->req.length - req->req.actual;
+	buf = req->req.buf + req->req.actual;
+	if (bytes > buf_space) {
+		if ((buf_space % ep->ep.maxpacket) != 0) {
+			DBG(ep->dev,
+				"%s: rx %d bytes, rx-buf space = %d bytesn\n",
+				ep->ep.name, bytes, buf_space);
+			req->req.status = -EOVERFLOW;
+		}
+		bytes = buf_space;
+	}
+	req->req.actual += bytes;
+
+	/* last packet ? */
+	if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+		|| ((req->req.actual == req->req.length) && !req->req.zero))
+		finished = 1;
+
+	/* read rx fifo bytes */
+	VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+	udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+	return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+	int	retval = 0;
+	u32	tmp;
+
+	VDBG(ep->dev, "prep_dma\n");
+	VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+			ep->num, req->td_data);
+
+	/* set buffer pointer */
+	req->td_data->bufptr = req->req.dma;
+
+	/* set last bit */
+	req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+	/* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+	if (use_dma_ppb) {
+
+		retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+		if (retval != 0) {
+			if (retval == -ENOMEM)
+				DBG(ep->dev, "Out of DMA memory\n");
+			return retval;
+		}
+		if (ep->in) {
+			if (req->req.length == ep->ep.maxpacket) {
+				/* write tx bytes */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						ep->ep.maxpacket,
+						UDC_DMA_IN_STS_TXBYTES);
+
+			}
+		}
+
+	}
+
+	if (ep->in) {
+		VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+				"maxpacket=%d ep%d\n",
+				use_dma_ppb, req->req.length,
+				ep->ep.maxpacket, ep->num);
+		/*
+		 * if bytes < max packet then tx bytes must
+		 * be written in packet per buffer mode
+		 */
+		if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+				|| ep->num == UDC_EP0OUT_IX
+				|| ep->num == UDC_EP0IN_IX) {
+			/* write tx bytes */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						req->req.length,
+						UDC_DMA_IN_STS_TXBYTES);
+			/* reset frame num */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						0,
+						UDC_DMA_IN_STS_FRAMENUM);
+		}
+		/* set HOST BUSY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_BUSY,
+				UDC_DMA_STP_STS_BS);
+	} else {
+		VDBG(ep->dev, "OUT set host ready\n");
+		/* set HOST READY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_READY,
+				UDC_DMA_STP_STS_BS);
+
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+	}
+
+	return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+	struct udc		*dev;
+	unsigned		halted;
+
+	VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+	dev = ep->dev;
+	/* unmap DMA */
+	if (req->dma_mapping) {
+		if (ep->in)
+			pci_unmap_single(dev->pdev,
+					req->req.dma,
+					req->req.length,
+					PCI_DMA_TODEVICE);
+		else
+			pci_unmap_single(dev->pdev,
+					req->req.dma,
+					req->req.length,
+					PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 0;
+		req->req.dma = DMA_DONT_USE;
+	}
+
+	halted = ep->halted;
+	ep->halted = 1;
+
+	/* set new status if pending */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = sts;
+
+	/* remove from ep queue */
+	list_del_init(&req->queue);
+
+	VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+		&req->req, req->req.length, ep->ep.name, sts);
+
+	spin_unlock(&dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+	int ret_val = 0;
+	struct udc_data_dma	*td;
+	struct udc_data_dma	*td_last = NULL;
+	unsigned int i;
+
+	DBG(dev, "free chain req = %p\n", req);
+
+	/* do not free first desc., will be done by free for request */
+	td_last = req->td_data;
+	td = phys_to_virt(td_last->next);
+
+	for (i = 1; i < req->chain_len; i++) {
+
+		pci_pool_free(dev->data_requests, td,
+				(dma_addr_t) td_last->next);
+		td_last = td;
+		td = phys_to_virt(td_last->next);
+	}
+
+	return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+
+	td = req->td_data;
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+		td = phys_to_virt(td->next);
+	}
+
+	return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+	u32 count;
+
+	td = req->td_data;
+	/* received number bytes */
+	count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+		td = phys_to_virt(td->next);
+		/* received number bytes */
+		if (td) {
+			count += AMD_GETBITS(td->status,
+				UDC_DMA_OUT_STS_RXBYTES);
+		}
+	}
+
+	return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+	struct udc_ep *ep,
+	struct udc_request *req,
+	unsigned long buf_len, gfp_t gfp_flags
+)
+{
+	unsigned long bytes = req->req.length;
+	unsigned int i;
+	dma_addr_t dma_addr;
+	struct udc_data_dma	*td = NULL;
+	struct udc_data_dma	*last = NULL;
+	unsigned long txbytes;
+	unsigned create_new_chain = 0;
+	unsigned len;
+
+	VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+			bytes, buf_len);
+	dma_addr = DMA_DONT_USE;
+
+	/* unset L bit in first desc for OUT */
+	if (!ep->in) {
+		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+	}
+
+	/* alloc only new desc's if not already available */
+	len = req->req.length / ep->ep.maxpacket;
+	if (req->req.length % ep->ep.maxpacket) {
+		len++;
+	}
+
+	if (len > req->chain_len) {
+		/* shorter chain already allocated before */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+		req->chain_len = len;
+		create_new_chain = 1;
+	}
+
+	td = req->td_data;
+	/* gen. required number of descriptors and buffers */
+	for (i = buf_len; i < bytes; i += buf_len) {
+		/* create or determine next desc. */
+		if (create_new_chain) {
+
+			td = pci_pool_alloc(ep->dev->data_requests,
+					gfp_flags, &dma_addr);
+			if (!td)
+				return -ENOMEM;
+
+			td->status = 0;
+		} else if (i == buf_len) {
+			/* first td */
+			td = (struct udc_data_dma *) phys_to_virt(
+						req->td_data->next);
+			td->status = 0;
+		} else {
+			td = (struct udc_data_dma *) phys_to_virt(last->next);
+			td->status = 0;
+		}
+
+
+		if (td)
+			td->bufptr = req->req.dma + i; /* assign buffer */
+		else
+			break;
+
+		/* short packet ? */
+		if ((bytes - i) >= buf_len) {
+			txbytes = buf_len;
+		} else {
+			/* short packet */
+			txbytes = bytes - i;
+		}
+
+		/* link td and assign tx bytes */
+		if (i == buf_len) {
+			if (create_new_chain) {
+				req->td_data->next = dma_addr;
+			} else {
+				/* req->td_data->next = virt_to_phys(td); */
+			}
+			/* write tx bytes */
+			if (ep->in) {
+				/* first desc */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+							ep->ep.maxpacket,
+							UDC_DMA_IN_STS_TXBYTES);
+				/* second desc */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		} else {
+			if (create_new_chain) {
+				last->next = dma_addr;
+			} else {
+				/* last->next = virt_to_phys(td); */
+			}
+			if (ep->in) {
+				/* write tx bytes */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		}
+		last = td;
+	}
+	/* set last bit */
+	if (td) {
+		td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* last desc. points to itself */
+		req->td_data_last = td;
+	}
+
+	return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+	u32 tmp;
+
+	VDBG(dev, "udc_set_rde()\n");
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* set RDE */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+	writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+	int			retval = 0;
+	u8			open_rxfifo = 0;
+	unsigned long		iflags;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	struct udc		*dev;
+	u32			tmp;
+
+	/* check the inputs */
+	req = container_of(usbreq, struct udc_request, req);
+
+	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+			|| !list_empty(&req->queue))
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+	dev = ep->dev;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* map dma (usually done before) */
+	if (ep->dma && usbreq->length != 0
+			&& (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+		VDBG(dev, "DMA map req %p\n", req);
+		if (ep->in)
+			usbreq->dma = pci_map_single(dev->pdev,
+						usbreq->buf,
+						usbreq->length,
+						PCI_DMA_TODEVICE);
+		else
+			usbreq->dma = pci_map_single(dev->pdev,
+						usbreq->buf,
+						usbreq->length,
+						PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 1;
+	}
+
+	VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+			usbep->name, usbreq, usbreq->length,
+			req->td_data, usbreq->buf);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+	req->dma_done = 0;
+
+	/* on empty queue just do first transfer */
+	if (list_empty(&ep->queue)) {
+		/* zlp */
+		if (usbreq->length == 0) {
+			/* IN zlp's are handled by hardware */
+			complete_req(ep, req, 0);
+			VDBG(dev, "%s: zlp\n", ep->ep.name);
+			/*
+			 * if set_config or set_intf is waiting for ack by zlp
+			 * then set CSR_DONE
+			 */
+			if (dev->set_cfg_not_acked) {
+				tmp = readl(&dev->regs->ctl);
+				tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+				writel(tmp, &dev->regs->ctl);
+				dev->set_cfg_not_acked = 0;
+			}
+			/* setup command is ACK'ed now by zlp */
+			if (dev->waiting_zlp_ack_ep0in) {
+				/* clear NAK by writing CNAK in EP0_IN */
+				tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+				dev->ep[UDC_EP0IN_IX].naking = 0;
+				UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+							UDC_EP0IN_IX);
+				dev->waiting_zlp_ack_ep0in = 0;
+			}
+			goto finished;
+		}
+		if (ep->dma) {
+			retval = prep_dma(ep, req, gfp);
+			if (retval != 0)
+				goto finished;
+			/* write desc pointer to enable DMA */
+			if (ep->in) {
+				/* set HOST READY */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+			}
+
+			/* disabled rx dma while descriptor update */
+			if (!ep->in) {
+				/* stop RDE timer */
+				if (timer_pending(&udc_timer)) {
+					set_rde = 0;
+					mod_timer(&udc_timer, jiffies - 1);
+				}
+				/* clear RDE */
+				tmp = readl(&dev->regs->ctl);
+				tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+				writel(tmp, &dev->regs->ctl);
+				open_rxfifo = 1;
+
+				/*
+				 * if BNA occurred then let BNA dummy desc.
+				 * point to current desc.
+				 */
+				if (ep->bna_occurred) {
+					VDBG(dev, "copy to BNA dummy desc.\n");
+					memcpy(ep->bna_dummy_req->td_data,
+						req->td_data,
+						sizeof(struct udc_data_dma));
+				}
+			}
+			/* write desc pointer */
+			writel(req->td_phys, &ep->regs->desptr);
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+			if (ep->in) {
+				/* enable ep irq */
+				tmp = readl(&dev->regs->ep_irqmsk);
+				tmp &= AMD_UNMASK_BIT(ep->num);
+				writel(tmp, &dev->regs->ep_irqmsk);
+			}
+		}
+
+	} else if (ep->dma) {
+
+		/*
+		 * prep_dma not used for OUT ep's, this is not possible
+		 * for PPB modes, because of chain creation reasons
+		 */
+		if (ep->in) {
+			retval = prep_dma(ep, req, gfp);
+			if (retval != 0)
+				goto finished;
+		}
+	}
+	VDBG(dev, "list_add\n");
+	/* add request to ep queue */
+	if (req) {
+
+		list_add_tail(&req->queue, &ep->queue);
+
+		/* open rxfifo if out data queued */
+		if (open_rxfifo) {
+			/* enable DMA */
+			req->dma_going = 1;
+			udc_set_rde(dev);
+			if (ep->num != UDC_EP0OUT_IX)
+				dev->data_ep_queued = 1;
+		}
+		/* stop OUT naking */
+		if (!ep->in) {
+			if (!use_dma && udc_rxfifo_pending) {
+				DBG(dev, "udc_queue(): pending bytes in"
+					"rxfifo after nyet\n");
+				/*
+				 * read pending bytes afer nyet:
+				 * referring to isr
+				 */
+				if (udc_rxfifo_read(ep, req)) {
+					/* finish */
+					complete_req(ep, req, 0);
+				}
+				udc_rxfifo_pending = 0;
+
+			}
+		}
+	}
+
+finished:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+	struct udc_request	*req;
+
+	ep->halted = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+			struct udc_request,
+			queue);
+		complete_req(ep, req, -ESHUTDOWN);
+	}
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned		halted;
+	unsigned long		iflags;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+				&& ep->num != UDC_EP0OUT_IX)))
+		return -EINVAL;
+
+	req = container_of(usbreq, struct udc_request, req);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	halted = ep->halted;
+	ep->halted = 1;
+	/* request in processing or next one */
+	if (ep->queue.next == &req->queue) {
+		if (ep->dma && req->dma_going) {
+			if (ep->in)
+				ep->cancel_transfer = 1;
+			else {
+				u32 tmp;
+				u32 dma_sts;
+				/* stop potential receive DMA */
+				tmp = readl(&udc->regs->ctl);
+				writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+							&udc->regs->ctl);
+				/*
+				 * Cancel transfer later in ISR
+				 * if descriptor was touched.
+				 */
+				dma_sts = AMD_GETBITS(req->td_data->status,
+							UDC_DMA_OUT_STS_BS);
+				if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+					ep->cancel_transfer = 1;
+				else {
+					udc_init_bna_dummy(ep->req);
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+				}
+				writel(tmp, &udc->regs->ctl);
+			}
+		}
+	}
+	complete_req(ep, req, -ECONNRESET);
+	ep->halted = halted;
+
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+	return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct udc_ep	*ep;
+	u32 tmp;
+	unsigned long iflags;
+	int retval = 0;
+
+	if (!usbep)
+		return -EINVAL;
+
+	pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* halt or clear halt */
+	if (halt) {
+		if (ep->num == 0)
+			ep->dev->stall_ep0in = 1;
+		else {
+			/*
+			 * set STALL
+			 * rxfifo empty not taken into acount
+			 */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 1;
+
+			/* setup poll timer */
+			if (!timer_pending(&udc_pollstall_timer)) {
+				udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+				if (!stop_pollstall_timer) {
+					DBG(ep->dev, "start polltimer\n");
+					add_timer(&udc_pollstall_timer);
+				}
+			}
+		}
+	} else {
+		/* ep is halted by set_halt() before */
+		if (ep->halted) {
+			tmp = readl(&ep->regs->ctl);
+			/* clear stall bit */
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+	.enable		= udc_ep_enable,
+	.disable	= udc_ep_disable,
+
+	.alloc_request	= udc_alloc_request,
+	.free_request	= udc_free_request,
+
+	.queue		= udc_queue,
+	.dequeue	= udc_dequeue,
+
+	.set_halt	= udc_set_halt,
+	/* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+	return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+	struct udc		*dev;
+
+	if (!gadget)
+		return -EINVAL;
+	dev = container_of(gadget, struct udc, gadget);
+	udc_remote_wakeup(dev);
+
+	return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+	.wakeup		= udc_wakeup,
+	.get_frame	= udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+	/* make gadget ep lists */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+
+	/* fifo config */
+	dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+	dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+	u32 tmp;
+
+	/* init controller by soft reset */
+	udc_soft_reset(dev);
+
+	/* mask not needed interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* put into initial config */
+	udc_basic_init(dev);
+	/* link up all endpoints */
+	udc_setup_endpoints(dev);
+
+	/* program speed */
+	tmp = readl(&dev->regs->cfg);
+	if (use_fullspeed) {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+	} else {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+	}
+	writel(tmp, &dev->regs->cfg);
+
+	return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+	u32	tmp;
+
+	DBG(dev, "udc_basic_init()\n");
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* stop poll stall timer */
+	if (timer_pending(&udc_pollstall_timer)) {
+		mod_timer(&udc_pollstall_timer, jiffies - 1);
+	}
+	/* disable DMA */
+	tmp = readl(&dev->regs->ctl);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+	writel(tmp, &dev->regs->ctl);
+
+	/* enable dynamic CSR programming */
+	tmp = readl(&dev->regs->cfg);
+	tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+	/* set self powered */
+	tmp |= AMD_BIT(UDC_DEVCFG_SP);
+	/* set remote wakeupable */
+	tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+	writel(tmp, &dev->regs->cfg);
+
+	make_ep_lists(dev);
+
+	dev->data_ep_enabled = 0;
+	dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+	struct udc_ep	*ep;
+	u32	tmp;
+	u32	reg;
+
+	DBG(dev, "udc_setup_endpoints()\n");
+
+	/* read enum speed */
+	tmp = readl(&dev->regs->sts);
+	tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+		dev->gadget.speed = USB_SPEED_HIGH;
+	} else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+		dev->gadget.speed = USB_SPEED_FULL;
+	}
+
+	/* set basic ep parameters */
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		ep = &dev->ep[tmp];
+		ep->dev = dev;
+		ep->ep.name = ep_string[tmp];
+		ep->num = tmp;
+		/* txfifo size is calculated at enable time */
+		ep->txfifo = dev->txfifo;
+
+		/* fifo size */
+		if (tmp < UDC_EPIN_NUM) {
+			ep->fifo_depth = UDC_TXFIFO_SIZE;
+			ep->in = 1;
+		} else {
+			ep->fifo_depth = UDC_RXFIFO_SIZE;
+			ep->in = 0;
+
+		}
+		ep->regs = &dev->ep_regs[tmp];
+		/*
+		 * ep will be reset only if ep was not enabled before to avoid
+		 * disabling ep interrupts when ENUM interrupt occurs but ep is
+		 * not enabled by gadget driver
+		 */
+		if (!ep->desc) {
+			ep_init(dev->regs, ep);
+		}
+
+		if (use_dma) {
+			/*
+			 * ep->dma is not really used, just to indicate that
+			 * DMA is active: remove this
+			 * dma regs = dev control regs
+			 */
+			ep->dma = &dev->regs->ctl;
+
+			/* nak OUT endpoints until enable - not for ep0 */
+			if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+						&& tmp > UDC_EPIN_NUM) {
+				/* set NAK */
+				reg = readl(&dev->ep[tmp].regs->ctl);
+				reg |= AMD_BIT(UDC_EPCTL_SNAK);
+				writel(reg, &dev->ep[tmp].regs->ctl);
+				dev->ep[tmp].naking = 1;
+
+			}
+		}
+	}
+	/* EP0 max packet */
+	if (dev->gadget.speed == USB_SPEED_FULL) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+						UDC_FS_EP0OUT_MAX_PKT_SIZE;
+	} else if (dev->gadget.speed == USB_SPEED_HIGH) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+	}
+
+	/*
+	 * with suspend bug workaround, ep0 params for gadget driver
+	 * are set at gadget driver bind() call
+	 */
+	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+	dev->ep[UDC_EP0IN_IX].halted = 0;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+	/* init cfg/alt/int */
+	dev->cur_config = 0;
+	dev->cur_intf = 0;
+	dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Connect\n");
+
+	dev->connected = 1;
+
+	/* put into initial config */
+	udc_basic_init(dev);
+
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+	dev->connected = 0;
+
+	/* mask interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* REVISIT there doesn't seem to be a point to having this
+	 * talk to a tasklet ... do it directly, we already hold
+	 * the spinlock needed to process the disconnect.
+	 */
+
+	tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+	struct udc *dev = (struct udc *)(*((struct udc **) par));
+	u32 tmp;
+
+	DBG(dev, "Tasklet disconnect\n");
+	spin_lock_irq(&dev->lock);
+
+	if (dev->driver) {
+		spin_unlock(&dev->lock);
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* empty queues */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+			empty_req_queue(&dev->ep[tmp]);
+		}
+
+	}
+
+	/* disable ep0 */
+	ep_init(dev->regs,
+			&dev->ep[UDC_EP0IN_IX]);
+
+
+	if (!soft_reset_occured) {
+		/* init controller by soft reset */
+		udc_soft_reset(dev);
+		soft_reset_occured++;
+	}
+
+	/* re-enable dev interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+	/* back to full speed ? */
+	if (use_fullspeed) {
+		tmp = readl(&dev->regs->cfg);
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+		writel(tmp, &dev->regs->cfg);
+	}
+
+	spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+	unsigned long	flags;
+
+	DBG(dev, "Soft reset\n");
+	/*
+	 * reset possible waiting interrupts, because int.
+	 * status is lost after soft reset,
+	 * ep int. status reset
+	 */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+	/* device int. status reset */
+	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+	spin_lock_irqsave(&udc_irq_spinlock, flags);
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	readl(&dev->regs->cfg);
+	spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+	u32 tmp;
+
+	spin_lock_irq(&udc_irq_spinlock);
+
+	if (set_rde > 0) {
+		/*
+		 * open the fifo if fifo was filled on last timer call
+		 * conditionally
+		 */
+		if (set_rde > 1) {
+			/* set RDE to receive setup data */
+			tmp = readl(&udc->regs->ctl);
+			tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+			writel(tmp, &udc->regs->ctl);
+			set_rde = -1;
+		} else if (readl(&udc->regs->sts)
+				& AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			/*
+			 * if fifo empty setup polling, do not just
+			 * open the fifo
+			 */
+			udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		} else {
+			/*
+			 * fifo contains data now, setup timer for opening
+			 * the fifo when timer expires to be able to receive
+			 * setup packets, when data packets gets queued by
+			 * gadget layer then timer will forced to expire with
+			 * set_rde=0 (RDE is set in udc_queue())
+			 */
+			set_rde++;
+			/* debug: lhadmot_timer_start = 221070 */
+			udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		}
+
+	} else
+		set_rde = -1; /* RDE was set by udc_queue() */
+	spin_unlock_irq(&udc_irq_spinlock);
+	if (stop_timer)
+		complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+	u32 tmp;
+	/* set stall as long not halted */
+	if (ep->halted == 1) {
+		tmp = readl(&ep->regs->ctl);
+		/* STALL cleared ? */
+		if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+			/*
+			 * FIXME: MSC spec requires that stall remains
+			 * even on receivng of CLEAR_FEATURE HALT. So
+			 * we would set STALL again here to be compliant.
+			 * But with current mass storage drivers this does
+			 * not work (would produce endless host retries).
+			 * So we clear halt on CLEAR_FEATURE.
+			 *
+			DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);*/
+
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+	struct udc_ep *ep;
+	int halted = 0;
+
+	spin_lock_irq(&udc_stall_spinlock);
+	/*
+	 * only one IN and OUT endpoints are handled
+	 * IN poll stall
+	 */
+	ep = &udc->ep[UDC_EPIN_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+	/* OUT poll stall */
+	ep = &udc->ep[UDC_EPOUT_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+
+	/* setup timer again when still halted */
+	if (!stop_pollstall_timer && halted) {
+		udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+		add_timer(&udc_pollstall_timer);
+	}
+	spin_unlock_irq(&udc_stall_spinlock);
+
+	if (stop_pollstall_timer)
+		complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "activate_control_endpoints\n");
+
+	/* flush fifo */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_F);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+	/* set ep0 directions */
+	dev->ep[UDC_EP0IN_IX].in = 1;
+	dev->ep[UDC_EP0OUT_IX].in = 0;
+
+	/* set buffer size (tx fifo entries) of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+	/* set max packet size of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0_OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0 in UDC CSR */
+	tmp = readl(&dev->csr->ne[0]);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	writel(tmp, &dev->csr->ne[0]);
+
+	if (use_dma) {
+		dev->ep[UDC_EP0OUT_IX].td->status |=
+			AMD_BIT(UDC_DMA_OUT_STS_L);
+		/* write dma desc address */
+		writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+			&dev->ep[UDC_EP0OUT_IX].regs->subptr);
+		writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+			&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+		/* stop RDE timer */
+		if (timer_pending(&udc_timer)) {
+			set_rde = 0;
+			mod_timer(&udc_timer, jiffies - 1);
+		}
+		/* stop pollstall timer */
+		if (timer_pending(&udc_pollstall_timer)) {
+			mod_timer(&udc_pollstall_timer, jiffies - 1);
+		}
+		/* enable DMA */
+		tmp = readl(&dev->regs->ctl);
+		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+				| AMD_BIT(UDC_DEVCTL_RDE)
+				| AMD_BIT(UDC_DEVCTL_TDE);
+		if (use_dma_bufferfill_mode) {
+			tmp |= AMD_BIT(UDC_DEVCTL_BF);
+		} else if (use_dma_ppb_du) {
+			tmp |= AMD_BIT(UDC_DEVCTL_DU);
+		}
+		writel(tmp, &dev->regs->ctl);
+	}
+
+	/* clear NAK by writing CNAK for EP0IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+	dev->ep[UDC_EP0IN_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+	/* clear NAK by writing CNAK for EP0OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	dev->ep[UDC_EP0OUT_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+	activate_control_endpoints(dev);
+	/* enable ep0 interrupts */
+	udc_enable_ep0_interrupts(dev);
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+
+	return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct udc		*dev = udc;
+	int			retval;
+	u32 tmp;
+
+	if (!driver || !driver->bind || !driver->setup
+			|| driver->speed != USB_SPEED_HIGH)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	driver->driver.bus = NULL;
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+
+	retval = driver->bind(&dev->gadget);
+
+	/* Some gadget drivers use both ep0 directions.
+	 * NOTE: to gadget driver, ep0 is just one endpoint...
+	 */
+	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+		dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+	if (retval) {
+		DBG(dev, "binding to %s returning %d\n",
+				driver->driver.name, retval);
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
+		return retval;
+	}
+
+	/* get ready for ep0 traffic */
+	setup_ep0(dev);
+
+	/* clear SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+	usb_connect(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	int tmp;
+
+	/* empty queues and init hardware */
+	udc_basic_init(dev);
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		empty_req_queue(&dev->ep[tmp]);
+	}
+
+	if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+	/* init */
+	udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct udc	*dev = udc;
+	unsigned long	flags;
+	u32 tmp;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	udc_mask_unused_interrupts(dev);
+	shutdown(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+	dev->driver = NULL;
+
+	/* set SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+
+	DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+	u32 tmp;
+	u32 reg;
+
+	/* check epin's */
+	DBG(dev, "CNAK pending queue processing\n");
+	for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+		if (cnak_pending & (1 << tmp)) {
+			DBG(dev, "CNAK pending for ep%d\n", tmp);
+			/* clear NAK by writing CNAK */
+			reg = readl(&dev->ep[tmp].regs->ctl);
+			reg |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(reg, &dev->ep[tmp].regs->ctl);
+			dev->ep[tmp].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+		}
+	}
+	/* ...	and ep0out */
+	if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+		DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+		/* clear NAK by writing CNAK */
+		reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		reg |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		dev->ep[UDC_EP0OUT_IX].naking = 0;
+		UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+				dev->ep[UDC_EP0OUT_IX].num);
+	}
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+	if (use_dma) {
+		/*
+		 * only enable RXDMA when no data endpoint enabled
+		 * or data is queued
+		 */
+		if (!dev->data_ep_enabled || dev->data_ep_queued) {
+			udc_set_rde(dev);
+		} else {
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data endpoints to early)
+			 */
+			if (set_rde != 0 && !timer_pending(&udc_timer)) {
+				udc_timer.expires =
+					jiffies + HZ/UDC_RDE_TIMER_DIV;
+				set_rde = 1;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+		}
+	}
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t		ret_val = IRQ_NONE;
+	u32			tmp;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned int		count;
+	struct udc_data_dma	*td = NULL;
+	unsigned		dma_done;
+
+	VDBG(dev, "ep%d irq\n", ep_ix);
+	ep = &dev->ep[ep_ix];
+
+	tmp = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA event ? */
+		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+			DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+					ep->num, readl(&ep->regs->desptr));
+			/* clear BNA */
+			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+			if (!ep->cancel_transfer)
+				ep->bna_occurred = 1;
+			else
+				ep->cancel_transfer = 0;
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+		/* clear HE */
+		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	if (!list_empty(&ep->queue)) {
+
+		/* next request */
+		req = list_entry(ep->queue.next,
+			struct udc_request, queue);
+	} else {
+		req = NULL;
+		udc_rxfifo_pending = 1;
+	}
+	VDBG(dev, "req = %p\n", req);
+	/* fifo mode */
+	if (!use_dma) {
+
+		/* read fifo */
+		if (req && udc_rxfifo_read(ep, req)) {
+			ret_val = IRQ_HANDLED;
+
+			/* finish */
+			complete_req(ep, req, 0);
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			} else
+				req = NULL;
+		}
+
+	/* DMA */
+	} else if (!ep->cancel_transfer && req != NULL) {
+		ret_val = IRQ_HANDLED;
+
+		/* check for DMA done */
+		if (!use_dma_ppb) {
+			dma_done = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_BS);
+		/* packet per buffer mode - rx bytes */
+		} else {
+			/*
+			 * if BNA occurred then recover desc. from
+			 * BNA dummy desc.
+			 */
+			if (ep->bna_occurred) {
+				VDBG(dev, "Recover desc. from BNA dummy\n");
+				memcpy(req->td_data, ep->bna_dummy_req->td_data,
+						sizeof(struct udc_data_dma));
+				ep->bna_occurred = 0;
+				udc_init_bna_dummy(ep->req);
+			}
+			td = udc_get_last_dma_desc(req);
+			dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+		}
+		if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+			/* buffer fill mode - rx bytes */
+			if (!use_dma_ppb) {
+				/* received number bytes */
+				count = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+				VDBG(dev, "rx bytes=%u\n", count);
+			/* packet per buffer mode - rx bytes */
+			} else {
+				VDBG(dev, "req->td_data=%p\n", req->td_data);
+				VDBG(dev, "last desc = %p\n", td);
+				/* received number bytes */
+				if (use_dma_ppb_du) {
+					/* every desc. counts bytes */
+					count = udc_get_ppbdu_rxbytes(req);
+				} else {
+					/* last desc. counts bytes */
+					count = AMD_GETBITS(td->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+					if (!count && req->req.length
+						== UDC_DMA_MAXPACKET) {
+						/*
+						 * on 64k packets the RXBYTES
+						 * field is zero
+						 */
+						count = UDC_DMA_MAXPACKET;
+					}
+				}
+				VDBG(dev, "last desc rx bytes=%u\n", count);
+			}
+
+			tmp = req->req.length - req->req.actual;
+			if (count > tmp) {
+				if ((tmp % ep->ep.maxpacket) != 0) {
+					DBG(dev, "%s: rx %db, space=%db\n",
+						ep->ep.name, count, tmp);
+					req->req.status = -EOVERFLOW;
+				}
+				count = tmp;
+			}
+			req->req.actual += count;
+			req->dma_going = 0;
+			/* complete request */
+			complete_req(ep, req, 0);
+
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request,
+					queue);
+				/*
+				 * DMA may be already started by udc_queue()
+				 * called by gadget drivers completion
+				 * routine. This happens when queue
+				 * holds one request only.
+				 */
+				if (req->dma_going == 0) {
+					/* next dma */
+					if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+						goto finished;
+					/* write desc pointer */
+					writel(req->td_phys,
+						&ep->regs->desptr);
+					req->dma_going = 1;
+					/* enable DMA */
+					udc_set_rde(dev);
+				}
+			} else {
+				/*
+				 * implant BNA dummy descriptor to allow
+				 * RXFIFO opening by RDE
+				 */
+				if (ep->bna_dummy_req) {
+					/* write desc pointer */
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+					ep->bna_occurred = 0;
+				}
+
+				/*
+				 * schedule timer for setting RDE if queue
+				 * remains empty to allow ep0 packets pass
+				 * through
+				 */
+				if (set_rde != 0
+						&& !timer_pending(&udc_timer)) {
+					udc_timer.expires =
+						jiffies
+						+ HZ*UDC_RDE_TIMER_SECONDS;
+					set_rde = 1;
+					if (!stop_timer) {
+						add_timer(&udc_timer);
+					}
+				}
+				if (ep->num != UDC_EP0OUT_IX)
+					dev->data_ep_queued = 0;
+			}
+
+		} else {
+			/*
+			* RX DMA must be reenabled for each desc in PPBDU mode
+			* and must be enabled for PPBNDU mode in case of BNA
+			*/
+			udc_set_rde(dev);
+		}
+
+	} else if (ep->cancel_transfer) {
+		ret_val = IRQ_HANDLED;
+		ep->cancel_transfer = 0;
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+
+	/* clear OUT bits in ep status */
+	writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 epsts;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	struct udc_data_dma *td;
+	unsigned dma_done;
+	unsigned len;
+
+	ep = &dev->ep[ep_ix];
+
+	epsts = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA ? */
+		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+			dev_err(&dev->pdev->dev,
+				"BNA ep%din occured - DESPTR = %08lx \n",
+				ep->num,
+				(unsigned long) readl(&ep->regs->desptr));
+
+			/* clear BNA */
+			writel(epsts, &ep->regs->sts);
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev,
+			"HE ep%dn occured - DESPTR = %08lx \n",
+			ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+		/* clear HE */
+		writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* DMA completion */
+	if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "TDC set- completion\n");
+		ret_val = IRQ_HANDLED;
+		if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			if (req) {
+				/*
+				 * length bytes transfered
+				 * check dma done of last desc. in PPBDU mode
+				 */
+				if (use_dma_ppb_du) {
+					td = udc_get_last_dma_desc(req);
+					if (td) {
+						dma_done =
+							AMD_GETBITS(td->status,
+							UDC_DMA_IN_STS_BS);
+						/* don't care DMA done */
+						req->req.actual =
+							req->req.length;
+					}
+				} else {
+					/* assume all bytes transferred */
+					req->req.actual = req->req.length;
+				}
+
+				if (req->req.actual == req->req.length) {
+					/* complete req */
+					complete_req(ep, req, 0);
+					req->dma_going = 0;
+					/* further request available ? */
+					if (list_empty(&ep->queue)) {
+						/* disable interrupt */
+						tmp = readl(
+							&dev->regs->ep_irqmsk);
+						tmp |= AMD_BIT(ep->num);
+						writel(tmp,
+							&dev->regs->ep_irqmsk);
+					}
+
+				}
+			}
+		}
+		ep->cancel_transfer = 0;
+
+	}
+	/*
+	 * status reg has IN bit set and TDC not set (if TDC was handled,
+	 * IN must not be handled (UDC defect) ?
+	 */
+	if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+			&& !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+		ret_val = IRQ_HANDLED;
+		if (!list_empty(&ep->queue)) {
+			/* next request */
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			/* FIFO mode */
+			if (!use_dma) {
+				/* write fifo */
+				udc_txfifo_write(ep, &req->req);
+				len = req->req.length - req->req.actual;
+						if (len > ep->ep.maxpacket)
+							len = ep->ep.maxpacket;
+						req->req.actual += len;
+				if (req->req.actual == req->req.length
+					|| (len != ep->ep.maxpacket)) {
+					/* complete req */
+					complete_req(ep, req, 0);
+				}
+			/* DMA */
+			} else if (req && !req->dma_going) {
+				VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+					req, req->td_data);
+				if (req->td_data) {
+
+					req->dma_going = 1;
+
+					/*
+					 * unset L bit of first desc.
+					 * for chain
+					 */
+					if (use_dma_ppb && req->req.length >
+							ep->ep.maxpacket) {
+						req->td_data->status &=
+							AMD_CLEAR_BIT(
+							UDC_DMA_IN_STS_L);
+					}
+
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+
+					/* set poll demand bit */
+					tmp = readl(&ep->regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp, &ep->regs->ctl);
+				}
+			}
+
+		}
+	}
+	/* clear status bits */
+	writel(epsts, &ep->regs->sts);
+
+finished:
+	return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	int setup_supported;
+	u32 count;
+	int set = 0;
+	struct udc_ep	*ep;
+	struct udc_ep	*ep_tmp;
+
+	ep = &dev->ep[UDC_EP0OUT_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+	/* check BNA and clear if set */
+	if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+		VDBG(dev, "ep0: BNA set\n");
+		writel(AMD_BIT(UDC_EPSTS_BNA),
+			&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		ep->bna_occurred = 1;
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* type of data: SETUP or DATA 0 bytes */
+	tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+	VDBG(dev, "data_typ = %x\n", tmp);
+
+	/* setup data */
+	if (tmp == UDC_EPSTS_OUT_SETUP) {
+		ret_val = IRQ_HANDLED;
+
+		ep->dev->stall_ep0in = 0;
+		dev->waiting_zlp_ack_ep0in = 0;
+
+		/* set NAK for EP0_IN */
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+		writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		dev->ep[UDC_EP0IN_IX].naking = 1;
+		/* get setup data */
+		if (use_dma) {
+
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+			setup_data.data[0] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+			setup_data.data[1] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+			/* set HOST READY */
+			dev->ep[UDC_EP0OUT_IX].td_stp->status =
+					UDC_DMA_STP_STS_BS_HOST_READY;
+		} else {
+			/* read fifo */
+			udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+		}
+
+		/* determine direction of control data */
+		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+			/* enable RDE */
+			udc_ep0_set_rde(dev);
+			set = 0;
+		} else {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+			/*
+			 * implant BNA dummy descriptor to allow RXFIFO opening
+			 * by RDE
+			 */
+			if (ep->bna_dummy_req) {
+				/* write desc pointer */
+				writel(ep->bna_dummy_req->td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				ep->bna_occurred = 0;
+			}
+
+			set = 1;
+			dev->ep[UDC_EP0OUT_IX].naking = 1;
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data to early)
+			 */
+			set_rde = 1;
+			if (!timer_pending(&udc_timer)) {
+				udc_timer.expires = jiffies +
+							HZ/UDC_RDE_TIMER_DIV;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+		}
+
+		/*
+		 * mass storage reset must be processed here because
+		 * next packet may be a CLEAR_FEATURE HALT which would not
+		 * clear the stall bit when no STALL handshake was received
+		 * before (autostall can cause this)
+		 */
+		if (setup_data.data[0] == UDC_MSCRES_DWORD0
+				&& setup_data.data[1] == UDC_MSCRES_DWORD1) {
+			DBG(dev, "MSC Reset\n");
+			/*
+			 * clear stall bits
+			 * only one IN and OUT endpoints are handled
+			 */
+			ep_tmp = &udc->ep[UDC_EPIN_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+			ep_tmp = &udc->ep[UDC_EPOUT_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+		}
+
+		/* call gadget with setup data received */
+		spin_unlock(&dev->lock);
+		setup_supported = dev->driver->setup(&dev->gadget,
+						&setup_data.request);
+		spin_lock(&dev->lock);
+
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		/* ep0 in returns data (not zlp) on IN phase */
+		if (setup_supported >= 0 && setup_supported <
+				UDC_EP0IN_MAXPACKET) {
+			/* clear NAK by writing CNAK in EP0_IN */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+			dev->ep[UDC_EP0IN_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+		/* if unsupported request then stall */
+		} else if (setup_supported < 0) {
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		} else
+			dev->waiting_zlp_ack_ep0in = 1;
+
+
+		/* clear NAK by writing CNAK in EP0_OUT */
+		if (!set) {
+			tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			dev->ep[UDC_EP0OUT_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+		}
+
+		if (!use_dma) {
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		}
+
+	/* data packet 0 bytes */
+	} else if (tmp == UDC_EPSTS_OUT_DATA) {
+		/* clear OUT bits in ep status */
+		writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+		/* get setup data: only 0 packet */
+		if (use_dma) {
+			/* no req if 0 packet, just reactivate */
+			if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+				VDBG(dev, "ZLP\n");
+
+				/* set HOST READY */
+				dev->ep[UDC_EP0OUT_IX].td->status =
+					AMD_ADDBITS(
+					dev->ep[UDC_EP0OUT_IX].td->status,
+					UDC_DMA_OUT_STS_BS_HOST_READY,
+					UDC_DMA_OUT_STS_BS);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+				ret_val = IRQ_HANDLED;
+
+			} else {
+				/* control write */
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+				/* re-program desc. pointer for possible ZLPs */
+				writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+			}
+		} else {
+
+			/* received number bytes */
+			count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+			count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+			/* out data for fifo mode not working */
+			count = 0;
+
+			/* 0 packet or real data ? */
+			if (count != 0) {
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+			} else {
+				/* dummy read confirm */
+				readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+				ret_val = IRQ_HANDLED;
+			}
+		}
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	unsigned len;
+
+	ep = &dev->ep[UDC_EP0IN_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+	/* DMA completion */
+	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "isr: TDC clear \n");
+		ret_val = IRQ_HANDLED;
+
+		/* clear TDC bit */
+		writel(AMD_BIT(UDC_EPSTS_TDC),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+
+	/* status reg has IN bit set ? */
+	} else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+		ret_val = IRQ_HANDLED;
+
+		if (ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+		if (dev->stall_ep0in) {
+			DBG(dev, "stall ep0in\n");
+			/* halt ep0in */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		} else {
+			if (!list_empty(&ep->queue)) {
+				/* next request */
+				req = list_entry(ep->queue.next,
+						struct udc_request, queue);
+
+				if (ep->dma) {
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_STP_STS_BS_HOST_READY,
+						UDC_DMA_STP_STS_BS);
+
+					/* set poll demand bit */
+					tmp =
+					readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp,
+					&dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+					/* all bytes will be transferred */
+					req->req.actual = req->req.length;
+
+					/* complete req */
+					complete_req(ep, req, 0);
+
+				} else {
+					/* write fifo */
+					udc_txfifo_write(ep, &req->req);
+
+					/* lengh bytes transfered */
+					len = req->req.length - req->req.actual;
+					if (len > ep->ep.maxpacket)
+						len = ep->ep.maxpacket;
+
+					req->req.actual += len;
+					if (req->req.actual == req->req.length
+						|| (len != ep->ep.maxpacket)) {
+						/* complete req */
+						complete_req(ep, req, 0);
+					}
+				}
+
+			}
+		}
+		ep->halted = 0;
+		dev->stall_ep0in = 0;
+		if (!ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+	}
+
+	return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 cfg;
+	struct udc_ep *ep;
+	u16 i;
+	u8 udc_csr_epix;
+
+	/* SET_CONFIG irq ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+		ret_val = IRQ_HANDLED;
+
+		/* read config value */
+		tmp = readl(&dev->regs->sts);
+		cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+		DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+		dev->cur_config = cfg;
+		dev->set_cfg_not_acked = 1;
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+		setup_data.request.wValue = dev->cur_config;
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep cfg */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+						UDC_CSR_NE_CFG);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* SET_INTERFACE ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+		ret_val = IRQ_HANDLED;
+
+		dev->set_cfg_not_acked = 1;
+		/* read interface and alt setting values */
+		tmp = readl(&dev->regs->sts);
+		dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+		dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+		setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+		setup_data.request.wValue = dev->cur_alt;
+		setup_data.request.wIndex = dev->cur_intf;
+
+		DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+				dev->cur_alt, dev->cur_intf);
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			/* UDC CSR reg */
+			/* set ep values */
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep interface */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+						UDC_CSR_NE_INTF);
+			/* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+			/* ep alt */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+						UDC_CSR_NE_ALT);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* USB reset */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+		DBG(dev, "USB Reset interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* allow soft reset when suspend occurs */
+		soft_reset_occured = 0;
+
+		dev->waiting_zlp_ack_ep0in = 0;
+		dev->set_cfg_not_acked = 0;
+
+		/* mask not needed interrupts */
+		udc_mask_unused_interrupts(dev);
+
+		/* call gadget to resume and reset configs etc. */
+		spin_unlock(&dev->lock);
+		if (dev->sys_suspended && dev->driver->resume) {
+			dev->driver->resume(&dev->gadget);
+			dev->sys_suspended = 0;
+		}
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* soft reset when rxfifo not empty */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+				&& !soft_reset_after_usbreset_occured) {
+			udc_soft_reset(dev);
+			soft_reset_after_usbreset_occured++;
+		}
+
+		/*
+		 * DMA reset to kill potential old DMA hw hang,
+		 * POLL bit is already reset by ep_init() through
+		 * disconnect()
+		 */
+		DBG(dev, "DMA machine reset\n");
+		tmp = readl(&dev->regs->cfg);
+		writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+		writel(tmp, &dev->regs->cfg);
+
+		/* put into initial config */
+		udc_basic_init(dev);
+
+		/* enable device setup interrupts */
+		udc_enable_dev_setup_interrupts(dev);
+
+		/* enable suspend interrupt */
+		tmp = readl(&dev->regs->irqmsk);
+		tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+		writel(tmp, &dev->regs->irqmsk);
+
+	} /* USB suspend */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+		DBG(dev, "USB Suspend interrupt\n");
+		ret_val = IRQ_HANDLED;
+		if (dev->driver->suspend) {
+			spin_unlock(&dev->lock);
+			dev->sys_suspended = 1;
+			dev->driver->suspend(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
+	} /* new speed ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+		DBG(dev, "ENUM interrupt\n");
+		ret_val = IRQ_HANDLED;
+		soft_reset_after_usbreset_occured = 0;
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* link up all endpoints */
+		udc_setup_endpoints(dev);
+		if (dev->gadget.speed == USB_SPEED_HIGH) {
+			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+				"high");
+		} else if (dev->gadget.speed == USB_SPEED_FULL) {
+			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+				"full");
+		}
+
+		/* init ep 0 */
+		activate_control_endpoints(dev);
+
+		/* enable ep0 interrupts */
+		udc_enable_ep0_interrupts(dev);
+	}
+	/* session valid change interrupt */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+		DBG(dev, "USB SVC interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* check that session is not valid to detect disconnect */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+			/* disable suspend interrupt */
+			tmp = readl(&dev->regs->irqmsk);
+			tmp |= AMD_BIT(UDC_DEVINT_US);
+			writel(tmp, &dev->regs->irqmsk);
+			DBG(dev, "USB Disconnect (session valid low)\n");
+			/* cleanup on disconnect */
+			usb_disconnect(udc);
+		}
+
+	}
+
+	return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+	struct udc *dev = pdev;
+	u32 reg;
+	u16 i;
+	u32 ep_irq;
+	irqreturn_t ret_val = IRQ_NONE;
+
+	spin_lock(&dev->lock);
+
+	/* check for ep irq */
+	reg = readl(&dev->regs->ep_irqsts);
+	if (reg) {
+		if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+			ret_val |= udc_control_out_isr(dev);
+		if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+			ret_val |= udc_control_in_isr(dev);
+
+		/*
+		 * data endpoint
+		 * iterate ep's
+		 */
+		for (i = 1; i < UDC_EP_NUM; i++) {
+			ep_irq = 1 << i;
+			if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+				continue;
+
+			/* clear irq status */
+			writel(ep_irq, &dev->regs->ep_irqsts);
+
+			/* irq for out ep ? */
+			if (i > UDC_EPIN_NUM)
+				ret_val |= udc_data_out_isr(dev, i);
+			else
+				ret_val |= udc_data_in_isr(dev, i);
+		}
+
+	}
+
+
+	/* check for dev irq */
+	reg = readl(&dev->regs->irqsts);
+	if (reg) {
+		/* clear irq */
+		writel(reg, &dev->regs->irqsts);
+		ret_val |= udc_dev_isr(dev, reg);
+	}
+
+
+	spin_unlock(&dev->lock);
+	return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+	struct amd5536udc *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+	/* remove timer */
+	stop_timer++;
+	if (timer_pending(&udc_timer))
+		wait_for_completion(&on_exit);
+	if (udc_timer.data)
+		del_timer_sync(&udc_timer);
+	/* remove pollstall timer */
+	stop_pollstall_timer++;
+	if (timer_pending(&udc_pollstall_timer))
+		wait_for_completion(&on_pollstall_exit);
+	if (udc_pollstall_timer.data)
+		del_timer_sync(&udc_pollstall_timer);
+	udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+	struct udc		*dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	/* gadget driver must not be registered */
+	BUG_ON(dev->driver != NULL);
+
+	/* dma pool cleanup */
+	if (dev->data_requests)
+		pci_pool_destroy(dev->data_requests);
+
+	if (dev->stp_requests) {
+		/* cleanup DMA desc's for ep0in */
+		pci_pool_free(dev->stp_requests,
+			dev->ep[UDC_EP0OUT_IX].td_stp,
+			dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+		pci_pool_free(dev->stp_requests,
+			dev->ep[UDC_EP0OUT_IX].td,
+			dev->ep[UDC_EP0OUT_IX].td_phys);
+
+		pci_pool_destroy(dev->stp_requests);
+	}
+
+	/* reset controller */
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	if (dev->irq_registered)
+		free_irq(pdev->irq, dev);
+	if (dev->regs)
+		iounmap(dev->regs);
+	if (dev->mem_region)
+		release_mem_region(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0));
+	if (dev->active)
+		pci_disable_device(pdev);
+
+	device_unregister(&dev->gadget.dev);
+	pci_set_drvdata(pdev, NULL);
+
+	udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+	struct udc_stp_dma	*td_stp;
+	struct udc_data_dma	*td_data;
+	int retval;
+
+	/* consistent DMA mode setting ? */
+	if (use_dma_ppb) {
+		use_dma_bufferfill_mode = 0;
+	} else {
+		use_dma_ppb_du = 0;
+		use_dma_bufferfill_mode = 1;
+	}
+
+	/* DMA setup */
+	dev->data_requests = dma_pool_create("data_requests", NULL,
+		sizeof(struct udc_data_dma), 0, 0);
+	if (!dev->data_requests) {
+		DBG(dev, "can't get request data pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+
+	/* EP0 in dma regs = dev control regs */
+	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+	/* dma desc for setup data */
+	dev->stp_requests = dma_pool_create("setup requests", NULL,
+		sizeof(struct udc_stp_dma), 0, 0);
+	if (!dev->stp_requests) {
+		DBG(dev, "can't get stp request pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+	/* setup */
+	td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+	if (td_stp == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+	/* data: 0 packets !? */
+	td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_phys);
+	if (td_data == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td = td_data;
+	return 0;
+
+finished:
+	return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+	struct pci_dev *pdev,
+	const struct pci_device_id *id
+)
+{
+	struct udc		*dev;
+	unsigned long		resource;
+	unsigned long		len;
+	int			retval = 0;
+
+	/* one udc only */
+	if (udc) {
+		dev_dbg(&pdev->dev, "already probed\n");
+		return -EBUSY;
+	}
+
+	/* init */
+	dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	memset(dev, 0, sizeof(struct udc));
+
+	/* pci setup */
+	if (pci_enable_device(pdev) < 0) {
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev->active = 1;
+
+	/* PCI resource allocation */
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+
+	if (!request_mem_region(resource, len, name)) {
+		dev_dbg(&pdev->dev, "pci device used already\n");
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->mem_region = 1;
+
+	dev->virt_addr = ioremap_nocache(resource, len);
+	if (dev->virt_addr == NULL) {
+		dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+		retval = -EFAULT;
+		goto finished;
+	}
+
+	if (!pdev->irq) {
+		dev_err(&dev->pdev->dev, "irq not set\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+
+	if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+		dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->irq_registered = 1;
+
+	pci_set_drvdata(pdev, dev);
+
+	/* chip revision */
+	dev->chiprev = 0;
+
+	pci_set_master(pdev);
+	pci_set_mwi(pdev);
+
+	/* chip rev for Hs AMD5536 */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+	/* init dma pools */
+	if (use_dma) {
+		retval = init_dma_pools(dev);
+		if (retval != 0)
+			goto finished;
+	}
+
+	dev->phys_addr = resource;
+	dev->irq = pdev->irq;
+	dev->pdev = pdev;
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	/* general probing */
+	if (udc_probe(dev) == 0)
+		return 0;
+
+finished:
+	if (dev)
+		udc_pci_remove(pdev);
+	return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+	char		tmp[128];
+	u32		reg;
+	int		retval;
+
+	/* mark timer as not initialized */
+	udc_timer.data = 0;
+	udc_pollstall_timer.data = 0;
+
+	/* device struct setup */
+	spin_lock_init(&dev->lock);
+	dev->gadget.ops = &udc_ops;
+
+	strcpy(dev->gadget.dev.bus_id, "gadget");
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = name;
+	dev->gadget.name = name;
+	dev->gadget.is_dualspeed = 1;
+
+	/* udc csr registers base */
+	dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+	/* dev registers base */
+	dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+	/* ep registers base */
+	dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+	/* fifo's base */
+	dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+	dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+	/* init registers, interrupts, ... */
+	startup_registers(dev);
+
+	dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+	snprintf(tmp, sizeof tmp, "%d", dev->irq);
+	dev_info(&dev->pdev->dev,
+		"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+		tmp, dev->phys_addr, dev->chiprev,
+		(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+	if (dev->chiprev == UDC_HSA0_REV) {
+		dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev_info(&dev->pdev->dev,
+		"driver version: %s(for Geode5536 B1)\n", tmp);
+	udc = dev;
+
+	retval = device_register(&dev->gadget.dev);
+	if (retval)
+		goto finished;
+
+	/* timer init */
+	init_timer(&udc_timer);
+	udc_timer.function = udc_timer_function;
+	udc_timer.data = 1;
+	/* timer pollstall init */
+	init_timer(&udc_pollstall_timer);
+	udc_pollstall_timer.function = udc_pollstall_timer_function;
+	udc_pollstall_timer.data = 1;
+
+	/* set SD */
+	reg = readl(&dev->regs->ctl);
+	reg |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(reg, &dev->regs->ctl);
+
+	/* print dev register info */
+	print_regs(dev);
+
+	return 0;
+
+finished:
+	return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	DBG(dev, "UDC initiates remote wakeup\n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+	tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+		.class =	(PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+		.class_mask =	0xffffffff,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+	.name =		(char *) name,
+	.id_table =	pci_id,
+	.probe =	udc_pci_probe,
+	.remove =	udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+	return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+	pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 0000000..4bbabbb
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS		1
+#define UDC_RDE_TIMER_DIV		10
+#define UDC_POLLSTALL_TIMER_USECONDS	500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0			0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK		0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS		16
+
+#define UDC_SETCONFIG_DWORD1			0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0			0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK		0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS		16
+
+#define UDC_SETINTF_DWORD1			0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK		0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS		0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0			0x0000ff21
+#define UDC_MSCRES_DWORD1			0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR				0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK			0x0000000f
+#define UDC_CSR_NE_NUM_OFS			0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK			0x00000010
+#define UDC_CSR_NE_DIR_OFS			4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK			0x00000060
+#define UDC_CSR_NE_TYPE_OFS			5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK			0x00000780
+#define UDC_CSR_NE_CFG_OFS			7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK			0x00007800
+#define UDC_CSR_NE_INTF_OFS			11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK			0x00078000
+#define UDC_CSR_NE_ALT_OFS			15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK			0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS			19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR				0x400
+
+#define UDC_DEVCFG_SOFTRESET			31
+#define UDC_DEVCFG_HNPSFEN			30
+#define UDC_DEVCFG_DMARST			29
+#define UDC_DEVCFG_SET_DESC			18
+#define UDC_DEVCFG_CSR_PRG			17
+#define UDC_DEVCFG_STATUS			7
+#define UDC_DEVCFG_DIR				6
+#define UDC_DEVCFG_PI				5
+#define UDC_DEVCFG_SS				4
+#define UDC_DEVCFG_SP				3
+#define UDC_DEVCFG_RWKP				2
+
+#define UDC_DEVCFG_SPD_MASK			0x3
+#define UDC_DEVCFG_SPD_OFS			0
+#define UDC_DEVCFG_SPD_HS			0x0
+#define UDC_DEVCFG_SPD_FS			0x1
+#define UDC_DEVCFG_SPD_LS			0x2
+/*#define UDC_DEVCFG_SPD_FS			0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR				0x404
+
+#define UDC_DEVCTL_THLEN_MASK			0xff000000
+#define UDC_DEVCTL_THLEN_OFS			24
+
+#define UDC_DEVCTL_BRLEN_MASK			0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS			16
+
+#define UDC_DEVCTL_CSR_DONE			13
+#define UDC_DEVCTL_DEVNAK			12
+#define UDC_DEVCTL_SD				10
+#define UDC_DEVCTL_MODE				9
+#define UDC_DEVCTL_BREN				8
+#define UDC_DEVCTL_THE				7
+#define UDC_DEVCTL_BF				6
+#define UDC_DEVCTL_BE				5
+#define UDC_DEVCTL_DU				4
+#define UDC_DEVCTL_TDE				3
+#define UDC_DEVCTL_RDE				2
+#define UDC_DEVCTL_RES				0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR				0x408
+
+#define UDC_DEVSTS_TS_MASK			0xfffc0000
+#define UDC_DEVSTS_TS_OFS			18
+
+#define UDC_DEVSTS_SESSVLD			17
+#define UDC_DEVSTS_PHY_ERROR			16
+#define UDC_DEVSTS_RXFIFO_EMPTY			15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK		0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS		13
+#define UDC_DEVSTS_ENUM_SPEED_FULL		1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH		0
+
+#define UDC_DEVSTS_SUSP				12
+
+#define UDC_DEVSTS_ALT_MASK			0x00000f00
+#define UDC_DEVSTS_ALT_OFS			8
+
+#define UDC_DEVSTS_INTF_MASK			0x000000f0
+#define UDC_DEVSTS_INTF_OFS			4
+
+#define UDC_DEVSTS_CFG_MASK			0x0000000f
+#define UDC_DEVSTS_CFG_OFS			0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR				0x40c
+
+#define UDC_DEVINT_SVC				7
+#define UDC_DEVINT_ENUM				6
+#define UDC_DEVINT_SOF				5
+#define UDC_DEVINT_US				4
+#define UDC_DEVINT_UR				3
+#define UDC_DEVINT_ES				2
+#define UDC_DEVINT_SI				1
+#define UDC_DEVINT_SC				0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR			0x410
+
+#define UDC_DEVINT_MSK				0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR				0x414
+
+#define UDC_EPINT_OUT_MASK			0xffff0000
+#define UDC_EPINT_OUT_OFS			16
+#define UDC_EPINT_IN_MASK			0x0000ffff
+#define UDC_EPINT_IN_OFS			0
+
+#define UDC_EPINT_IN_EP0			0
+#define UDC_EPINT_IN_EP1			1
+#define UDC_EPINT_IN_EP2			2
+#define UDC_EPINT_IN_EP3			3
+#define UDC_EPINT_OUT_EP0			16
+#define UDC_EPINT_OUT_EP1			17
+#define UDC_EPINT_OUT_EP2			18
+#define UDC_EPINT_OUT_EP3			19
+
+#define UDC_EPINT_EP0_ENABLE_MSK		0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR			0x418
+
+#define UDC_EPINT_OUT_MSK_MASK			0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS			16
+#define UDC_EPINT_IN_MSK_MASK			0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS			0
+
+#define UDC_EPINT_MSK_DISABLE_ALL		0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE		0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE			0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR				0x0
+#define UDC_EPIN_REGS_ADDR			0x0
+#define UDC_EPOUT_REGS_ADDR			0x200
+
+#define UDC_EPCTL_ADDR				0x0
+
+#define UDC_EPCTL_RRDY				9
+#define UDC_EPCTL_CNAK				8
+#define UDC_EPCTL_SNAK				7
+#define UDC_EPCTL_NAK				6
+
+#define UDC_EPCTL_ET_MASK			0x00000030
+#define UDC_EPCTL_ET_OFS			4
+#define UDC_EPCTL_ET_CONTROL			0
+#define UDC_EPCTL_ET_ISO			1
+#define UDC_EPCTL_ET_BULK			2
+#define UDC_EPCTL_ET_INTERRUPT			3
+
+#define UDC_EPCTL_P				3
+#define UDC_EPCTL_SN				2
+#define UDC_EPCTL_F				1
+#define UDC_EPCTL_S				0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR				0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK		0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS		11
+
+#define UDC_EPSTS_TDC				10
+#define UDC_EPSTS_HE				9
+#define UDC_EPSTS_BNA				7
+#define UDC_EPSTS_IN				6
+
+#define UDC_EPSTS_OUT_MASK			0x00000030
+#define UDC_EPSTS_OUT_OFS			4
+#define UDC_EPSTS_OUT_DATA			1
+#define UDC_EPSTS_OUT_DATA_CLEAR		0x10
+#define UDC_EPSTS_OUT_SETUP			2
+#define UDC_EPSTS_OUT_SETUP_CLEAR		0x20
+#define UDC_EPSTS_OUT_CLEAR			0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR			0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR		0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK			0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS			0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE			32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE			32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT			2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE			256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE		32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE			32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK		0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS		0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR		0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR		0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK		0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS			16
+#define UDC_EP_MAX_PKT_SIZE_MASK		0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS			0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE			64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE			64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE		64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE		64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK		0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS			16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK		0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS		16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK		0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS		20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK		0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS		24
+#define UDC_DMA_STP_STS_RX_MASK			0x30000000
+#define UDC_DMA_STP_STS_RX_OFS			28
+#define UDC_DMA_STP_STS_BS_MASK			0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS			30
+#define UDC_DMA_STP_STS_BS_HOST_READY		0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY		1
+#define UDC_DMA_STP_STS_BS_DMA_DONE		2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY		3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK		0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS		0
+#define	UDC_DMA_IN_STS_FRAMENUM_MASK		0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS		0
+#define UDC_DMA_IN_STS_L			27
+#define UDC_DMA_IN_STS_TX_MASK			0x30000000
+#define UDC_DMA_IN_STS_TX_OFS			28
+#define UDC_DMA_IN_STS_BS_MASK			0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS			30
+#define UDC_DMA_IN_STS_BS_HOST_READY		0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY		1
+#define UDC_DMA_IN_STS_BS_DMA_DONE		2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY		3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK		0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS		0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK		0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS		0
+#define UDC_DMA_OUT_STS_L			27
+#define UDC_DMA_OUT_STS_RX_MASK			0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS			28
+#define UDC_DMA_OUT_STS_BS_MASK			0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS			30
+#define UDC_DMA_OUT_STS_BS_HOST_READY		0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY		1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE		2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY		3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET			1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET			65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE				(~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR			0x10
+#define UDC_EP_DESPTR_ADDR			0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR		0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM				32
+#define UDC_EPIN_NUM				16
+#define UDC_EPIN_NUM_USED			5
+#define UDC_EPOUT_NUM				16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM				9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS			12
+
+#define UDC_EP0OUT_IX				16
+#define UDC_EP0IN_IX				0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR				0x800
+#define UDC_RXFIFO_SIZE				0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR				0xc00
+#define UDC_TXFIFO_SIZE				0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX			1
+#define UDC_EPIN_IX				2
+#define UDC_EPOUT_IX				18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES				4
+#define UDC_BITS_PER_BYTE_SHIFT			3
+#define UDC_BYTE_MASK				0xff
+#define UDC_BITS_PER_BYTE			8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+	/* sca - setup command address */
+	u32 sca;
+
+	/* ep ne's */
+	u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+	/* device configuration */
+	u32 cfg;
+
+	/* device control */
+	u32 ctl;
+
+	/* device status */
+	u32 sts;
+
+	/* device interrupt */
+	u32 irqsts;
+
+	/* device interrupt mask */
+	u32 irqmsk;
+
+	/* endpoint interrupt */
+	u32 ep_irqsts;
+
+	/* endpoint interrupt mask */
+	u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+	/* endpoint control */
+	u32 ctl;
+
+	/* endpoint status */
+	u32 sts;
+
+	/* endpoint buffer size in/ receive packet frame number out */
+	u32 bufin_framenum;
+
+	/* endpoint buffer size out/max packet size */
+	u32 bufout_maxpkt;
+
+	/* endpoint setup buffer pointer */
+	u32 subptr;
+
+	/* endpoint data descriptor pointer */
+	u32 desptr;
+
+	/* reserverd */
+	u32 reserved;
+
+	/* write/read confirmation */
+	u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+	/* status quadlet */
+	u32	status;
+	/* reserved */
+	u32	_reserved;
+	/* first setup word */
+	u32	data12;
+	/* second setup word */
+	u32	data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+	/* status quadlet */
+	u32	status;
+	/* reserved */
+	u32	_reserved;
+	/* buffer pointer */
+	u32	bufptr;
+	/* next descriptor pointer */
+	u32	next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+	/* embedded gadget ep */
+	struct usb_request		req;
+
+	/* flags */
+	unsigned			dma_going : 1,
+					dma_mapping : 1,
+					dma_done : 1;
+	/* phys. address */
+	dma_addr_t			td_phys;
+	/* first dma desc. of chain */
+	struct udc_data_dma		*td_data;
+	/* last dma desc. of chain */
+	struct udc_data_dma		*td_data_last;
+	struct list_head		queue;
+
+	/* chain length */
+	unsigned			chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+	struct usb_ep			ep;
+	struct udc_ep_regs __iomem	*regs;
+	u32 __iomem			*txfifo;
+	u32 __iomem			*dma;
+	dma_addr_t			td_phys;
+	dma_addr_t			td_stp_dma;
+	struct udc_stp_dma		*td_stp;
+	struct udc_data_dma		*td;
+	/* temp request */
+	struct udc_request		*req;
+	unsigned			req_used;
+	unsigned			req_completed;
+	/* dummy DMA desc for BNA dummy */
+	struct udc_request		*bna_dummy_req;
+	unsigned			bna_occurred;
+
+	/* NAK state */
+	unsigned			naking;
+
+	struct udc			*dev;
+
+	/* queue for requests */
+	struct list_head		queue;
+	const struct usb_endpoint_descriptor	*desc;
+	unsigned			halted;
+	unsigned			cancel_transfer;
+	unsigned			num : 5,
+					fifo_depth : 14,
+					in : 1;
+};
+
+/* device struct */
+struct udc {
+	struct usb_gadget		gadget;
+	spinlock_t			lock;	/* protects all state */
+	/* all endpoints */
+	struct udc_ep			ep[UDC_EP_NUM];
+	struct usb_gadget_driver	*driver;
+	/* operational flags */
+	unsigned			active : 1,
+					stall_ep0in : 1,
+					waiting_zlp_ack_ep0in : 1,
+					set_cfg_not_acked : 1,
+					irq_registered : 1,
+					data_ep_enabled : 1,
+					data_ep_queued : 1,
+					mem_region : 1,
+					sys_suspended : 1,
+					connected;
+
+	u16				chiprev;
+
+	/* registers */
+	struct pci_dev			*pdev;
+	struct udc_csrs __iomem		*csr;
+	struct udc_regs __iomem		*regs;
+	struct udc_ep_regs __iomem	*ep_regs;
+	u32 __iomem			*rxfifo;
+	u32 __iomem			*txfifo;
+
+	/* DMA desc pools */
+	struct pci_pool			*data_requests;
+	struct pci_pool			*stp_requests;
+
+	/* device data */
+	unsigned long			phys_addr;
+	void __iomem			*virt_addr;
+	unsigned			irq;
+
+	/* states */
+	u16				cur_config;
+	u16				cur_intf;
+	u16				cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+	u32			data[2];
+	struct usb_ctrlrequest	request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)		\
+	(((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))	\
+	| (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))		\
+		& ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)	\
+	((u32Val)							\
+	| (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))		\
+		& ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name)				\
+	((u32Val & ((u32) bitfield_stub_name##_MASK))			\
+		>> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...)	dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG			DBG
+#else
+#define VDBG(udc , args...)	do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index dbaf867..a337673 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -305,6 +305,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define	DEV_CONFIG_CDC
+#endif
+
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 53e9139..f7f159c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -17,6 +17,12 @@
 #define	gadget_is_net2280(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define	gadget_is_amd5536udc(g)	!strcmp("amd5536udc", (g)->name)
+#else
+#define	gadget_is_amd5536udc(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_DUMMY_HCD
 #define	gadget_is_dummy(g)	!strcmp("dummy_udc", (g)->name)
 #else
@@ -202,7 +208,9 @@
 		return 0x18;
 	else if (gadget_is_fsl_usb2(gadget))
 		return 0x19;
-	else if (gadget_is_m66592(gadget))
+	else if (gadget_is_amd5536udc(gadget))
 		return 0x20;
+	else if (gadget_is_m66592(gadget))
+		return 0x21;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 0174a32..700dda8 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -21,26 +21,18 @@
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
+
 #include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
 #include "m66592-udc.h"
 
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
@@ -49,16 +41,21 @@
 /* module parameters */
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+		"(default=16384)");
+
 static unsigned short vif = M66592_LDRV;
 module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+		"(default=2)");
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@
 			gfp_t gfp_flags);
 
 static void transfer_complete(struct m66592_ep *ep,
-			      struct m66592_request *req,
-			      int status);
+		struct m66592_request *req, int status);
+
 /*-------------------------------------------------------------------------*/
 static inline u16 get_usb_speed(struct m66592 *m66592)
 {
@@ -81,25 +78,25 @@
 }
 
 static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-			    unsigned long reg)
+		unsigned long reg)
 {
 	u16 tmp;
 
 	tmp = m66592_read(m66592, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bset(m66592, (1 << pipenum), reg);
 	m66592_write(m66592, tmp, M66592_INTENB0);
 }
 
 static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-			     unsigned long reg)
+		unsigned long reg)
 {
 	u16 tmp;
 
 	tmp = m66592_read(m66592, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bclr(m66592, (1 << pipenum), reg);
 	m66592_write(m66592, tmp, M66592_INTENB0);
 }
@@ -108,17 +105,19 @@
 {
 	m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
 	m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 
 	m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
 }
 
 static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
 
@@ -148,7 +147,7 @@
 }
 
 static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
-				       u16 pid)
+		u16 pid)
 {
 	unsigned long offset;
 
@@ -250,7 +249,7 @@
 }
 
 static int pipe_buffer_setting(struct m66592 *m66592,
-			       struct m66592_pipe_info *info)
+		struct m66592_pipe_info *info)
 {
 	u16 bufnum = 0, buf_bsize = 0;
 	u16 pipecfg = 0;
@@ -287,7 +286,7 @@
 	}
 	if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
 		printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
-		       m66592->bi_bufnum);
+				m66592->bi_bufnum);
 		return -ENOMEM;
 	}
 
@@ -328,7 +327,7 @@
 			m66592->bulk--;
 	} else
 		printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
-		       info->pipe);
+				info->pipe);
 }
 
 static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@
 }
 
 static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
-			      const struct usb_endpoint_descriptor *desc,
-			      u16 pipenum, int dma)
+		const struct usb_endpoint_descriptor *desc,
+		u16 pipenum, int dma)
 {
 	if ((pipenum != 0) && dma) {
 		if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@
 
 	ep->pipectr = get_pipectr_addr(pipenum);
 	ep->pipenum = pipenum;
-	ep->ep.maxpacket = desc->wMaxPacketSize;
+	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
 	m66592->pipenum2ep[pipenum] = ep;
 	m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
 	INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@
 }
 
 static int alloc_pipe_config(struct m66592_ep *ep,
-			     const struct usb_endpoint_descriptor *desc)
+		const struct usb_endpoint_descriptor *desc)
 {
 	struct m66592 *m66592 = ep->m66592;
 	struct m66592_pipe_info info;
@@ -419,15 +418,15 @@
 
 	BUG_ON(ep->pipenum);
 
-	switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
 	case USB_ENDPOINT_XFER_BULK:
 		if (m66592->bulk >= M66592_MAX_NUM_BULK) {
 			if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
 				printk(KERN_ERR "bulk pipe is insufficient\n");
 				return -ENODEV;
 			} else {
-				info.pipe = M66592_BASE_PIPENUM_ISOC +
-					    m66592->isochronous;
+				info.pipe = M66592_BASE_PIPENUM_ISOC
+						+ m66592->isochronous;
 				counter = &m66592->isochronous;
 			}
 		} else {
@@ -462,7 +461,7 @@
 	ep->type = info.type;
 
 	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	info.maxpacket = desc->wMaxPacketSize;
+	info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
 	info.interval = desc->bInterval;
 	if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 		info.dir_in = 1;
@@ -525,8 +524,8 @@
 
 	pipe_change(m66592, ep->pipenum);
 	m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
-		    (M66592_ISEL | M66592_CURPIPE),
-		    M66592_CFIFOSEL);
+			(M66592_ISEL | M66592_CURPIPE),
+			M66592_CFIFOSEL);
 	m66592_write(m66592, M66592_BCLR, ep->fifoctr);
 	if (req->req.length == 0) {
 		m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@
 
 	if (ep->pipenum == 0) {
 		m66592_mdfy(m66592, M66592_PIPE0,
-			    (M66592_ISEL | M66592_CURPIPE),
-			    M66592_CFIFOSEL);
+				(M66592_ISEL | M66592_CURPIPE),
+				M66592_CFIFOSEL);
 		m66592_write(m66592, M66592_BCLR, ep->fifoctr);
 		pipe_start(m66592, pipenum);
 		pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@
 			pipe_change(m66592, pipenum);
 			m66592_bset(m66592, M66592_TRENB, ep->fifosel);
 			m66592_write(m66592,
-				     (req->req.length + ep->ep.maxpacket - 1) /
-				     ep->ep.maxpacket, ep->fifotrn);
+				(req->req.length + ep->ep.maxpacket - 1)
+					/ ep->ep.maxpacket,
+				ep->fifotrn);
 		}
 		pipe_start(m66592, pipenum);	/* trigger once */
 		pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@
 static void init_controller(struct m66592 *m66592)
 {
 	m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
-		    M66592_PINCFG);
+			M66592_PINCFG);
 	m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);		/* High spd */
 	m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
 
@@ -634,7 +634,7 @@
 
 	m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
 	m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
-		     M66592_DMA0CFG);
+			M66592_DMA0CFG);
 }
 
 static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@
 
 /*-------------------------------------------------------------------------*/
 static void transfer_complete(struct m66592_ep *ep,
-			      struct m66592_request *req,
-			      int status)
+		struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	int restart = 0;
 
@@ -680,8 +681,9 @@
 	if (!list_empty(&ep->queue))
 		restart = 1;
 
-	if (likely(req->req.complete))
-		req->req.complete(&ep->ep, &req->req);
+	spin_unlock(&ep->m66592->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&ep->m66592->lock);
 
 	if (restart) {
 		req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@
 static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 {
 	int i;
-	volatile u16 tmp;
+	u16 tmp;
 	unsigned bufsize;
 	size_t size;
 	void *buf;
@@ -731,8 +733,9 @@
 	req->req.actual += size;
 
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		disable_irq_ready(m66592, pipenum);
 		disable_irq_empty(m66592, pipenum);
 	} else {
@@ -768,16 +771,19 @@
 	/* write fifo */
 	if (req->req.buf) {
 		m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
-		if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
-		    ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+		if ((size == 0)
+				|| ((size % ep->ep.maxpacket) != 0)
+				|| ((bufsize != ep->ep.maxpacket)
+					&& (bufsize > size)))
 			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
 	}
 
 	/* update parameters */
 	req->req.actual += size;
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		disable_irq_ready(m66592, pipenum);
 		enable_irq_empty(m66592, pipenum);
 	} else {
@@ -821,8 +827,9 @@
 	req->req.actual += size;
 
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		pipe_stop(m66592, pipenum);
 		pipe_irq_disable(m66592, pipenum);
 		finish = 1;
@@ -850,7 +857,7 @@
 	if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
 		m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
 		m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
-			    M66592_CFIFOSEL);
+				M66592_CFIFOSEL);
 
 		ep = &m66592->ep[0];
 		req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@
 }
 
 static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	struct m66592_ep *ep;
 	u16 pid;
 	u16 status = 0;
+	u16 w_index = le16_to_cpu(ctrl->wIndex);
 
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	case USB_RECIP_DEVICE:
-		status = 1;	/* selfpower */
+		status = 1 << USB_DEVICE_SELF_POWERED;
 		break;
 	case USB_RECIP_INTERFACE:
 		status = 0;
 		break;
 	case USB_RECIP_ENDPOINT:
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pid = control_reg_get_pid(m66592, ep->pipenum);
 		if (pid == M66592_PID_STALL)
-			status = 1;
+			status = 1 << USB_ENDPOINT_HALT;
 		else
 			status = 0;
 		break;
@@ -934,11 +944,13 @@
 		return;		/* exit */
 	}
 
-	*m66592->ep0_buf = status;
-	m66592->ep0_req->buf = m66592->ep0_buf;
+	m66592->ep0_data = cpu_to_le16(status);
+	m66592->ep0_req->buf = &m66592->ep0_data;
 	m66592->ep0_req->length = 2;
 	/* AV: what happens if we get called again before that gets through? */
+	spin_unlock(&m66592->lock);
 	m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+	spin_lock(&m66592->lock);
 }
 
 static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@
 	case USB_RECIP_ENDPOINT: {
 		struct m66592_ep *ep;
 		struct m66592_request *req;
+		u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pipe_stop(m66592, ep->pipenum);
 		control_reg_sqclr(m66592, ep->pipenum);
 
@@ -989,8 +1002,9 @@
 		break;
 	case USB_RECIP_ENDPOINT: {
 		struct m66592_ep *ep;
+		u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pipe_stall(m66592, ep->pipenum);
 
 		control_end(m66592, 1);
@@ -1066,14 +1080,16 @@
 	}
 	if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
 		m66592_update_usb_speed(m66592);
-	if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
-	    m66592->gadget.speed == USB_SPEED_UNKNOWN)
+	if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+			&& m66592->gadget.speed == USB_SPEED_UNKNOWN)
 		m66592_update_usb_speed(m66592);
 
 	m66592->old_dvsq = dvsq;
 }
 
 static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	struct usb_ctrlrequest ctrl;
 	u16 ctsq;
@@ -1095,8 +1111,10 @@
 	case M66592_CS_WRDS:
 	case M66592_CS_WRND:
 		if (setup_packet(m66592, &ctrl)) {
+			spin_unlock(&m66592->lock);
 			if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
 				pipe_stall(m66592, 0);
+			spin_lock(&m66592->lock);
 		}
 		break;
 	case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@
 	u16 savepipe;
 	u16 mask0;
 
+	spin_lock(&m66592->lock);
+
 	intsts0 = m66592_read(m66592, M66592_INTSTS0);
 	intenb0 = m66592_read(m66592, M66592_INTENB0);
 
@@ -1134,27 +1154,27 @@
 		bempenb = m66592_read(m66592, M66592_BEMPENB);
 
 		if (mask0 & M66592_VBINT) {
-			m66592_write(m66592, (u16)~M66592_VBINT,
-				     M66592_INTSTS0);
+			m66592_write(m66592,  0xffff & ~M66592_VBINT,
+					M66592_INTSTS0);
 			m66592_start_xclock(m66592);
 
 			/* start vbus sampling */
 			m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
-					   & M66592_VBSTS;
+					& M66592_VBSTS;
 			m66592->scount = M66592_MAX_SAMPLING;
 
 			mod_timer(&m66592->timer,
-				  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 		}
 		if (intsts0 & M66592_DVSQ)
 			irq_device_state(m66592);
 
-		if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
-		    (brdysts & brdyenb)) {
+		if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+				&& (brdysts & brdyenb)) {
 			irq_pipe_ready(m66592, brdysts, brdyenb);
 		}
-		if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
-		    (bempsts & bempenb)) {
+		if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+				&& (bempsts & bempenb)) {
 			irq_pipe_empty(m66592, bempsts, bempenb);
 		}
 
@@ -1164,6 +1184,7 @@
 
 	m66592_write(m66592, savepipe, M66592_CFIFOSEL);
 
+	spin_unlock(&m66592->lock);
 	return IRQ_HANDLED;
 }
 
@@ -1191,13 +1212,13 @@
 					m66592_usb_disconnect(m66592);
 			} else {
 				mod_timer(&m66592->timer,
-					  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 			}
 		} else {
 			m66592->scount = M66592_MAX_SAMPLING;
 			m66592->old_vbus = tmp;
 			mod_timer(&m66592->timer,
-				  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 		}
 	}
 	spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1335,11 +1356,6 @@
 	return ret;
 }
 
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
-	return -EOPNOTSUPP;
-}
-
 static void m66592_fifo_flush(struct usb_ep *_ep)
 {
 	struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@
 	.dequeue	= m66592_dequeue,
 
 	.set_halt	= m66592_set_halt,
-	.fifo_status	= m66592_fifo_status,
 	.fifo_flush	= m66592_fifo_flush,
 };
 
@@ -1377,11 +1392,10 @@
 	struct m66592 *m66592 = the_controller;
 	int retval;
 
-	if (!driver ||
-	    driver->speed != USB_SPEED_HIGH ||
-	    !driver->bind ||
-	    !driver->unbind ||
-	    !driver->setup)
+	if (!driver
+			|| driver->speed != USB_SPEED_HIGH
+			|| !driver->bind
+			|| !driver->setup)
 		return -EINVAL;
 	if (!m66592)
 		return -ENODEV;
@@ -1413,8 +1427,7 @@
 		m66592->old_vbus = m66592_read(m66592,
 					 M66592_INTSTS0) & M66592_VBSTS;
 		m66592->scount = M66592_MAX_SAMPLING;
-		mod_timer(&m66592->timer,
-			  jiffies + msecs_to_jiffies(50));
+		mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
 	}
 
 	return 0;
@@ -1432,6 +1445,9 @@
 	struct m66592 *m66592 = the_controller;
 	unsigned long flags;
 
+	if (driver != m66592->driver || !driver->unbind)
+		return -EINVAL;
+
 	spin_lock_irqsave(&m66592->lock, flags);
 	if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
 		m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@
 	.get_frame		= m66592_get_frame,
 };
 
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	pdev->dev.power.power_state = state;
-	return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
-	pdev->dev.power.power_state = PMSG_ON;
-	return 0;
-}
-#else	/* if defined(CONFIG_PM) */
-#define m66592_suspend		NULL
-#define m66592_resume		NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
 {
 	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
 
 	del_timer_sync(&m66592->timer);
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
+	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 	kfree(m66592);
 	return 0;
 }
 
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
 #define resource_len(r) (((r)->end - (r)->start) + 1)
+
 static int __init m66592_probe(struct platform_device *pdev)
 {
-	struct resource *res = NULL;
-	int irq = -1;
+	struct resource *res;
+	int irq;
 	void __iomem *reg = NULL;
 	struct m66592 *m66592 = NULL;
 	int ret = 0;
 	int i;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-					   (char *)udc_name);
+			(char *)udc_name);
 	if (!res) {
 		ret = -ENODEV;
 		printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@
 	m66592->bi_bufnum = M66592_BASE_BUFNUM;
 
 	ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
-			  udc_name, m66592);
+			udc_name, m66592);
 	if (ret < 0) {
 		printk(KERN_ERR "request_irq error (%d)\n", ret);
 		goto clean_up;
@@ -1563,7 +1568,7 @@
 		if (i != 0) {
 			INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
 			list_add_tail(&m66592->ep[i].ep.ep_list,
-				      &m66592->gadget.ep_list);
+					&m66592->gadget.ep_list);
 		}
 		ep->m66592 = m66592;
 		INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@
 
 	the_controller = m66592;
 
-	/* AV: leaks */
 	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
 	if (m66592->ep0_req == NULL)
-		goto clean_up;
-	/* AV: leaks, and do we really need it separately allocated? */
-	m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
-	if (m66592->ep0_buf == NULL)
-		goto clean_up;
+		goto clean_up2;
+	m66592->ep0_req->complete = nop_completion;
 
 	init_controller(m66592);
 
-	printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 
+clean_up2:
+	free_irq(irq, m66592);
 clean_up:
 	if (m66592) {
 		if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver m66592_driver = {
-	.probe =	m66592_probe,
-	.remove =	m66592_remove,
-	.suspend =	m66592_suspend,
-	.resume =	m66592_resume,
+	.remove =	__exit_p(m66592_remove),
 	.driver		= {
 		.name =	(char *) udc_name,
 	},
@@ -1622,7 +1622,7 @@
 
 static int __init m66592_udc_init(void)
 {
-	return platform_driver_register(&m66592_driver);
+	return platform_driver_probe(&m66592_driver, m66592_probe);
 }
 module_init(m66592_udc_init);
 
@@ -1631,4 +1631,3 @@
 	platform_driver_unregister(&m66592_driver);
 }
 module_exit(m66592_udc_cleanup);
-
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 26b54f8..bfa0c64 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -24,73 +24,73 @@
 #define __M66592_UDC_H__
 
 #define M66592_SYSCFG		0x00
-#define	M66592_XTAL		0xC000	/* b15-14: Crystal selection */
-#define	  M66592_XTAL48		 0x8000		  /* 48MHz */
-#define   M66592_XTAL24		 0x4000		  /* 24MHz */
-#define	  M66592_XTAL12		 0x0000		  /* 12MHz */
-#define	M66592_XCKE		0x2000	/* b13: External clock enable */
-#define	M66592_RCKE		0x1000	/* b12: Register clock enable */
-#define	M66592_PLLC		0x0800	/* b11: PLL control */
-#define	M66592_SCKE		0x0400	/* b10: USB clock enable */
-#define	M66592_ATCKM		0x0100	/* b8: Automatic supply functional enable */
-#define	M66592_HSE		0x0080	/* b7: Hi-speed enable */
-#define	M66592_DCFM		0x0040	/* b6: Controller function select  */
-#define	M66592_DMRPD		0x0020	/* b5: D- pull down control */
-#define	M66592_DPRPU		0x0010	/* b4: D+ pull up control */
-#define	M66592_FSRPC		0x0004	/* b2: Full-speed receiver enable */
-#define	M66592_PCUT		0x0002	/* b1: Low power sleep enable */
-#define	M66592_USBE		0x0001	/* b0: USB module operation enable */
+#define M66592_XTAL		0xC000	/* b15-14: Crystal selection */
+#define   M66592_XTAL48		 0x8000		/* 48MHz */
+#define   M66592_XTAL24		 0x4000		/* 24MHz */
+#define   M66592_XTAL12		 0x0000		/* 12MHz */
+#define M66592_XCKE		0x2000	/* b13: External clock enable */
+#define M66592_RCKE		0x1000	/* b12: Register clock enable */
+#define M66592_PLLC		0x0800	/* b11: PLL control */
+#define M66592_SCKE		0x0400	/* b10: USB clock enable */
+#define M66592_ATCKM		0x0100	/* b8: Automatic clock supply */
+#define M66592_HSE		0x0080	/* b7: Hi-speed enable */
+#define M66592_DCFM		0x0040	/* b6: Controller function select  */
+#define M66592_DMRPD		0x0020	/* b5: D- pull down control */
+#define M66592_DPRPU		0x0010	/* b4: D+ pull up control */
+#define M66592_FSRPC		0x0004	/* b2: Full-speed receiver enable */
+#define M66592_PCUT		0x0002	/* b1: Low power sleep enable */
+#define M66592_USBE		0x0001	/* b0: USB module operation enable */
 
 #define M66592_SYSSTS		0x02
-#define	M66592_LNST		0x0003	/* b1-0: D+, D- line status */
-#define	  M66592_SE1		 0x0003		  /* SE1 */
-#define	  M66592_KSTS		 0x0002		  /* K State */
-#define	  M66592_JSTS		 0x0001		  /* J State */
-#define	  M66592_SE0		 0x0000		  /* SE0 */
+#define M66592_LNST		0x0003	/* b1-0: D+, D- line status */
+#define   M66592_SE1		 0x0003		/* SE1 */
+#define   M66592_KSTS		 0x0002		/* K State */
+#define   M66592_JSTS		 0x0001		/* J State */
+#define   M66592_SE0		 0x0000		/* SE0 */
 
 #define M66592_DVSTCTR		0x04
-#define	M66592_WKUP		0x0100	/* b8: Remote wakeup */
-#define	M66592_RWUPE		0x0080	/* b7: Remote wakeup sense */
-#define	M66592_USBRST		0x0040	/* b6: USB reset enable */
-#define	M66592_RESUME		0x0020	/* b5: Resume enable */
-#define	M66592_UACT		0x0010	/* b4: USB bus enable */
-#define	M66592_RHST		0x0003	/* b1-0: Reset handshake status */
-#define	  M66592_HSMODE		 0x0003		  /* Hi-Speed mode */
-#define	  M66592_FSMODE		 0x0002		  /* Full-Speed mode */
-#define	  M66592_HSPROC		 0x0001		  /* HS handshake is processing */
+#define M66592_WKUP		0x0100	/* b8: Remote wakeup */
+#define M66592_RWUPE		0x0080	/* b7: Remote wakeup sense */
+#define M66592_USBRST		0x0040	/* b6: USB reset enable */
+#define M66592_RESUME		0x0020	/* b5: Resume enable */
+#define M66592_UACT		0x0010	/* b4: USB bus enable */
+#define M66592_RHST		0x0003	/* b1-0: Reset handshake status */
+#define   M66592_HSMODE		 0x0003		/* Hi-Speed mode */
+#define   M66592_FSMODE		 0x0002		/* Full-Speed mode */
+#define   M66592_HSPROC		 0x0001		/* HS handshake is processing */
 
 #define M66592_TESTMODE		0x06
-#define	M66592_UTST		0x000F	/* b4-0: Test select */
-#define	  M66592_H_TST_PACKET	 0x000C		  /* HOST TEST Packet */
-#define	  M66592_H_TST_SE0_NAK	 0x000B		  /* HOST TEST SE0 NAK */
-#define	  M66592_H_TST_K	 0x000A		  /* HOST TEST K */
-#define	  M66592_H_TST_J	 0x0009		  /* HOST TEST J */
-#define	  M66592_H_TST_NORMAL	 0x0000		  /* HOST Normal Mode */
-#define	  M66592_P_TST_PACKET	 0x0004		  /* PERI TEST Packet */
-#define	  M66592_P_TST_SE0_NAK	 0x0003		  /* PERI TEST SE0 NAK */
-#define	  M66592_P_TST_K	 0x0002		  /* PERI TEST K */
-#define	  M66592_P_TST_J	 0x0001		  /* PERI TEST J */
-#define	  M66592_P_TST_NORMAL	 0x0000		  /* PERI Normal Mode */
+#define M66592_UTST		0x000F	/* b4-0: Test select */
+#define   M66592_H_TST_PACKET	 0x000C		/* HOST TEST Packet */
+#define   M66592_H_TST_SE0_NAK	 0x000B		/* HOST TEST SE0 NAK */
+#define   M66592_H_TST_K	 0x000A		/* HOST TEST K */
+#define   M66592_H_TST_J	 0x0009		/* HOST TEST J */
+#define   M66592_H_TST_NORMAL	 0x0000		/* HOST Normal Mode */
+#define   M66592_P_TST_PACKET	 0x0004		/* PERI TEST Packet */
+#define   M66592_P_TST_SE0_NAK	 0x0003		/* PERI TEST SE0 NAK */
+#define   M66592_P_TST_K	 0x0002		/* PERI TEST K */
+#define   M66592_P_TST_J	 0x0001		/* PERI TEST J */
+#define   M66592_P_TST_NORMAL	 0x0000		/* PERI Normal Mode */
 
 #define M66592_PINCFG		0x0A
-#define	M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
-#define	M66592_BIGEND		0x0100	/* b8: Big endian mode */
+#define M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
+#define M66592_BIGEND		0x0100	/* b8: Big endian mode */
 
 #define M66592_DMA0CFG		0x0C
 #define M66592_DMA1CFG		0x0E
-#define	M66592_DREQA		0x4000	/* b14: Dreq active select */
-#define	M66592_BURST		0x2000	/* b13: Burst mode */
-#define	M66592_DACKA		0x0400	/* b10: Dack active select */
-#define	M66592_DFORM		0x0380	/* b9-7: DMA mode select */
-#define	  M66592_CPU_ADR_RD_WR	 0x0000		  /* Address + RD/WR mode (CPU bus) */
-#define	  M66592_CPU_DACK_RD_WR	 0x0100		  /* DACK + RD/WR mode (CPU bus) */
-#define	  M66592_CPU_DACK_ONLY	 0x0180		  /* DACK only mode (CPU bus) */
-#define	  M66592_SPLIT_DACK_ONLY	 0x0200		  /* DACK only mode (SPLIT bus) */
-#define	  M66592_SPLIT_DACK_DSTB	 0x0300		  /* DACK + DSTB0 mode (SPLIT bus) */
-#define	M66592_DENDA		0x0040	/* b6: Dend active select */
-#define	M66592_PKTM		0x0020	/* b5: Packet mode */
-#define	M66592_DENDE		0x0010	/* b4: Dend enable */
-#define	M66592_OBUS		0x0004	/* b2: OUTbus mode */
+#define M66592_DREQA		0x4000	/* b14: Dreq active select */
+#define M66592_BURST		0x2000	/* b13: Burst mode */
+#define M66592_DACKA		0x0400	/* b10: Dack active select */
+#define M66592_DFORM		0x0380	/* b9-7: DMA mode select */
+#define   M66592_CPU_ADR_RD_WR	 0x0000   /* Address + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_RD_WR	 0x0100   /* DACK + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_ONLY	 0x0180   /* DACK only mode (CPU bus) */
+#define   M66592_SPLIT_DACK_ONLY 0x0200   /* DACK only mode (SPLIT bus) */
+#define   M66592_SPLIT_DACK_DSTB 0x0300   /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA		0x0040	/* b6: Dend active select */
+#define M66592_PKTM		0x0020	/* b5: Packet mode */
+#define M66592_DENDE		0x0010	/* b4: Dend enable */
+#define M66592_OBUS		0x0004	/* b2: OUTbus mode */
 
 #define M66592_CFIFO		0x10
 #define M66592_D0FIFO		0x14
@@ -99,300 +99,300 @@
 #define M66592_CFIFOSEL		0x1E
 #define M66592_D0FIFOSEL	0x24
 #define M66592_D1FIFOSEL	0x2A
-#define	M66592_RCNT		0x8000	/* b15: Read count mode */
-#define	M66592_REW		0x4000	/* b14: Buffer rewind */
-#define	M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
-#define	M66592_DREQE		0x1000	/* b12: DREQ output enable */
-#define	M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO access */
-#define	  M66592_MBW_8		 0x0000	  /*  8bit */
-#define	  M66592_MBW_16		 0x0400		  /* 16bit */
-#define	M66592_TRENB		0x0200	/* b9: Transaction counter enable */
-#define	M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
-#define	M66592_DEZPM		0x0080	/* b7: Zero-length packet additional mode */
-#define	M66592_ISEL		0x0020	/* b5: DCP FIFO port direction select */
-#define	M66592_CURPIPE		0x0007	/* b2-0: PIPE select */
+#define M66592_RCNT		0x8000	/* b15: Read count mode */
+#define M66592_REW		0x4000	/* b14: Buffer rewind */
+#define M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
+#define M66592_DREQE		0x1000	/* b12: DREQ output enable */
+#define M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO */
+#define   M66592_MBW_8		 0x0000   /*  8bit */
+#define   M66592_MBW_16		 0x0400   /* 16bit */
+#define M66592_TRENB		0x0200	/* b9: Transaction counter enable */
+#define M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
+#define M66592_DEZPM		0x0080	/* b7: Zero-length packet mode */
+#define M66592_ISEL		0x0020	/* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE		0x0007	/* b2-0: PIPE select */
 
 #define M66592_CFIFOCTR		0x20
 #define M66592_D0FIFOCTR	0x26
 #define M66592_D1FIFOCTR	0x2c
-#define	M66592_BVAL		0x8000	/* b15: Buffer valid flag */
-#define	M66592_BCLR		0x4000	/* b14: Buffer clear */
-#define	M66592_FRDY		0x2000	/* b13: FIFO ready */
-#define	M66592_DTLN		0x0FFF	/* b11-0: FIFO received data length */
+#define M66592_BVAL		0x8000	/* b15: Buffer valid flag */
+#define M66592_BCLR		0x4000	/* b14: Buffer clear */
+#define M66592_FRDY		0x2000	/* b13: FIFO ready */
+#define M66592_DTLN		0x0FFF	/* b11-0: FIFO received data length */
 
 #define M66592_CFIFOSIE		0x22
-#define	M66592_TGL		0x8000	/* b15: Buffer toggle */
-#define	M66592_SCLR		0x4000	/* b14: Buffer clear */
-#define	M66592_SBUSY		0x2000	/* b13: SIE_FIFO busy */
+#define M66592_TGL		0x8000	/* b15: Buffer toggle */
+#define M66592_SCLR		0x4000	/* b14: Buffer clear */
+#define M66592_SBUSY		0x2000	/* b13: SIE_FIFO busy */
 
 #define M66592_D0FIFOTRN	0x28
 #define M66592_D1FIFOTRN	0x2E
-#define	M66592_TRNCNT		0xFFFF	/* b15-0: Transaction counter */
+#define M66592_TRNCNT		0xFFFF	/* b15-0: Transaction counter */
 
 #define M66592_INTENB0	0x30
-#define	M66592_VBSE	0x8000	/* b15: VBUS interrupt */
-#define	M66592_RSME	0x4000	/* b14: Resume interrupt */
-#define	M66592_SOFE	0x2000	/* b13: Frame update interrupt */
-#define	M66592_DVSE	0x1000	/* b12: Device state transition interrupt */
-#define	M66592_CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
-#define	M66592_BEMPE	0x0400	/* b10: Buffer empty interrupt */
-#define	M66592_NRDYE	0x0200	/* b9: Buffer not ready interrupt */
-#define	M66592_BRDYE	0x0100	/* b8: Buffer ready interrupt */
-#define	M66592_URST	0x0080	/* b7: USB reset detected interrupt */
-#define	M66592_SADR	0x0040	/* b6: Set address executed interrupt */
-#define	M66592_SCFG	0x0020	/* b5: Set configuration executed interrupt */
-#define	M66592_SUSP	0x0010	/* b4: Suspend detected interrupt */
-#define	M66592_WDST	0x0008	/* b3: Control write data stage completed interrupt */
-#define	M66592_RDST	0x0004	/* b2: Control read data stage completed interrupt */
-#define	M66592_CMPL	0x0002	/* b1: Control transfer complete interrupt */
-#define	M66592_SERR	0x0001	/* b0: Sequence error interrupt */
+#define M66592_VBSE	0x8000	/* b15: VBUS interrupt */
+#define M66592_RSME	0x4000	/* b14: Resume interrupt */
+#define M66592_SOFE	0x2000	/* b13: Frame update interrupt */
+#define M66592_DVSE	0x1000	/* b12: Device state transition interrupt */
+#define M66592_CTRE	0x0800	/* b11: Control transfer stage transition irq */
+#define M66592_BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define M66592_NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define M66592_BRDYE	0x0100	/* b8: Buffer ready interrupt */
+#define M66592_URST	0x0080	/* b7: USB reset detected interrupt */
+#define M66592_SADR	0x0040	/* b6: Set address executed interrupt */
+#define M66592_SCFG	0x0020	/* b5: Set configuration executed interrupt */
+#define M66592_SUSP	0x0010	/* b4: Suspend detected interrupt */
+#define M66592_WDST	0x0008	/* b3: Control write data stage completed irq */
+#define M66592_RDST	0x0004	/* b2: Control read data stage completed irq */
+#define M66592_CMPL	0x0002	/* b1: Control transfer complete interrupt */
+#define M66592_SERR	0x0001	/* b0: Sequence error interrupt */
 
 #define M66592_INTENB1	0x32
-#define	M66592_BCHGE	0x4000	/* b14: USB us chenge interrupt */
-#define	M66592_DTCHE	0x1000	/* b12: Detach sense interrupt */
-#define	M66592_SIGNE	0x0020	/* b5: SETUP IGNORE interrupt */
-#define	M66592_SACKE	0x0010	/* b4: SETUP ACK interrupt */
-#define	M66592_BRDYM	0x0004	/* b2: BRDY clear timing */
-#define	M66592_INTL	0x0002	/* b1: Interrupt sense select */
-#define	M66592_PCSE	0x0001	/* b0: PCUT enable by CS assert */
+#define M66592_BCHGE	0x4000	/* b14: USB us chenge interrupt */
+#define M66592_DTCHE	0x1000	/* b12: Detach sense interrupt */
+#define M66592_SIGNE	0x0020	/* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE	0x0010	/* b4: SETUP ACK interrupt */
+#define M66592_BRDYM	0x0004	/* b2: BRDY clear timing */
+#define M66592_INTL	0x0002	/* b1: Interrupt sense select */
+#define M66592_PCSE	0x0001	/* b0: PCUT enable by CS assert */
 
 #define M66592_BRDYENB		0x36
 #define M66592_BRDYSTS		0x46
-#define	M66592_BRDY7		0x0080	/* b7: PIPE7 */
-#define	M66592_BRDY6		0x0040	/* b6: PIPE6 */
-#define	M66592_BRDY5		0x0020	/* b5: PIPE5 */
-#define	M66592_BRDY4		0x0010	/* b4: PIPE4 */
-#define	M66592_BRDY3		0x0008	/* b3: PIPE3 */
-#define	M66592_BRDY2		0x0004	/* b2: PIPE2 */
-#define	M66592_BRDY1		0x0002	/* b1: PIPE1 */
-#define	M66592_BRDY0		0x0001	/* b1: PIPE0 */
+#define M66592_BRDY7		0x0080	/* b7: PIPE7 */
+#define M66592_BRDY6		0x0040	/* b6: PIPE6 */
+#define M66592_BRDY5		0x0020	/* b5: PIPE5 */
+#define M66592_BRDY4		0x0010	/* b4: PIPE4 */
+#define M66592_BRDY3		0x0008	/* b3: PIPE3 */
+#define M66592_BRDY2		0x0004	/* b2: PIPE2 */
+#define M66592_BRDY1		0x0002	/* b1: PIPE1 */
+#define M66592_BRDY0		0x0001	/* b1: PIPE0 */
 
 #define M66592_NRDYENB		0x38
 #define M66592_NRDYSTS		0x48
-#define	M66592_NRDY7		0x0080	/* b7: PIPE7 */
-#define	M66592_NRDY6		0x0040	/* b6: PIPE6 */
-#define	M66592_NRDY5		0x0020	/* b5: PIPE5 */
-#define	M66592_NRDY4		0x0010	/* b4: PIPE4 */
-#define	M66592_NRDY3		0x0008	/* b3: PIPE3 */
-#define	M66592_NRDY2		0x0004	/* b2: PIPE2 */
-#define	M66592_NRDY1		0x0002	/* b1: PIPE1 */
-#define	M66592_NRDY0		0x0001	/* b1: PIPE0 */
+#define M66592_NRDY7		0x0080	/* b7: PIPE7 */
+#define M66592_NRDY6		0x0040	/* b6: PIPE6 */
+#define M66592_NRDY5		0x0020	/* b5: PIPE5 */
+#define M66592_NRDY4		0x0010	/* b4: PIPE4 */
+#define M66592_NRDY3		0x0008	/* b3: PIPE3 */
+#define M66592_NRDY2		0x0004	/* b2: PIPE2 */
+#define M66592_NRDY1		0x0002	/* b1: PIPE1 */
+#define M66592_NRDY0		0x0001	/* b1: PIPE0 */
 
 #define M66592_BEMPENB		0x3A
 #define M66592_BEMPSTS		0x4A
-#define	M66592_BEMP7		0x0080	/* b7: PIPE7 */
-#define	M66592_BEMP6		0x0040	/* b6: PIPE6 */
-#define	M66592_BEMP5		0x0020	/* b5: PIPE5 */
-#define	M66592_BEMP4		0x0010	/* b4: PIPE4 */
-#define	M66592_BEMP3		0x0008	/* b3: PIPE3 */
-#define	M66592_BEMP2		0x0004	/* b2: PIPE2 */
-#define	M66592_BEMP1		0x0002	/* b1: PIPE1 */
-#define	M66592_BEMP0		0x0001	/* b0: PIPE0 */
+#define M66592_BEMP7		0x0080	/* b7: PIPE7 */
+#define M66592_BEMP6		0x0040	/* b6: PIPE6 */
+#define M66592_BEMP5		0x0020	/* b5: PIPE5 */
+#define M66592_BEMP4		0x0010	/* b4: PIPE4 */
+#define M66592_BEMP3		0x0008	/* b3: PIPE3 */
+#define M66592_BEMP2		0x0004	/* b2: PIPE2 */
+#define M66592_BEMP1		0x0002	/* b1: PIPE1 */
+#define M66592_BEMP0		0x0001	/* b0: PIPE0 */
 
 #define M66592_SOFCFG		0x3C
-#define	M66592_SOFM		0x000C	/* b3-2: SOF palse mode */
-#define	  M66592_SOF_125US	 0x0008		  /* SOF OUT 125us uFrame Signal */
-#define	  M66592_SOF_1MS	 0x0004		  /* SOF OUT 1ms Frame Signal */
-#define	  M66592_SOF_DISABLE	 0x0000		  /* SOF OUT Disable */
+#define M66592_SOFM		0x000C	/* b3-2: SOF palse mode */
+#define   M66592_SOF_125US	 0x0008   /* SOF OUT 125us uFrame Signal */
+#define   M66592_SOF_1MS	 0x0004   /* SOF OUT 1ms Frame Signal */
+#define   M66592_SOF_DISABLE	 0x0000   /* SOF OUT Disable */
 
 #define M66592_INTSTS0		0x40
-#define	M66592_VBINT		0x8000	/* b15: VBUS interrupt */
-#define	M66592_RESM		0x4000	/* b14: Resume interrupt */
-#define	M66592_SOFR		0x2000	/* b13: SOF frame update interrupt */
-#define	M66592_DVST		0x1000	/* b12: Device state transition interrupt */
-#define	M66592_CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	M66592_BEMP		0x0400	/* b10: Buffer empty interrupt */
-#define	M66592_NRDY		0x0200	/* b9: Buffer not ready interrupt */
-#define	M66592_BRDY		0x0100	/* b8: Buffer ready interrupt */
-#define	M66592_VBSTS		0x0080	/* b7: VBUS input port */
-#define	M66592_DVSQ		0x0070	/* b6-4: Device state */
-#define	  M66592_DS_SPD_CNFG	 0x0070		  /* Suspend Configured */
-#define	  M66592_DS_SPD_ADDR	 0x0060		  /* Suspend Address */
-#define	  M66592_DS_SPD_DFLT	 0x0050		  /* Suspend Default */
-#define	  M66592_DS_SPD_POWR	 0x0040		  /* Suspend Powered */
-#define	  M66592_DS_SUSP	 0x0040		  /* Suspend */
-#define	  M66592_DS_CNFG	 0x0030		  /* Configured */
-#define	  M66592_DS_ADDS	 0x0020		  /* Address */
-#define	  M66592_DS_DFLT	 0x0010		  /* Default */
-#define	  M66592_DS_POWR	 0x0000		  /* Powered */
-#define	M66592_DVSQS		0x0030	/* b5-4: Device state */
-#define	M66592_VALID		0x0008	/* b3: Setup packet detected flag */
-#define	M66592_CTSQ		0x0007	/* b2-0: Control transfer stage */
-#define	  M66592_CS_SQER	 0x0006		  /* Sequence error */
-#define	  M66592_CS_WRND	 0x0005		  /* Control write nodata status stage */
-#define	  M66592_CS_WRSS	 0x0004		  /* Control write status stage */
-#define	  M66592_CS_WRDS	 0x0003		  /* Control write data stage */
-#define	  M66592_CS_RDSS	 0x0002		  /* Control read status stage */
-#define	  M66592_CS_RDDS	 0x0001		  /* Control read data stage */
-#define	  M66592_CS_IDST	 0x0000		  /* Idle or setup stage */
+#define M66592_VBINT		0x8000	/* b15: VBUS interrupt */
+#define M66592_RESM		0x4000	/* b14: Resume interrupt */
+#define M66592_SOFR		0x2000	/* b13: SOF frame update interrupt */
+#define M66592_DVST		0x1000	/* b12: Device state transition */
+#define M66592_CTRT		0x0800	/* b11: Control stage transition */
+#define M66592_BEMP		0x0400	/* b10: Buffer empty interrupt */
+#define M66592_NRDY		0x0200	/* b9: Buffer not ready interrupt */
+#define M66592_BRDY		0x0100	/* b8: Buffer ready interrupt */
+#define M66592_VBSTS		0x0080	/* b7: VBUS input port */
+#define M66592_DVSQ		0x0070	/* b6-4: Device state */
+#define   M66592_DS_SPD_CNFG	 0x0070	   /* Suspend Configured */
+#define   M66592_DS_SPD_ADDR	 0x0060	   /* Suspend Address */
+#define   M66592_DS_SPD_DFLT	 0x0050	   /* Suspend Default */
+#define   M66592_DS_SPD_POWR	 0x0040	   /* Suspend Powered */
+#define   M66592_DS_SUSP	 0x0040	   /* Suspend */
+#define   M66592_DS_CNFG	 0x0030	   /* Configured */
+#define   M66592_DS_ADDS	 0x0020	   /* Address */
+#define   M66592_DS_DFLT	 0x0010	   /* Default */
+#define   M66592_DS_POWR	 0x0000	   /* Powered */
+#define M66592_DVSQS		0x0030	/* b5-4: Device state */
+#define M66592_VALID		0x0008	/* b3: Setup packet detected flag */
+#define M66592_CTSQ		0x0007	/* b2-0: Control transfer stage */
+#define   M66592_CS_SQER	 0x0006	  /* Sequence error */
+#define   M66592_CS_WRND	 0x0005	  /* Control write nodata status */
+#define   M66592_CS_WRSS	 0x0004	  /* Control write status stage */
+#define   M66592_CS_WRDS	 0x0003	  /* Control write data stage */
+#define   M66592_CS_RDSS	 0x0002	  /* Control read status stage */
+#define   M66592_CS_RDDS	 0x0001	  /* Control read data stage */
+#define   M66592_CS_IDST	 0x0000	  /* Idle or setup stage */
 
 #define M66592_INTSTS1		0x42
-#define	M66592_BCHG		0x4000	/* b14: USB bus chenge interrupt */
-#define	M66592_DTCH		0x1000	/* b12: Detach sense interrupt */
-#define	M66592_SIGN		0x0020	/* b5: SETUP IGNORE interrupt */
-#define	M66592_SACK		0x0010	/* b4: SETUP ACK interrupt */
+#define M66592_BCHG		0x4000	/* b14: USB bus chenge interrupt */
+#define M66592_DTCH		0x1000	/* b12: Detach sense interrupt */
+#define M66592_SIGN		0x0020	/* b5: SETUP IGNORE interrupt */
+#define M66592_SACK		0x0010	/* b4: SETUP ACK interrupt */
 
 #define M66592_FRMNUM		0x4C
-#define	M66592_OVRN		0x8000	/* b15: Overrun error */
-#define	M66592_CRCE		0x4000	/* b14: Received data error */
-#define	M66592_SOFRM		0x0800	/* b11: SOF output mode */
-#define	M66592_FRNM		0x07FF	/* b10-0: Frame number */
+#define M66592_OVRN		0x8000	/* b15: Overrun error */
+#define M66592_CRCE		0x4000	/* b14: Received data error */
+#define M66592_SOFRM		0x0800	/* b11: SOF output mode */
+#define M66592_FRNM		0x07FF	/* b10-0: Frame number */
 
 #define M66592_UFRMNUM		0x4E
-#define	M66592_UFRNM		0x0007	/* b2-0: Micro frame number */
+#define M66592_UFRNM		0x0007	/* b2-0: Micro frame number */
 
 #define M66592_RECOVER		0x50
-#define	M66592_STSRECOV		0x0700	/* Status recovery */
-#define	  M66592_STSR_HI	 0x0400		  /* FULL(0) or HI(1) Speed */
-#define	  M66592_STSR_DEFAULT	 0x0100		  /* Default state */
-#define	  M66592_STSR_ADDRESS	 0x0200		  /* Address state */
-#define	  M66592_STSR_CONFIG	 0x0300		  /* Configured state */
-#define	M66592_USBADDR		0x007F	/* b6-0: USB address */
+#define M66592_STSRECOV		0x0700	/* Status recovery */
+#define   M66592_STSR_HI	 0x0400		  /* FULL(0) or HI(1) Speed */
+#define   M66592_STSR_DEFAULT	 0x0100		  /* Default state */
+#define   M66592_STSR_ADDRESS	 0x0200		  /* Address state */
+#define   M66592_STSR_CONFIG	 0x0300		  /* Configured state */
+#define M66592_USBADDR		0x007F	/* b6-0: USB address */
 
 #define M66592_USBREQ			0x54
-#define	M66592_bRequest			0xFF00	/* b15-8: bRequest */
-#define	  M66592_GET_STATUS		 0x0000
-#define	  M66592_CLEAR_FEATURE		 0x0100
-#define	  M66592_ReqRESERVED		 0x0200
-#define	  M66592_SET_FEATURE		 0x0300
-#define	  M66592_ReqRESERVED1		 0x0400
-#define	  M66592_SET_ADDRESS		 0x0500
-#define	  M66592_GET_DESCRIPTOR		 0x0600
-#define	  M66592_SET_DESCRIPTOR		 0x0700
-#define	  M66592_GET_CONFIGURATION	 0x0800
-#define	  M66592_SET_CONFIGURATION	 0x0900
-#define	  M66592_GET_INTERFACE		 0x0A00
-#define	  M66592_SET_INTERFACE		 0x0B00
-#define	  M66592_SYNCH_FRAME		 0x0C00
-#define	M66592_bmRequestType		0x00FF	/* b7-0: bmRequestType */
-#define	M66592_bmRequestTypeDir		0x0080	/* b7  : Data transfer direction */
-#define	  M66592_HOST_TO_DEVICE		 0x0000
-#define	  M66592_DEVICE_TO_HOST		 0x0080
-#define	M66592_bmRequestTypeType	0x0060	/* b6-5: Type */
-#define	  M66592_STANDARD		 0x0000
-#define	  M66592_CLASS			 0x0020
-#define	  M66592_VENDOR			 0x0040
-#define	M66592_bmRequestTypeRecip	0x001F	/* b4-0: Recipient */
-#define	  M66592_DEVICE			 0x0000
-#define	  M66592_INTERFACE		 0x0001
-#define	  M66592_ENDPOINT		 0x0002
+#define M66592_bRequest			0xFF00	/* b15-8: bRequest */
+#define   M66592_GET_STATUS		 0x0000
+#define   M66592_CLEAR_FEATURE		 0x0100
+#define   M66592_ReqRESERVED		 0x0200
+#define   M66592_SET_FEATURE		 0x0300
+#define   M66592_ReqRESERVED1		 0x0400
+#define   M66592_SET_ADDRESS		 0x0500
+#define   M66592_GET_DESCRIPTOR		 0x0600
+#define   M66592_SET_DESCRIPTOR		 0x0700
+#define   M66592_GET_CONFIGURATION	 0x0800
+#define   M66592_SET_CONFIGURATION	 0x0900
+#define   M66592_GET_INTERFACE		 0x0A00
+#define   M66592_SET_INTERFACE		 0x0B00
+#define   M66592_SYNCH_FRAME		 0x0C00
+#define M66592_bmRequestType		0x00FF	/* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir		0x0080	/* b7  : Data direction */
+#define   M66592_HOST_TO_DEVICE		 0x0000
+#define   M66592_DEVICE_TO_HOST		 0x0080
+#define M66592_bmRequestTypeType	0x0060	/* b6-5: Type */
+#define   M66592_STANDARD		 0x0000
+#define   M66592_CLASS			 0x0020
+#define   M66592_VENDOR			 0x0040
+#define M66592_bmRequestTypeRecip	0x001F	/* b4-0: Recipient */
+#define   M66592_DEVICE			 0x0000
+#define   M66592_INTERFACE		 0x0001
+#define   M66592_ENDPOINT		 0x0002
 
 #define M66592_USBVAL				0x56
-#define	M66592_wValue				0xFFFF	/* b15-0: wValue */
+#define M66592_wValue				0xFFFF	/* b15-0: wValue */
 /* Standard Feature Selector */
-#define	  M66592_ENDPOINT_HALT			0x0000
-#define	  M66592_DEVICE_REMOTE_WAKEUP		0x0001
-#define	  M66592_TEST_MODE			0x0002
+#define   M66592_ENDPOINT_HALT			0x0000
+#define   M66592_DEVICE_REMOTE_WAKEUP		0x0001
+#define   M66592_TEST_MODE			0x0002
 /* Descriptor Types */
-#define	M66592_DT_TYPE				0xFF00
-#define	M66592_GET_DT_TYPE(v)			(((v) & DT_TYPE) >> 8)
-#define	  M66592_DT_DEVICE			0x01
-#define	  M66592_DT_CONFIGURATION		0x02
-#define	  M66592_DT_STRING			0x03
-#define	  M66592_DT_INTERFACE			0x04
-#define	  M66592_DT_ENDPOINT			0x05
-#define	  M66592_DT_DEVICE_QUALIFIER		0x06
-#define	  M66592_DT_OTHER_SPEED_CONFIGURATION	0x07
-#define	  M66592_DT_INTERFACE_POWER		0x08
-#define	M66592_DT_INDEX				0x00FF
-#define	M66592_CONF_NUM				0x00FF
-#define	M66592_ALT_SET				0x00FF
+#define M66592_DT_TYPE				0xFF00
+#define M66592_GET_DT_TYPE(v)			(((v) & DT_TYPE) >> 8)
+#define   M66592_DT_DEVICE			0x01
+#define   M66592_DT_CONFIGURATION		0x02
+#define   M66592_DT_STRING			0x03
+#define   M66592_DT_INTERFACE			0x04
+#define   M66592_DT_ENDPOINT			0x05
+#define   M66592_DT_DEVICE_QUALIFIER		0x06
+#define   M66592_DT_OTHER_SPEED_CONFIGURATION	0x07
+#define   M66592_DT_INTERFACE_POWER		0x08
+#define M66592_DT_INDEX				0x00FF
+#define M66592_CONF_NUM				0x00FF
+#define M66592_ALT_SET				0x00FF
 
 #define M66592_USBINDEX			0x58
-#define	M66592_wIndex			0xFFFF	/* b15-0: wIndex */
-#define	M66592_TEST_SELECT		0xFF00	/* b15-b8: Test Mode Selectors */
-#define	  M66592_TEST_J			 0x0100		  /* Test_J */
-#define	  M66592_TEST_K			 0x0200		  /* Test_K */
-#define	  M66592_TEST_SE0_NAK		 0x0300		  /* Test_SE0_NAK */
-#define	  M66592_TEST_PACKET		 0x0400		  /* Test_Packet */
-#define	  M66592_TEST_FORCE_ENABLE	 0x0500		  /* Test_Force_Enable */
-#define	  M66592_TEST_STSelectors	 0x0600		  /* Standard test selectors */
-#define	  M66592_TEST_Reserved		 0x4000		  /* Reserved */
-#define	  M66592_TEST_VSTModes		 0xC000		  /* Vendor-specific test modes */
-#define	M66592_EP_DIR			0x0080	/* b7: Endpoint Direction */
-#define	  M66592_EP_DIR_IN		 0x0080
-#define	  M66592_EP_DIR_OUT		 0x0000
+#define M66592_wIndex			0xFFFF	/* b15-0: wIndex */
+#define M66592_TEST_SELECT		0xFF00	/* b15-b8: Test Mode */
+#define   M66592_TEST_J			 0x0100	  /* Test_J */
+#define   M66592_TEST_K			 0x0200	  /* Test_K */
+#define   M66592_TEST_SE0_NAK		 0x0300	  /* Test_SE0_NAK */
+#define   M66592_TEST_PACKET		 0x0400	  /* Test_Packet */
+#define   M66592_TEST_FORCE_ENABLE	 0x0500	  /* Test_Force_Enable */
+#define   M66592_TEST_STSelectors	 0x0600	  /* Standard test selectors */
+#define   M66592_TEST_Reserved		 0x4000	  /* Reserved */
+#define   M66592_TEST_VSTModes		 0xC000	  /* Vendor-specific tests */
+#define M66592_EP_DIR			0x0080	/* b7: Endpoint Direction */
+#define   M66592_EP_DIR_IN		 0x0080
+#define   M66592_EP_DIR_OUT		 0x0000
 
 #define M66592_USBLENG		0x5A
-#define	M66592_wLength		0xFFFF	/* b15-0: wLength */
+#define M66592_wLength		0xFFFF	/* b15-0: wLength */
 
 #define M66592_DCPCFG		0x5C
-#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
-#define	M66592_DIR		0x0010	/* b4: Control transfer DIR select */
+#define M66592_CNTMD		0x0100	/* b8: Continuous transfer mode */
+#define M66592_DIR		0x0010	/* b4: Control transfer DIR select */
 
 #define M66592_DCPMAXP		0x5E
-#define	M66592_DEVSEL		0xC000	/* b15-14: Device address select */
-#define	  M66592_DEVICE_0	 0x0000		  /* Device address 0 */
-#define	  M66592_DEVICE_1	 0x4000		  /* Device address 1 */
-#define	  M66592_DEVICE_2	 0x8000		  /* Device address 2 */
-#define	  M66592_DEVICE_3	 0xC000		  /* Device address 3 */
-#define	M66592_MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL		0xC000	/* b15-14: Device address select */
+#define   M66592_DEVICE_0	 0x0000		  /* Device address 0 */
+#define   M66592_DEVICE_1	 0x4000		  /* Device address 1 */
+#define   M66592_DEVICE_2	 0x8000		  /* Device address 2 */
+#define   M66592_DEVICE_3	 0xC000		  /* Device address 3 */
+#define M66592_MAXP		0x007F	/* b6-0: Maxpacket size of ep0 */
 
 #define M66592_DCPCTR		0x60
-#define	M66592_BSTS		0x8000	/* b15: Buffer status */
-#define	M66592_SUREQ		0x4000	/* b14: Send USB request  */
-#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	M66592_CCPL		0x0004	/* b2: Enable control transfer complete */
-#define	M66592_PID		0x0003	/* b1-0: Response PID */
-#define	  M66592_PID_STALL	 0x0002		  /* STALL */
-#define	  M66592_PID_BUF	 0x0001		  /* BUF */
-#define	  M66592_PID_NAK	 0x0000		  /* NAK */
+#define M66592_BSTS		0x8000	/* b15: Buffer status */
+#define M66592_SUREQ		0x4000	/* b14: Send USB request  */
+#define M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define M66592_CCPL		0x0004	/* b2: control transfer complete */
+#define M66592_PID		0x0003	/* b1-0: Response PID */
+#define   M66592_PID_STALL	 0x0002		  /* STALL */
+#define   M66592_PID_BUF	 0x0001		  /* BUF */
+#define   M66592_PID_NAK	 0x0000		  /* NAK */
 
 #define M66592_PIPESEL		0x64
-#define	M66592_PIPENM		0x0007	/* b2-0: Pipe select */
-#define	  M66592_PIPE0		 0x0000		  /* PIPE 0 */
-#define	  M66592_PIPE1		 0x0001		  /* PIPE 1 */
-#define	  M66592_PIPE2		 0x0002		  /* PIPE 2 */
-#define	  M66592_PIPE3		 0x0003		  /* PIPE 3 */
-#define	  M66592_PIPE4		 0x0004		  /* PIPE 4 */
-#define	  M66592_PIPE5		 0x0005		  /* PIPE 5 */
-#define	  M66592_PIPE6		 0x0006		  /* PIPE 6 */
-#define	  M66592_PIPE7		 0x0007		  /* PIPE 7 */
+#define M66592_PIPENM		0x0007	/* b2-0: Pipe select */
+#define   M66592_PIPE0		 0x0000		  /* PIPE 0 */
+#define   M66592_PIPE1		 0x0001		  /* PIPE 1 */
+#define   M66592_PIPE2		 0x0002		  /* PIPE 2 */
+#define   M66592_PIPE3		 0x0003		  /* PIPE 3 */
+#define   M66592_PIPE4		 0x0004		  /* PIPE 4 */
+#define   M66592_PIPE5		 0x0005		  /* PIPE 5 */
+#define   M66592_PIPE6		 0x0006		  /* PIPE 6 */
+#define   M66592_PIPE7		 0x0007		  /* PIPE 7 */
 
 #define M66592_PIPECFG		0x66
-#define	M66592_TYP		0xC000	/* b15-14: Transfer type */
-#define	  M66592_ISO		 0xC000		  /* Isochronous */
-#define	  M66592_INT		 0x8000		  /* Interrupt */
-#define	  M66592_BULK		 0x4000		  /* Bulk */
-#define	M66592_BFRE		0x0400	/* b10: Buffer ready interrupt mode select */
-#define	M66592_DBLB		0x0200	/* b9: Double buffer mode select */
-#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
-#define	M66592_SHTNAK		0x0080	/* b7: Transfer end NAK */
-#define	M66592_DIR		0x0010	/* b4: Transfer direction select */
-#define	  M66592_DIR_H_OUT	 0x0010		  /* HOST OUT */
-#define	  M66592_DIR_P_IN	 0x0010		  /* PERI IN */
-#define	  M66592_DIR_H_IN	 0x0000		  /* HOST IN */
-#define	  M66592_DIR_P_OUT	 0x0000		  /* PERI OUT */
-#define	M66592_EPNUM		0x000F	/* b3-0: Eendpoint number select */
-#define	  M66592_EP1		 0x0001
-#define	  M66592_EP2		 0x0002
-#define	  M66592_EP3		 0x0003
-#define	  M66592_EP4		 0x0004
-#define	  M66592_EP5		 0x0005
-#define	  M66592_EP6		 0x0006
-#define	  M66592_EP7		 0x0007
-#define	  M66592_EP8		 0x0008
-#define	  M66592_EP9		 0x0009
-#define	  M66592_EP10		 0x000A
-#define	  M66592_EP11		 0x000B
-#define	  M66592_EP12		 0x000C
-#define	  M66592_EP13		 0x000D
-#define	  M66592_EP14		 0x000E
-#define	  M66592_EP15		 0x000F
+#define M66592_TYP		0xC000	/* b15-14: Transfer type */
+#define   M66592_ISO		 0xC000		  /* Isochronous */
+#define   M66592_INT		 0x8000		  /* Interrupt */
+#define   M66592_BULK		 0x4000		  /* Bulk */
+#define M66592_BFRE		0x0400	/* b10: Buffer ready interrupt mode */
+#define M66592_DBLB		0x0200	/* b9: Double buffer mode select */
+#define M66592_CNTMD		0x0100	/* b8: Continuous transfer mode */
+#define M66592_SHTNAK		0x0080	/* b7: Transfer end NAK */
+#define M66592_DIR		0x0010	/* b4: Transfer direction select */
+#define   M66592_DIR_H_OUT	 0x0010		  /* HOST OUT */
+#define   M66592_DIR_P_IN	 0x0010		  /* PERI IN */
+#define   M66592_DIR_H_IN	 0x0000		  /* HOST IN */
+#define   M66592_DIR_P_OUT	 0x0000		  /* PERI OUT */
+#define M66592_EPNUM		0x000F	/* b3-0: Eendpoint number select */
+#define   M66592_EP1		 0x0001
+#define   M66592_EP2		 0x0002
+#define   M66592_EP3		 0x0003
+#define   M66592_EP4		 0x0004
+#define   M66592_EP5		 0x0005
+#define   M66592_EP6		 0x0006
+#define   M66592_EP7		 0x0007
+#define   M66592_EP8		 0x0008
+#define   M66592_EP9		 0x0009
+#define   M66592_EP10		 0x000A
+#define   M66592_EP11		 0x000B
+#define   M66592_EP12		 0x000C
+#define   M66592_EP13		 0x000D
+#define   M66592_EP14		 0x000E
+#define   M66592_EP15		 0x000F
 
 #define M66592_PIPEBUF		0x68
-#define	M66592_BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
-#define	M66592_BUF_SIZE(x)	((((x) / 64) - 1) << 10)
-#define	M66592_BUFNMB		0x00FF	/* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x)	((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB		0x00FF	/* b7-0: Pipe buffer number */
 
 #define M66592_PIPEMAXP		0x6A
-#define	M66592_MXPS		0x07FF	/* b10-0: Maxpacket size */
+#define M66592_MXPS		0x07FF	/* b10-0: Maxpacket size */
 
 #define M66592_PIPEPERI		0x6C
-#define	M66592_IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
-#define	M66592_IITV		0x0007	/* b2-0: Isochronous interval */
+#define M66592_IFIS		0x1000	/* b12: ISO in-buffer flush mode */
+#define M66592_IITV		0x0007	/* b2-0: ISO interval */
 
 #define M66592_PIPE1CTR		0x70
 #define M66592_PIPE2CTR		0x72
@@ -401,19 +401,17 @@
 #define M66592_PIPE5CTR		0x78
 #define M66592_PIPE6CTR		0x7A
 #define M66592_PIPE7CTR		0x7C
-#define	M66592_BSTS		0x8000	/* b15: Buffer status */
-#define	M66592_INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define	M66592_ACLRM		0x0200	/* b9: Out buffer auto clear mode */
-#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	M66592_PID		0x0003	/* b1-0: Response PID */
+#define M66592_BSTS		0x8000	/* b15: Buffer status */
+#define M66592_INBUFM		0x4000	/* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM		0x0200	/* b9: Out buffer auto clear mode */
+#define M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define M66592_PID		0x0003	/* b1-0: Response PID */
 
 #define M66592_INVALID_REG	0x7E
 
 
-#define __iomem
-
 #define get_pipectr_addr(pipenum)	(M66592_PIPE1CTR + (pipenum - 1) * 2)
 
 #define M66592_MAX_SAMPLING	10
@@ -449,7 +447,7 @@
 	struct m66592		*m66592;
 
 	struct list_head	queue;
-	unsigned 		busy:1;
+	unsigned		busy:1;
 	unsigned		internal_ccpl:1;	/* use only control */
 
 	/* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@
 	struct m66592_ep	*epaddr2ep[16];
 
 	struct usb_request	*ep0_req;	/* for internal request */
-	u16			*ep0_buf;	/* for internal request */
+	u16			ep0_data;	/* for internal request */
 
 	struct timer_list	timer;
 
@@ -527,8 +525,8 @@
 }
 
 static inline void m66592_read_fifo(struct m66592 *m66592,
-				    unsigned long offset,
-				    void *buf, unsigned long len)
+		unsigned long offset,
+		void *buf, unsigned long len)
 {
 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
@@ -543,8 +541,8 @@
 }
 
 static inline void m66592_write_fifo(struct m66592 *m66592,
-				     unsigned long offset,
-				     void *buf, unsigned long len)
+		unsigned long offset,
+		void *buf, unsigned long len)
 {
 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 	unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@
 }
 
 static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
-			       unsigned long offset)
+		unsigned long offset)
 {
 	u16 tmp;
 	tmp = m66592_read(m66592, offset);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 38138bb..9cd98e7 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -258,7 +259,7 @@
 static const char *EP_OUT_NAME;
 static const char *EP_NOTIFY_NAME;
 
-static struct semaphore	gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
 static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@
 	tty_set_operations(gs_tty_driver, &gs_tty_ops);
 
 	for (i=0; i < GS_NUM_PORTS; i++)
-		sema_init(&gs_open_close_sem[i], 1);
+		mutex_init(&gs_open_close_lock[i]);
 
 	retval = tty_register_driver(gs_tty_driver);
 	if (retval) {
@@ -635,7 +636,7 @@
 	struct gs_port *port;
 	struct gs_dev *dev;
 	struct gs_buf *buf;
-	struct semaphore *sem;
+	struct mutex *mtx;
 	int ret;
 
 	port_num = tty->index;
@@ -656,10 +657,10 @@
 		return -ENODEV;
 	}
 
-	sem = &gs_open_close_sem[port_num];
-	if (down_interruptible(sem)) {
+	mtx = &gs_open_close_lock[port_num];
+	if (mutex_lock_interruptible(mtx)) {
 		printk(KERN_ERR
-		"gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+		"gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
 			port_num, tty, file);
 		return -ERESTARTSYS;
 	}
@@ -754,12 +755,12 @@
 
 exit_unlock_port:
 	spin_unlock_irqrestore(&port->port_lock, flags);
-	up(sem);
+	mutex_unlock(mtx);
 	return ret;
 
 exit_unlock_dev:
 	spin_unlock_irqrestore(&dev->dev_lock, flags);
-	up(sem);
+	mutex_unlock(mtx);
 	return ret;
 
 }
@@ -781,7 +782,7 @@
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
 	struct gs_port *port = tty->driver_data;
-	struct semaphore *sem;
+	struct mutex *mtx;
 
 	if (port == NULL) {
 		printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@
 
 	gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
 
-	sem = &gs_open_close_sem[port->port_num];
-	down(sem);
+	mtx = &gs_open_close_lock[port->port_num];
+	mutex_lock(mtx);
 
 	spin_lock_irq(&port->port_lock);
 
@@ -846,7 +847,7 @@
 
 exit:
 	spin_unlock_irq(&port->port_lock);
-	up(sem);
+	mutex_unlock(mtx);
 }
 
 /*
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46873f2..5c851a3 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@
 				   struct urb, urb_list);
 		ptd = &ep->ptd;
 		len = ep->length;
-		spin_lock(&urb->lock);
 		ep->data = (unsigned char *)urb->transfer_buffer
 		    + urb->actual_length;
 
@@ -264,7 +263,6 @@
 		    | PTD_EP(ep->epnum);
 		ptd->len = PTD_LEN(len) | PTD_DIR(dir);
 		ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
-		spin_unlock(&urb->lock);
 		if (!ep->active) {
 			ptd->mps |= PTD_LAST_MSK;
 			isp116x->atl_last_dir = dir;
@@ -275,145 +273,6 @@
 }
 
 /*
-  Analyze transfer results, handle partial transfers and errors
-*/
-static void postproc_atl_queue(struct isp116x *isp116x)
-{
-	struct isp116x_ep *ep;
-	struct urb *urb;
-	struct usb_device *udev;
-	struct ptd *ptd;
-	int short_not_ok;
-	u8 cc;
-
-	for (ep = isp116x->atl_active; ep; ep = ep->active) {
-		BUG_ON(list_empty(&ep->hep->urb_list));
-		urb =
-		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
-		udev = urb->dev;
-		ptd = &ep->ptd;
-		cc = PTD_GET_CC(ptd);
-		short_not_ok = 1;
-		spin_lock(&urb->lock);
-
-		/* Data underrun is special. For allowed underrun
-		   we clear the error and continue as normal. For
-		   forbidden underrun we finish the DATA stage
-		   immediately while for control transfer,
-		   we do a STATUS stage. */
-		if (cc == TD_DATAUNDERRUN) {
-			if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
-				DBG("Allowed data underrun\n");
-				cc = TD_CC_NOERROR;
-				short_not_ok = 0;
-			} else {
-				ep->error_count = 1;
-				if (usb_pipecontrol(urb->pipe))
-					ep->nextpid = USB_PID_ACK;
-				else
-					usb_settoggle(udev, ep->epnum,
-						      ep->nextpid ==
-						      USB_PID_OUT,
-						      PTD_GET_TOGGLE(ptd));
-				urb->actual_length += PTD_GET_COUNT(ptd);
-				urb->status = cc_to_error[TD_DATAUNDERRUN];
-				spin_unlock(&urb->lock);
-				continue;
-			}
-		}
-		/* Keep underrun error through the STATUS stage */
-		if (urb->status == cc_to_error[TD_DATAUNDERRUN])
-			cc = TD_DATAUNDERRUN;
-
-		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
-		    && (++ep->error_count >= 3 || cc == TD_CC_STALL
-			|| cc == TD_DATAOVERRUN)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error[cc];
-			if (ep->nextpid == USB_PID_ACK)
-				ep->nextpid = 0;
-			spin_unlock(&urb->lock);
-			continue;
-		}
-		/* According to usb spec, zero-length Int transfer signals
-		   finishing of the urb. Hey, does this apply only
-		   for IN endpoints? */
-		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
-			spin_unlock(&urb->lock);
-			continue;
-		}
-
-		/* Relax after previously failed, but later succeeded
-		   or correctly NAK'ed retransmission attempt */
-		if (ep->error_count
-		    && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))
-			ep->error_count = 0;
-
-		/* Take into account idiosyncracies of the isp116x chip
-		   regarding toggle bit for failed transfers */
-		if (ep->nextpid == USB_PID_OUT)
-			usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)
-				      ^ (ep->error_count > 0));
-		else if (ep->nextpid == USB_PID_IN)
-			usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)
-				      ^ (ep->error_count > 0));
-
-		switch (ep->nextpid) {
-		case USB_PID_IN:
-		case USB_PID_OUT:
-			urb->actual_length += PTD_GET_COUNT(ptd);
-			if (PTD_GET_ACTIVE(ptd)
-			    || (cc != TD_CC_NOERROR && cc < 0x0E))
-				break;
-			if (urb->transfer_buffer_length != urb->actual_length) {
-				if (short_not_ok)
-					break;
-			} else {
-				if (urb->transfer_flags & URB_ZERO_PACKET
-				    && ep->nextpid == USB_PID_OUT
-				    && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {
-					DBG("Zero packet requested\n");
-					break;
-				}
-			}
-			/* All data for this URB is transferred, let's finish */
-			if (usb_pipecontrol(urb->pipe))
-				ep->nextpid = USB_PID_ACK;
-			else if (urb->status == -EINPROGRESS)
-				urb->status = 0;
-			break;
-		case USB_PID_SETUP:
-			if (PTD_GET_ACTIVE(ptd)
-			    || (cc != TD_CC_NOERROR && cc < 0x0E))
-				break;
-			if (urb->transfer_buffer_length == urb->actual_length)
-				ep->nextpid = USB_PID_ACK;
-			else if (usb_pipeout(urb->pipe)) {
-				usb_settoggle(udev, 0, 1, 1);
-				ep->nextpid = USB_PID_OUT;
-			} else {
-				usb_settoggle(udev, 0, 0, 1);
-				ep->nextpid = USB_PID_IN;
-			}
-			break;
-		case USB_PID_ACK:
-			if (PTD_GET_ACTIVE(ptd)
-			    || (cc != TD_CC_NOERROR && cc < 0x0E))
-				break;
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
-			ep->nextpid = 0;
-			break;
-		default:
-			BUG();
-		}
-		spin_unlock(&urb->lock);
-	}
-}
-
-/*
   Take done or failed requests out of schedule. Give back
   processed urbs.
 */
@@ -469,6 +328,148 @@
 }
 
 /*
+  Analyze transfer results, handle partial transfers and errors
+*/
+static void postproc_atl_queue(struct isp116x *isp116x)
+{
+	struct isp116x_ep *ep;
+	struct urb *urb;
+	struct usb_device *udev;
+	struct ptd *ptd;
+	int short_not_ok;
+	int status;
+	u8 cc;
+
+	for (ep = isp116x->atl_active; ep; ep = ep->active) {
+		BUG_ON(list_empty(&ep->hep->urb_list));
+		urb =
+		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
+		udev = urb->dev;
+		ptd = &ep->ptd;
+		cc = PTD_GET_CC(ptd);
+		short_not_ok = 1;
+		status = -EINPROGRESS;
+
+		/* Data underrun is special. For allowed underrun
+		   we clear the error and continue as normal. For
+		   forbidden underrun we finish the DATA stage
+		   immediately while for control transfer,
+		   we do a STATUS stage. */
+		if (cc == TD_DATAUNDERRUN) {
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+					usb_pipecontrol(urb->pipe)) {
+				DBG("Allowed or control data underrun\n");
+				cc = TD_CC_NOERROR;
+				short_not_ok = 0;
+			} else {
+				ep->error_count = 1;
+				usb_settoggle(udev, ep->epnum,
+					      ep->nextpid == USB_PID_OUT,
+					      PTD_GET_TOGGLE(ptd));
+				urb->actual_length += PTD_GET_COUNT(ptd);
+				status = cc_to_error[TD_DATAUNDERRUN];
+				goto done;
+			}
+		}
+
+		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
+		    && (++ep->error_count >= 3 || cc == TD_CC_STALL
+			|| cc == TD_DATAOVERRUN)) {
+			status = cc_to_error[cc];
+			if (ep->nextpid == USB_PID_ACK)
+				ep->nextpid = 0;
+			goto done;
+		}
+		/* According to usb spec, zero-length Int transfer signals
+		   finishing of the urb. Hey, does this apply only
+		   for IN endpoints? */
+		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
+			status = 0;
+			goto done;
+		}
+
+		/* Relax after previously failed, but later succeeded
+		   or correctly NAK'ed retransmission attempt */
+		if (ep->error_count
+		    && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))
+			ep->error_count = 0;
+
+		/* Take into account idiosyncracies of the isp116x chip
+		   regarding toggle bit for failed transfers */
+		if (ep->nextpid == USB_PID_OUT)
+			usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)
+				      ^ (ep->error_count > 0));
+		else if (ep->nextpid == USB_PID_IN)
+			usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)
+				      ^ (ep->error_count > 0));
+
+		switch (ep->nextpid) {
+		case USB_PID_IN:
+		case USB_PID_OUT:
+			urb->actual_length += PTD_GET_COUNT(ptd);
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if (urb->transfer_buffer_length != urb->actual_length) {
+				if (short_not_ok)
+					break;
+			} else {
+				if (urb->transfer_flags & URB_ZERO_PACKET
+				    && ep->nextpid == USB_PID_OUT
+				    && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {
+					DBG("Zero packet requested\n");
+					break;
+				}
+			}
+			/* All data for this URB is transferred, let's finish */
+			if (usb_pipecontrol(urb->pipe))
+				ep->nextpid = USB_PID_ACK;
+			else
+				status = 0;
+			break;
+		case USB_PID_SETUP:
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if (urb->transfer_buffer_length == urb->actual_length)
+				ep->nextpid = USB_PID_ACK;
+			else if (usb_pipeout(urb->pipe)) {
+				usb_settoggle(udev, 0, 1, 1);
+				ep->nextpid = USB_PID_OUT;
+			} else {
+				usb_settoggle(udev, 0, 0, 1);
+				ep->nextpid = USB_PID_IN;
+			}
+			break;
+		case USB_PID_ACK:
+			if (PTD_GET_ACTIVE(ptd)
+			    || (cc != TD_CC_NOERROR && cc < 0x0E))
+				break;
+			if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+					urb->actual_length <
+						urb->transfer_buffer_length)
+				status = -EREMOTEIO;
+			else
+				status = 0;
+			ep->nextpid = 0;
+			break;
+		default:
+			BUG();
+		}
+
+ done:
+		if (status != -EINPROGRESS) {
+			spin_lock(&urb->lock);
+			if (urb->status == -EINPROGRESS)
+				urb->status = status;
+			spin_unlock(&urb->lock);
+		}
+		if (urb->status != -EINPROGRESS)
+			finish_request(isp116x, ep, urb);
+	}
+}
+
+/*
   Scan transfer lists, schedule transfers, send data off
   to chip.
  */
@@ -570,9 +571,6 @@
 */
 static void finish_atl_transfers(struct isp116x *isp116x)
 {
-	struct isp116x_ep *ep;
-	struct urb *urb;
-
 	if (!isp116x->atl_active)
 		return;
 	/* Fifo not ready? */
@@ -582,16 +580,6 @@
 	atomic_inc(&isp116x->atl_finishing);
 	unpack_fifo(isp116x);
 	postproc_atl_queue(isp116x);
-	for (ep = isp116x->atl_active; ep; ep = ep->active) {
-		urb =
-		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
-		/* USB_PID_ACK check here avoids finishing of
-		   control transfers, for which TD_DATAUNDERRUN
-		   occured, while URB_SHORT_NOT_OK was set */
-		if (urb && urb->status != -EINPROGRESS
-		    && ep->nextpid != USB_PID_ACK)
-			finish_request(isp116x, ep, urb);
-	}
 	atomic_dec(&isp116x->atl_finishing);
 }
 
@@ -821,15 +809,12 @@
 	}
 
 	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
 	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
 		finish_request(isp116x, ep, urb);
 		ret = 0;
 		goto fail;
 	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
 	start_atl_transfers(isp116x);
 
       fail:
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a7a7070..d60f198 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -35,10 +35,8 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 
 #include "../core/hcd.h"
 #include "r8a66597.h"
@@ -54,16 +52,21 @@
 /* module parameters */
 static unsigned short clock = XTAL12;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+		"(default=0)");
+
 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
 MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+		"(default=32)");
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
 static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@
 	struct r8a66597_device *dev;
 	int usb_address = urb->setup_packet[2];	/* urb->pipe is address 0 */
 
-	dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+	dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
 	if (dev == NULL)
 		return -ENOMEM;
 
@@ -611,33 +614,33 @@
 	u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
 
 	memset(array, 0, sizeof(array));
-        switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-        case USB_ENDPOINT_XFER_BULK:
+	switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 			array[i++] = 4;
 		else {
 			array[i++] = 3;
 			array[i++] = 5;
 		}
-                break;
-        case USB_ENDPOINT_XFER_INT:
+		break;
+	case USB_ENDPOINT_XFER_INT:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
 			array[i++] = 6;
 			array[i++] = 7;
 			array[i++] = 8;
 		} else
 			array[i++] = 9;
-                break;
-        case USB_ENDPOINT_XFER_ISOC:
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 			array[i++] = 2;
 		else
 			array[i++] = 1;
-                break;
-        default:
-                err("Illegal type");
-                return 0;
-        }
+		break;
+	default:
+		err("Illegal type");
+		return 0;
+	}
 
 	i = 1;
 	min = array[0];
@@ -654,7 +657,7 @@
 {
 	u16 r8a66597_type;
 
-	switch(type) {
+	switch (type) {
 	case USB_ENDPOINT_XFER_BULK:
 		r8a66597_type = R8A66597_BULK;
 		break;
@@ -874,7 +877,7 @@
 {
 	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
 					 | (1 << USB_PORT_FEAT_C_CONNECTION);
-	r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+	r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
 	r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
 }
 
@@ -917,7 +920,7 @@
 
 	r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
 		       DCPMAXP);
-	r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
 	for (i = 0; i < 4; i++) {
 		r8a66597_write(r8a66597, p[i], setup_addr);
@@ -948,19 +951,18 @@
 			pipe_irq_disable(r8a66597, td->pipenum);
 			pipe_setting(r8a66597, td);
 			pipe_stop(r8a66597, td->pipe);
-			r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
-				       BRDYSTS);
+			r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
 			if (td->pipe->pipetre) {
 				r8a66597_write(r8a66597, TRCLR,
-					        td->pipe->pipetre);
+						td->pipe->pipetre);
 				r8a66597_write(r8a66597,
-					       (urb->transfer_buffer_length
-					       + td->maxpacket - 1)
-					       / td->maxpacket,
-					       td->pipe->pipetrn);
+						(urb->transfer_buffer_length
+						+ td->maxpacket - 1)
+						/ td->maxpacket,
+						td->pipe->pipetrn);
 				r8a66597_bset(r8a66597, TRENB,
-					      td->pipe->pipetre);
+						td->pipe->pipetre);
 			}
 
 			pipe_start(r8a66597, td->pipe);
@@ -991,7 +993,7 @@
 		if (td->pipe->pipetre)
 			r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
 	}
-	r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+	r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,21 +1011,21 @@
 	struct urb *urb = td->urb;
 
 	r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+	pipe_stop(r8a66597, td->pipe);
 
 	if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
 		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
 		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
-		r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
-		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		r8a66597_write(r8a66597, BVAL, CFIFOCTR);
 		enable_irq_empty(r8a66597, 0);
 	} else {
 		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
 		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
 		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
-		r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
-		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
 		enable_irq_ready(r8a66597, 0);
 	}
 	enable_irq_nrdy(r8a66597, 0);
@@ -1269,7 +1271,7 @@
 
 	/* write fifo */
 	if (pipenum > 0)
-		r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+		r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
 	if (urb->transfer_buffer) {
 		r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
 		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1362,7 +1364,7 @@
 
 	mask = r8a66597_read(r8a66597, BRDYSTS)
 	       & r8a66597_read(r8a66597, BRDYENB);
-	r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+	r8a66597_write(r8a66597, ~mask, BRDYSTS);
 	if (mask & BRDY0) {
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type == USB_PID_IN)
@@ -1397,7 +1399,7 @@
 
 	mask = r8a66597_read(r8a66597, BEMPSTS)
 	       & r8a66597_read(r8a66597, BEMPENB);
-	r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+	r8a66597_write(r8a66597, ~mask, BEMPSTS);
 	if (mask & BEMP0) {
 		cfifo_change(r8a66597, 0);
 		td = r8a66597_get_td(r8a66597, 0);
@@ -1434,7 +1436,7 @@
 
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	       & r8a66597_read(r8a66597, NRDYENB);
-	r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	if (mask & NRDY0) {
 		cfifo_change(r8a66597, 0);
 		set_urb_error(r8a66597, 0);
@@ -1488,14 +1490,14 @@
 	mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
 	if (mask2) {
 		if (mask2 & ATTCH) {
-			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+			r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
 			r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
 
 			/* start usb bus sampling */
 			start_root_hub_sampling(r8a66597, 1);
 		}
 		if (mask2 & DTCH) {
-			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+			r8a66597_write(r8a66597, ~DTCH, INTSTS2);
 			r8a66597_bclr(r8a66597, DTCHE, INTENB2);
 			r8a66597_usb_disconnect(r8a66597, 1);
 		}
@@ -1503,24 +1505,24 @@
 
 	if (mask1) {
 		if (mask1 & ATTCH) {
-			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+			r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
 			r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
 
 			/* start usb bus sampling */
 			start_root_hub_sampling(r8a66597, 0);
 		}
 		if (mask1 & DTCH) {
-			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+			r8a66597_write(r8a66597, ~DTCH, INTSTS1);
 			r8a66597_bclr(r8a66597, DTCHE, INTENB1);
 			r8a66597_usb_disconnect(r8a66597, 0);
 		}
 		if (mask1 & SIGN) {
-			r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
+			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
 			set_urb_error(r8a66597, 0);
 			check_next_phase(r8a66597);
 		}
 		if (mask1 & SACK) {
-			r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
+			r8a66597_write(r8a66597, ~SACK, INTSTS1);
 			check_next_phase(r8a66597);
 		}
 	}
@@ -1663,13 +1665,9 @@
 static int r8a66597_start(struct usb_hcd *hcd)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
-	int ret;
 
 	hcd->state = HC_STATE_RUNNING;
-	if ((ret = enable_controller(r8a66597)) < 0)
-		return ret;
-
-	return 0;
+	return enable_controller(r8a66597);
 }
 
 static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1694,12 @@
 
 static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
 					    struct urb *urb,
-					    struct usb_host_endpoint *hep,
-					    gfp_t mem_flags)
+					    struct usb_host_endpoint *hep)
 {
 	struct r8a66597_td *td;
 	u16 pipenum;
 
-	td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+	td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
 	if (td == NULL)
 		return NULL;
 
@@ -1741,7 +1738,8 @@
 	}
 
 	if (!hep->hcpriv) {
-		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+				GFP_ATOMIC);
 		if (!hep->hcpriv) {
 			ret = -ENOMEM;
 			goto error;
@@ -1755,7 +1753,7 @@
 		init_pipe_config(r8a66597, urb);
 
 	set_address_zero(r8a66597, urb);
-	td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+	td = r8a66597_make_td(r8a66597, urb, hep);
 	if (td == NULL) {
 		ret = -ENOMEM;
 		goto error;
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 97c2a71..fe9ceb0 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -203,14 +203,14 @@
 #define	DTLN		0x0FFF	/* b11-0: FIFO received data length */
 
 /* Interrupt Enable Register 0 */
-#define	VBSE		0x8000	/* b15: VBUS interrupt */
-#define	RSME		0x4000	/* b14: Resume interrupt */
-#define	SOFE		0x2000	/* b13: Frame update interrupt */
-#define	DVSE		0x1000	/* b12: Device state transition interrupt */
-#define	CTRE		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	BEMPE		0x0400	/* b10: Buffer empty interrupt */
-#define	NRDYE		0x0200	/* b9: Buffer not ready interrupt */
-#define	BRDYE		0x0100	/* b8: Buffer ready interrupt */
+#define	VBSE	0x8000	/* b15: VBUS interrupt */
+#define	RSME	0x4000	/* b14: Resume interrupt */
+#define	SOFE	0x2000	/* b13: Frame update interrupt */
+#define	DVSE	0x1000	/* b12: Device state transition interrupt */
+#define	CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define	NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDYE	0x0100	/* b8: Buffer ready interrupt */
 
 /* Interrupt Enable Register 1 */
 #define	OVRCRE		0x8000	/* b15: Over-current interrupt */
@@ -268,16 +268,16 @@
 #define	  SOF_DISABLE	 0x0000	  /* SOF OUT Disable */
 
 /* Interrupt Status Register 0 */
-#define	VBINT		0x8000	/* b15: VBUS interrupt */
-#define	RESM		0x4000	/* b14: Resume interrupt */
-#define	SOFR		0x2000	/* b13: SOF frame update interrupt */
-#define	DVST		0x1000	/* b12: Device state transition interrupt */
-#define	CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	BEMP		0x0400	/* b10: Buffer empty interrupt */
-#define	NRDY		0x0200	/* b9: Buffer not ready interrupt */
-#define	BRDY		0x0100	/* b8: Buffer ready interrupt */
-#define	VBSTS		0x0080	/* b7: VBUS input port */
-#define	DVSQ		0x0070	/* b6-4: Device state */
+#define	VBINT	0x8000	/* b15: VBUS interrupt */
+#define	RESM	0x4000	/* b14: Resume interrupt */
+#define	SOFR	0x2000	/* b13: SOF frame update interrupt */
+#define	DVST	0x1000	/* b12: Device state transition interrupt */
+#define	CTRT	0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMP	0x0400	/* b10: Buffer empty interrupt */
+#define	NRDY	0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDY	0x0100	/* b8: Buffer ready interrupt */
+#define	VBSTS	0x0080	/* b7: VBUS input port */
+#define	DVSQ	0x0070	/* b6-4: Device state */
 #define	  DS_SPD_CNFG	 0x0070	  /* Suspend Configured */
 #define	  DS_SPD_ADDR	 0x0060	  /* Suspend Address */
 #define	  DS_SPD_DFLT	 0x0050	  /* Suspend Default */
@@ -315,13 +315,10 @@
 /* Micro Frame Number Register */
 #define	UFRNM		0x0007	/* b2-0: Micro frame number */
 
-/* USB Address / Low Power Status Recovery Register */
-//#define	USBADDR		0x007F	/* b6-0: USB address */
-
 /* Default Control Pipe Maxpacket Size Register */
 /* Pipe Maxpacket Size Register */
-#define	DEVSEL		0xF000	/* b15-14: Device address select */
-#define	MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+#define	DEVSEL	0xF000	/* b15-14: Device address select */
+#define	MAXP	0x007F	/* b6-0: Maxpacket size of default control pipe */
 
 /* Default Control Pipe Control Register */
 #define	BSTS		0x8000	/* b15: Buffer status */
@@ -366,21 +363,21 @@
 #define	MXPS		0x07FF	/* b10-0: Maxpacket size */
 
 /* Pipe Cycle Configuration Register */
-#define	IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
-#define	IITV		0x0007	/* b2-0: Isochronous interval */
+#define	IFIS	0x1000	/* b12: Isochronous in-buffer flush mode select */
+#define	IITV	0x0007	/* b2-0: Isochronous interval */
 
 /* Pipex Control Register */
-#define	BSTS		0x8000	/* b15: Buffer status */
-#define	INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define	CSCLR		0x2000	/* b13: complete-split status clear */
-#define	CSSTS		0x1000	/* b12: complete-split status */
-#define	ATREPM		0x0400	/* b10: Auto repeat mode */
-#define	ACLRM		0x0200	/* b9: Out buffer auto clear mode */
-#define	SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	PBUSY		0x0020	/* b5: pipe busy */
-#define	PID		0x0003	/* b1-0: Response PID */
+#define	BSTS	0x8000	/* b15: Buffer status */
+#define	INBUFM	0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define	CSCLR	0x2000	/* b13: complete-split status clear */
+#define	CSSTS	0x1000	/* b12: complete-split status */
+#define	ATREPM	0x0400	/* b10: Auto repeat mode */
+#define	ACLRM	0x0200	/* b9: Out buffer auto clear mode */
+#define	SQCLR	0x0100	/* b8: Sequence toggle bit clear */
+#define	SQSET	0x0080	/* b7: Sequence toggle bit set */
+#define	SQMON	0x0040	/* b6: Sequence toggle bit monitor */
+#define	PBUSY	0x0020	/* b5: pipe busy */
+#define	PID	0x0003	/* b1-0: Response PID */
 
 /* PIPExTRE */
 #define	TRENB		0x0200	/* b9: Transaction counter enable */
@@ -407,15 +404,15 @@
 #define make_devsel(addr)		(addr << 12)
 
 struct r8a66597_pipe_info {
-        u16 pipenum;
-        u16 address;	/* R8A66597 HCD usb addres */
-        u16 epnum;
-        u16 maxpacket;
-        u16 type;
-        u16 bufnum;
-        u16 buf_bsize;
-        u16 interval;
-        u16 dir_in;
+	u16 pipenum;
+	u16 address;	/* R8A66597 HCD usb addres */
+	u16 epnum;
+	u16 maxpacket;
+	u16 type;
+	u16 bufnum;
+	u16 buf_bsize;
+	u16 interval;
+	u16 dir_in;
 };
 
 struct r8a66597_pipe {
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index e98df2e..7f765ec 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -52,6 +52,7 @@
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/pci_ids.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -83,7 +84,7 @@
 * u132_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
 static int u132_exiting = 0;
 static int u132_instances = 0;
 static struct list_head u132_static_list;
@@ -258,10 +259,10 @@
         struct platform_device *pdev = u132->platform_dev;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         u132->going += 1;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         list_del_init(&u132->u132_list);
         u132_instances -= 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
                 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
         usb_put_hcd(hcd);
@@ -3111,10 +3112,10 @@
                 int retval = 0;
                 struct u132 *u132 = hcd_to_u132(hcd);
                 hcd->rsrc_start = 0;
-                down(&u132_module_lock);
+                mutex_lock(&u132_module_lock);
                 list_add_tail(&u132->u132_list, &u132_static_list);
                 u132->sequence_num = ++u132_instances;
-                up(&u132_module_lock);
+                mutex_unlock(&u132_module_lock);
                 u132_u132_init_kref(u132);
                 u132_initialise(u132, pdev);
                 hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3217,7 @@
         INIT_LIST_HEAD(&u132_static_list);
         u132_instances = 0;
         u132_exiting = 0;
-        init_MUTEX(&u132_module_lock);
+        mutex_init(&u132_module_lock);
         if (usb_disabled())
                 return -ENODEV;
         printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3233,9 @@
 {
         struct u132 *u132;
         struct u132 *temp;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         u132_exiting += 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
                 platform_device_unregister(u132->platform_dev);
         } platform_driver_unregister(&u132_platform_driver);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4aed305..3bb908c 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -827,8 +827,10 @@
 	 * If direction is "send", change the packet ID from SETUP (0x2D)
 	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
 	 * set Short Packet Detect (SPD) for all data packets.
+	 *
+	 * 0-length transfers always get treated as "send".
 	 */
-	if (usb_pipeout(urb->pipe))
+	if (usb_pipeout(urb->pipe) || len == 0)
 		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
 	else {
 		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +841,12 @@
 	 * Build the DATA TDs
 	 */
 	while (len > 0) {
-		int pktsze = min(len, maxsze);
+		int pktsze = maxsze;
+
+		if (len <= pktsze) {		/* The last data packet */
+			pktsze = len;
+			status &= ~TD_CTRL_SPD;
+		}
 
 		td = uhci_alloc_td(uhci);
 		if (!td)
@@ -866,20 +873,10 @@
 		goto nomem;
 	*plink = LINK_TO_TD(td);
 
-	/*
-	 * It's IN if the pipe is an output pipe or we're not expecting
-	 * data back.
-	 */
-	destination &= ~TD_TOKEN_PID_MASK;
-	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
+	/* Change direction for the status transaction */
+	destination ^= (USB_PID_IN ^ USB_PID_OUT);
 	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
 
-	status &= ~TD_CTRL_SPD;
-
 	uhci_add_td_to_urbp(td, urbp);
 	uhci_fill_td(td, status | TD_CTRL_IOC,
 			destination | uhci_explen(0), 0);
@@ -1185,10 +1182,18 @@
 				}
 			}
 
+		/* Did we receive a short packet? */
 		} else if (len < uhci_expected_length(td_token(td))) {
 
-			/* We received a short packet */
-			if (urb->transfer_flags & URB_SHORT_NOT_OK)
+			/* For control transfers, go to the status TD if
+			 * this isn't already the last data TD */
+			if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+				if (td->list.next != urbp->td_list.prev)
+					ret = 1;
+			}
+
+			/* For bulk and interrupt, this may be an error */
+			else if (urb->transfer_flags & URB_SHORT_NOT_OK)
 				ret = -EREMOTEIO;
 
 			/* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1213,6 @@
 
 err:
 	if (ret < 0) {
-		/* In case a control transfer gets an error
-		 * during the setup stage */
-		urb->actual_length = max(urb->actual_length, 0);
-
 		/* Note that the queue has stopped and save
 		 * the next toggle value */
 		qh->element = UHCI_PTR_TERM;
@@ -1489,9 +1490,25 @@
 {
 	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
+	if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+		/* urb->actual_length < 0 means the setup transaction didn't
+		 * complete successfully.  Either it failed or the URB was
+		 * unlinked first.  Regardless, don't confuse people with a
+		 * negative length. */
+		urb->actual_length = max(urb->actual_length, 0);
+
+		/* Report erroneous short transfers */
+		if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+				urb->actual_length <
+					urb->transfer_buffer_length &&
+				urb->status == 0))
+			urb->status = -EREMOTEIO;
+	}
+
 	/* When giving back the first URB in an Isochronous queue,
 	 * reinitialize the QH's iso-related members for the next URB. */
-	if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+	else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
 			urbp->node.prev == &qh->queue &&
 			urbp->node.next != &qh->queue) {
 		struct urb *nurb = list_entry(urbp->node.next,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 36502a0..d1131a8 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,9 +284,9 @@
 	int data_received=0, wake_up;
 	unsigned char* b=urb->transfer_buffer;
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status >= 0)
-	{
+	if (status >= 0) {
 
 		//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
 
@@ -324,7 +324,7 @@
 		||
 			((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
 		||
-			(urb->status < 0)
+			(status < 0)
 		);
 
 	if (wake_up)
@@ -376,15 +376,12 @@
 static void mdc800_usb_write_notify (struct urb *urb)
 {
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status != 0)
-	{
-		err ("writing command fails (status=%i)", urb->status);
-	}
+	if (status != 0)
+		err ("writing command fails (status=%i)", status);
 	else
-	{	
 		mdc800->state=READY;
-	}
 	mdc800->written = 1;
 	wake_up (&mdc800->write_wait);
 }
@@ -396,9 +393,9 @@
 static void mdc800_usb_download_notify (struct urb *urb)
 {
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status == 0)
-	{
+	if (status == 0) {
 		/* Fill output buffer with these data */
 		memcpy (mdc800->out,  urb->transfer_buffer, 64);
 		mdc800->out_count=64;
@@ -408,10 +405,8 @@
 		{
 			mdc800->state=READY;
 		}
-	}
-	else
-	{
-		err ("request bytes fails (status:%i)", urb->status);
+	} else {
+		err ("request bytes fails (status:%i)", status);
 	}
 	mdc800->downloaded = 1;
 	wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@
 
 	retval=0;
 	mdc800->irq_urb->dev = mdc800->dev;
-	if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
-	{
-		err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+	retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+	if (retval) {
+		err ("request USB irq fails (submit_retval=%i).", retval);
 		errn = -EIO;
 		goto error_out;
 	}
@@ -698,6 +693,7 @@
 {
 	size_t left=len, sts=len; /* single transfer size */
 	char __user *ptr = buf;
+	int retval;
 
 	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@
 
 				/* Download -> Request new bytes */
 				mdc800->download_urb->dev = mdc800->dev;
-				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
-				{
-					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+				retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+				if (retval) {
+					err ("Can't submit download urb (retval=%i)",retval);
 					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
@@ -788,6 +784,7 @@
 static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
 {
 	size_t i=0;
+	int retval;
 
 	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state != READY)
@@ -854,9 +851,9 @@
 			mdc800->state=WORKING;
 			memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
 			mdc800->write_urb->dev = mdc800->dev;
-			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
-			{
-				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+			retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+			if (retval) {
+				err ("submitting write urb fails (retval=%i)", retval);
 				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 51bd80d..768b2c1 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -189,7 +189,7 @@
 #define MTS_DEBUG_INT() \
 	do { MTS_DEBUG_GOT_HERE(); \
 	     MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
-	     MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+	     MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
              mts_debug_dump(context->instance);\
 	   } while(0)
 #else
@@ -393,8 +393,6 @@
 		      context
 		);
 
-	transfer->status = 0;
-
 	res = usb_submit_urb( transfer, GFP_ATOMIC );
 	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@
 static void mts_data_done( struct urb* transfer )
 /* Interrupt context! */
 {
+	int status = transfer->status;
 	MTS_INT_INIT();
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
-	} else if ( unlikely(transfer->status) ) {
-		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+	} else if ( unlikely(status) ) {
+		context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
 	mts_get_status(transfer);
@@ -461,10 +460,11 @@
 static void mts_command_done( struct urb *transfer )
 /* Interrupt context! */
 {
+	int status = transfer->status;
 	MTS_INT_INIT();
 
-	if ( unlikely(transfer->status) ) {
-	        if (transfer->status == -ENOENT) {
+	if ( unlikely(status) ) {
+	        if (status == -ENOENT) {
 		        /* We are being killed */
 			MTS_DEBUG_GOT_HERE();
 			context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@
 static void mts_do_sg (struct urb* transfer)
 {
 	struct scatterlist * sg;
+	int status = transfer->status;
 	MTS_INT_INIT();
 
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-	if (unlikely(transfer->status)) {
-                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+	if (unlikely(status)) {
+                context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 		mts_transfer_cleanup(transfer);
         }
 
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index d72c42e..e9fdbc8 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@
 
 /* Structure to hold all of our device specific stuff */
 struct adu_device {
-	struct semaphore	sem; /* locks this structure */
+	struct mutex		mtx; /* locks this structure */
 	struct usb_device*	udev; /* save off the usb device pointer */
 	struct usb_interface*	interface;
 	unsigned char		minor; /* the starting minor number for this device */
@@ -178,17 +179,18 @@
 static void adu_interrupt_in_callback(struct urb *urb)
 {
 	struct adu_device *dev = urb->context;
+	int status = urb->status;
 
-	dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : enter, status %d", __FUNCTION__, status);
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
 
 	spin_lock(&dev->buflock);
 
-	if (urb->status != 0) {
-		if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+	if (status != 0) {
+		if ((status != -ENOENT) && (status != -ECONNRESET)) {
 			dbg(1," %s : nonzero status received: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 		}
 		goto exit;
 	}
@@ -216,21 +218,22 @@
 	wake_up_interruptible(&dev->read_wait);
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
-	dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
 {
 	struct adu_device *dev = urb->context;
+	int status = urb->status;
 
-	dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : enter, status %d", __FUNCTION__, status);
 	adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->status != 0) {
-		if ((urb->status != -ENOENT) &&
-		    (urb->status != -ECONNRESET)) {
+	if (status != 0) {
+		if ((status != -ENOENT) &&
+		    (status != -ECONNRESET)) {
 			dbg(1, " %s :nonzero status received: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 		}
 		goto exit;
 	}
@@ -240,7 +243,7 @@
 
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
-	dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +272,8 @@
 	}
 
 	/* lock this device */
-	if ((retval = down_interruptible(&dev->sem))) {
-		dbg(2, "%s : sem down failed", __FUNCTION__);
+	if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+		dbg(2, "%s : mutex lock failed", __FUNCTION__);
 		goto exit_no_device;
 	}
 
@@ -299,7 +302,7 @@
 		if (retval)
 			--dev->open_count;
 	}
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 
 exit_no_device:
 	dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +350,7 @@
 	}
 
 	/* lock our device */
-	down(&dev->sem); /* not interruptible */
+	mutex_lock(&dev->mtx); /* not interruptible */
 
 	if (dev->open_count <= 0) {
 		dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +360,7 @@
 
 	if (dev->udev == NULL) {
 		/* the device was unplugged before the file was released */
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 		adu_delete(dev);
 		dev = NULL;
 	} else {
@@ -367,7 +370,7 @@
 
 exit:
 	if (dev)
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
 	return retval;
 }
@@ -390,7 +393,7 @@
 	dev = file->private_data;
 	dbg(2," %s : dev=%p", __FUNCTION__, dev);
 	/* lock this object */
-	if (down_interruptible(&dev->sem))
+	if (mutex_lock_interruptible(&dev->mtx))
 		return -ERESTARTSYS;
 
 	/* verify that the device wasn't unplugged */
@@ -522,7 +525,7 @@
 
 exit:
 	/* unlock the device */
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
 	return retval;
@@ -543,7 +546,7 @@
 	dev = file->private_data;
 
 	/* lock this object */
-	retval = down_interruptible(&dev->sem);
+	retval = mutex_lock_interruptible(&dev->mtx);
 	if (retval)
 		goto exit_nolock;
 
@@ -571,9 +574,9 @@
 				retval = -EINTR;
 				goto exit;
 			}
-			up(&dev->sem);
+			mutex_unlock(&dev->mtx);
 			timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
-			retval = down_interruptible(&dev->sem);
+			retval = mutex_lock_interruptible(&dev->mtx);
 			if (retval) {
 				retval = bytes_written ? bytes_written : retval;
 				goto exit_nolock;
@@ -638,7 +641,7 @@
 
 exit:
 	/* unlock the device */
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 exit_nolock:
 
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +701,7 @@
 		goto exit;
 	}
 
-	init_MUTEX(&dev->sem);
+	mutex_init(&dev->mtx);
 	spin_lock_init(&dev->buflock);
 	dev->udev = udev;
 	init_waitqueue_head(&dev->read_wait);
@@ -835,16 +838,16 @@
 	usb_deregister_dev(interface, &adu_class);
 	dev->minor = 0;
 
-	down(&dev->sem); /* not interruptible */
+	mutex_lock(&dev->mtx); /* not interruptible */
 
 	/* if the device is not opened, then we clean up right now */
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
 	if (!dev->open_count) {
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 		adu_delete(dev);
 	} else {
 		dev->udev = NULL;
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 	}
 
 	dev_info(&interface->dev, "ADU device adutux%d now disconnected",
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index cf70c16..1cb56f2 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,9 +88,10 @@
 {
 	struct appledisplay *pdata = urb->context;
 	unsigned long flags;
+	int status = urb->status;
 	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -102,12 +103,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-			__FUNCTION__, urb->status);
+		dbg("%s - urb shuttingdown with status: %d",
+			__FUNCTION__, status);
 		return;
 	default:
 		dbg("%s - nonzero urb status received: %d",
-			__FUNCTION__, urb->status);
+			__FUNCTION__, status);
 		goto exit;
 	}
 
@@ -137,7 +138,7 @@
 
 static int appledisplay_bl_update_status(struct backlight_device *bd)
 {
-	struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+	struct appledisplay *pdata = bl_get_data(bd);
 	int retval;
 
 	pdata->msgdata[0] = 0x10;
@@ -158,7 +159,7 @@
 
 static int appledisplay_bl_get_brightness(struct backlight_device *bd)
 {
-	struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+	struct appledisplay *pdata = bl_get_data(bd);
 	int retval;
 
 	retval = usb_control_msg(
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 42d4e64..df7e1ec 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -862,14 +862,16 @@
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
 	int ret;
+	int status = urb->status;
+
         dbg ("auerswald_ctrlread_wretcomplete called");
-        dbg ("complete with status: %d", urb->status);
+        dbg ("complete with status: %d", status);
 	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
 	/* check if it is possible to advance */
-	if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+	if (!auerswald_status_retry(status) || !cp->usbdev) {
 		/* reuse the buffer */
-		err ("control dummy: transmission error %d, can not retry", urb->status);
+		err ("control dummy: transmission error %d, can not retry", status);
 		auerbuf_releasebuf (bp);
 		/* Wake up all processes waiting for a buffer */
 		wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@
         pauerswald_t  cp;
         pauerscon_t   scp;
         pauerbuf_t    bp  = (pauerbuf_t) urb->context;
+	int status = urb->status;
 	int ret;
+
         dbg ("auerswald_ctrlread_complete called");
 
 	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
 	/* check if there is valid data in this urb */
-        if (urb->status) {
-		dbg ("complete with non-zero status: %d", urb->status);
+        if (status) {
+		dbg ("complete with non-zero status: %d", status);
 		/* should we do a retry? */
-		if (!auerswald_status_retry (urb->status)
+		if (!auerswald_status_retry(status)
 		 || !cp->usbdev
 		 || (cp->version < AUV_RETRY)
                  || (bp->retries >= AU_RETRIES)) {
 			/* reuse the buffer */
-			err ("control read: transmission error %d, can not retry", urb->status);
+			err ("control read: transmission error %d, can not retry", status);
 			auerbuf_releasebuf (bp);
 			/* Wake up all processes waiting for a buffer */
 			wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@
         unsigned  int channelid;
         unsigned  int bytecount;
         int ret;
+	int status = urb->status;
         pauerbuf_t   bp = NULL;
         pauerswald_t cp = (pauerswald_t) urb->context;
 
         dbg ("%s called", __FUNCTION__);
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -987,10 +992,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
 		goto exit;
 	}
 
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index e0f122e..538b535 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
@@ -64,7 +65,7 @@
 * ftdi_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
 static int ftdi_instances = 0;
 static struct list_head ftdi_static_list;
 /*
@@ -199,10 +200,10 @@
         dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
         usb_put_dev(ftdi->udev);
         ftdi->disconnected += 1;
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_del_init(&ftdi->ftdi_list);
         ftdi_instances -= 1;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         kfree(ftdi->bulk_in_buffer);
         ftdi->bulk_in_buffer = NULL;
 }
@@ -746,10 +747,12 @@
 static void ftdi_elan_write_bulk_callback(struct urb *urb)
 {
         struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
-        if (urb->status && !(urb->status == -ENOENT || urb->status ==
-                -ECONNRESET || urb->status == -ESHUTDOWN)) {
+	int status = urb->status;
+
+	if (status && !(status == -ENOENT || status == -ECONNRESET ||
+	    status == -ESHUTDOWN)) {
                 dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
-                        "d\n", urb, urb->status);
+                        "d\n", urb, status);
         }
         usb_buffer_free(urb->dev, urb->transfer_buffer_length,
                 urb->transfer_buffer, urb->transfer_dma);
@@ -2780,10 +2783,10 @@
                 return -ENOMEM;
         }
         memset(ftdi, 0x00, sizeof(struct usb_ftdi));
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         ftdi_elan_init_kref(ftdi);
         init_MUTEX(&ftdi->sw_lock);
         ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2912,7 @@
         int result;
         printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
 	       __TIME__, __DATE__);
-        init_MUTEX(&ftdi_module_lock);
+        mutex_init(&ftdi_module_lock);
         INIT_LIST_HEAD(&ftdi_static_list);
         status_queue = create_singlethread_workqueue("ftdi-status-control");
 	if (!status_queue)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 28548d1..46d9f27 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -158,9 +158,10 @@
 	int read_idx;
 	int aux_idx;
 	int offset;
-	int status;
+	int status = urb->status;
+	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -213,10 +214,10 @@
 	wake_up_interruptible(&dev->read_wait);
 
 exit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
 		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
-			__FUNCTION__, status);
+			__FUNCTION__, retval);
 
 }
 
@@ -226,13 +227,15 @@
 static void iowarrior_write_callback(struct urb *urb)
 {
 	struct iowarrior *dev;
+	int status = urb->status;
+
 	dev = (struct iowarrior *)urb->context;
 	/* sync/async unlink faults aren't errors */
-	if (urb->status &&
-	    !(urb->status == -ENOENT ||
-	      urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+	if (status &&
+	    !(status == -ENOENT ||
+	      status == -ECONNRESET || status == -ESHUTDOWN)) {
 		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, urb->status);
+		    __func__, status);
 	}
 	/* free up our allocated buffer */
 	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5e950b9..8208496 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -219,16 +219,17 @@
 	struct ld_usb *dev = urb->context;
 	size_t *actual_buffer;
 	unsigned int next_ring_head;
+	int status = urb->status;
 	int retval;
 
-	if (urb->status) {
-		if (urb->status == -ENOENT ||
-		    urb->status == -ECONNRESET ||
-		    urb->status == -ESHUTDOWN) {
+	if (status) {
+		if (status == -ENOENT ||
+		    status == -ECONNRESET ||
+		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
 			dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-				 __FUNCTION__, urb->status);
+				 __FUNCTION__, status);
 			spin_lock(&dev->rbsl);
 			goto resubmit; /* maybe we can recover */
 		}
@@ -275,14 +276,15 @@
 static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
 	struct ld_usb *dev = urb->context;
+	int status = urb->status;
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status && !(urb->status == -ENOENT ||
-			     urb->status == -ECONNRESET ||
-			     urb->status == -ESHUTDOWN))
+	if (status && !(status == -ENOENT ||
+			status == -ECONNRESET ||
+			status == -ESHUTDOWN))
 		dbg_info(&dev->intf->dev,
 			 "%s - nonzero write interrupt status received: %d\n",
-			 __FUNCTION__, urb->status);
+			 __FUNCTION__, status);
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 2ed0dae..561970b 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -742,19 +742,20 @@
 static void tower_interrupt_in_callback (struct urb *urb)
 {
 	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+	int status = urb->status;
 	int retval;
 
-	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->status) {
-		if (urb->status == -ENOENT ||
-		    urb->status == -ECONNRESET ||
-		    urb->status == -ESHUTDOWN) {
+	if (status) {
+		if (status == -ENOENT ||
+		    status == -ECONNRESET ||
+		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
-			dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+			dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
 			goto resubmit; /* maybe we can recover */
 		}
 	}
@@ -788,7 +789,7 @@
 	wake_up_interruptible (&dev->read_wait);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -798,23 +799,24 @@
 static void tower_interrupt_out_callback (struct urb *urb)
 {
 	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+	int status = urb->status;
 
-	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status && !(urb->status == -ENOENT ||
-			     urb->status == -ECONNRESET ||
-			     urb->status == -ESHUTDOWN)) {
+	if (status && !(status == -ENOENT ||
+			status == -ECONNRESET ||
+			status == -ESHUTDOWN)) {
 		dbg(1, "%s - nonzero write bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 	}
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 371bf2b..aa9bcce 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -305,9 +305,10 @@
 	struct interfacekit *kit = urb->context;
 	unsigned char *buffer = kit->data;
 	int i, level, sensor;
-	int status;
+	int retval;
+	int status = urb->status;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -377,11 +378,11 @@
 		schedule_delayed_work(&kit->do_notify, 0);
 
 resubmit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
-		err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
 			kit->udev->bus->bus_name,
-			kit->udev->devpath, status);
+			kit->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 5727e1e..df0ebcd 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -95,9 +95,10 @@
 	struct motorcontrol *mc = urb->context;
 	unsigned char *buffer = mc->data;
 	int i, level;
-	int status;
+	int retval;
+	int status = urb->status;;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -151,12 +152,12 @@
 		schedule_delayed_work(&mc->do_notify, 0);
 
 resubmit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
 		dev_err(&mc->intf->dev,
-			"can't resubmit intr, %s-%s/motorcontrol0, status %d",
+			"can't resubmit intr, %s-%s/motorcontrol0, retval %d",
 			mc->udev->bus->bus_name,
-			mc->udev->devpath, status);
+			mc->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 504f722..7198420 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -176,16 +176,17 @@
 static void lcd_write_bulk_callback(struct urb *urb)
 {
 	struct usb_lcd *dev;
+	int status = urb->status;
 
 	dev = (struct usb_lcd *)urb->context;
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status &&
-	    !(urb->status == -ENOENT ||
-	      urb->status == -ECONNRESET ||
-              urb->status == -ESHUTDOWN)) {
+	if (status &&
+	    !(status == -ENOENT ||
+	      status == -ECONNRESET ||
+              status == -ESHUTDOWN)) {
 		dbg("USBLCD: %s - nonzero write bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 	}
 
 	/* free up our allocated buffer */
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index fb32186..e901d31 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -768,8 +768,8 @@
 
 		/* some faults are allowed, not required */
 		if (subcase->expected > 0 && (
-			  ((urb->status == -subcase->expected	/* happened */
-			   || urb->status == 0))))		/* didn't */
+			  ((status == -subcase->expected	/* happened */
+			   || status == 0))))			/* didn't */
 			status = 0;
 		/* sometimes more than one fault is allowed */
 		else if (subcase->number == 12 && status == -EPIPE)
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 1a60f9c..2734fe2 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -111,12 +111,13 @@
 	struct uss720_async_request *rq;
 	struct parport *pp;
 	struct parport_uss720_private *priv;
+	int status = urb->status;
 
 	rq = urb->context;
 	priv = rq->priv;
 	pp = priv->pp;
-	if (urb->status) {
-		err("async_complete: urb error %d", urb->status);
+	if (status) {
+		err("async_complete: urb error %d", status);
 	} else if (rq->dr.bRequest == 3) {
 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0d39036..b867090 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2794,16 +2794,14 @@
 
 	dbg ("%s", __FUNCTION__);
 
-	for (i=0; i < serial->num_ports; ++i) {
+	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = usb_get_serial_port_data(serial->port[i]);
 		edge_remove_sysfs_attrs(edge_port->port);
-		if (edge_port) {
-			edge_buf_free(edge_port->ep_out_buf);
-			kfree(edge_port);
-		}
+		edge_buf_free(edge_port->ep_out_buf);
+		kfree(edge_port);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
-	kfree (usb_get_serial_data(serial));
+	kfree(usb_get_serial_data(serial));
 	usb_set_serial_data(serial, NULL);
 }
 
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 231b584..01e811b 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -110,11 +110,6 @@
 
 	dbg("%s"," : Entering\n");
 
-	if (!urb) {
-		dbg("%s","Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	switch (status) {
 	case 0:
 		/* success */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 37f41f5..f76480f 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -436,11 +436,6 @@
 	int result = 0;
 	int status = urb->status;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	mos7840_port = (struct moschip_port *)urb->context;
 
 	switch (status) {
@@ -525,10 +520,6 @@
 	int status = urb->status;
 
 	dbg("%s", " : Entering\n");
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
 
 	switch (status) {
 	case 0:
@@ -676,11 +667,6 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	if (status) {
 		dbg("nonzero read bulk status received: %d", status);
 		return;
@@ -753,11 +739,6 @@
 	int status = urb->status;
 	int i;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	mos7840_port = (struct moschip_port *)urb->context;
 	spin_lock(&mos7840_port->pool_lock);
 	for (i = 0; i < NUM_URBS; i++) {
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index e7db203..0794ccd 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006  Kevin Lloyd <linux@sierrawireless.com>
+  Copyright (C) 2006, 2007  Kevin Lloyd <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
@@ -12,10 +12,9 @@
 
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
 */
 
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -28,23 +27,98 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#define SWIMS_USB_REQUEST_SetMode	0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode	0x40
+#define SWIMS_USB_INDEX_SetMode		0x0000
+#define SWIMS_SET_MODE_Modem		0x0001
+
+/* per port private data */
+#define N_IN_URB	4
+#define N_OUT_URB	4
+#define IN_BUFLEN	4096
+
+static int debug;
+
+enum devicetype {
+	DEVICE_3_PORT =		0,
+	DEVICE_1_PORT =		1,
+	DEVICE_INSTALLER =	2,
+};
+
+int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+	int result;
+	dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			0x00,			/* __u8 request      */
+			0x40,			/* __u8 request type */
+			swiState,		/* __u16 value       */
+			0,			/* __u16 index       */
+			NULL,			/* void *data        */
+			0,			/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);	/* int timeout 	     */
+	return result;
+}
+
+int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+	int result;
+	dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			SWIMS_USB_REQUEST_SetMode,	/* __u8 request      */
+			SWIMS_USB_REQUEST_TYPE_SetMode,	/* __u8 request type */
+			eSocMode,			/* __u16 value       */
+			SWIMS_USB_INDEX_SetMode,	/* __u16 index       */
+			NULL,				/* void *data        */
+			0,				/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
+	return result;
+}
+
+int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+	int result;
+	struct usb_device *udev;
+
+	udev = usb_get_dev(interface_to_usbdev(iface));
+
+	/* Check if in installer mode */
+	if (id->driver_info == DEVICE_INSTALLER) {
+		dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+		result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+		/*We do not want to bind to the device when in installer mode*/
+		return -EIO;
+	}
+
+	return usb_serial_probe(iface, id);
+}
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
 	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
-	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless AirCard 595U */
 	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U */
+
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
+	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
+	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
+	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
+	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
+	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880 E */
+	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881 E */
 
-	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-	{ USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+	{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+	{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+	{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +132,36 @@
 static struct usb_device_id id_table_3port [] = {
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
 	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
-	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless AirCard 595U */
 	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U*/
+
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
+	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
+	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
+	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
+	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
+	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880E */
+	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881E */
 	{ }
 };
 
 static struct usb_driver sierra_driver = {
 	.name       = "sierra",
-	.probe      = usb_serial_probe,
+	.probe      = sierra_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table   = id_table,
 	.no_dynamic_id = 	1,
 };
 
 
-static int debug;
-
-/* per port private data */
-#define N_IN_URB	4
-#define N_OUT_URB	4
-#define IN_BUFLEN	4096
-
 struct sierra_port_private {
 	spinlock_t lock;	/* lock the structure */
 	int outstanding_urbs;	/* number of out urbs in flight */
@@ -421,7 +496,6 @@
 	int i;
 	struct urb *urb;
 	int result;
-	__u16 set_mode_dzero = 0x0000;
 
 	portdata = usb_get_serial_port_data(port);
 
@@ -457,12 +531,6 @@
 
 	port->tty->low_latency = 1;
 
-	/* set mode to D0 */
-	result = usb_control_msg(serial->dev,
-				 usb_rcvctrlpipe(serial->dev, 0),
-				 0x00, 0x40, set_mode_dzero, 0, NULL,
-				 0, USB_CTRL_SET_TIMEOUT);
-
 	sierra_send_setup(port);
 
 	/* start up the interrupt endpoint if we have one */
@@ -510,6 +578,9 @@
 
 	dbg("%s", __FUNCTION__);
 
+	/*Set Device mode to D0 */
+	sierra_set_power_state(serial->dev, 0x0000);
+
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 1628cb2..9a410b5 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -46,43 +46,43 @@
  */
 int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-  int ret;
+	int ret;
 
-  if(srb == NULL)
-    return USB_STOR_TRANSPORT_ERROR;
+	if (srb == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
 
-  US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+	US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
 
-  switch(srb->device->lun) {
-  case 0:
+	switch (srb->device->lun) {
+		case 0:
 
-    /*
-     * LUN 0 corresponds to the CompactFlash card reader.
-     */
-    ret = usb_stor_CB_transport(srb, us);
-    break;
+			/*
+			 * LUN 0 corresponds to the CompactFlash card reader.
+			 */
+			ret = usb_stor_CB_transport(srb, us);
+			break;
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
-  case 1:
+		case 1:
 
-    /*
-     * LUN 1 corresponds to the SmartMedia card reader.
-     */
+			/*
+			 * LUN 1 corresponds to the SmartMedia card reader.
+			 */
 
-    /*
-     * Set the LUN to 0 (just in case).
-     */
-    srb->device->lun = 0; us->srb->device->lun = 0;
-    ret = sddr09_transport(srb, us);
-    srb->device->lun = 1; us->srb->device->lun = 1;
-    break;
+			/*
+			 * Set the LUN to 0 (just in case).
+			 */
+			srb->device->lun = 0; us->srb->device->lun = 0;
+			ret = sddr09_transport(srb, us);
+			srb->device->lun = 1; us->srb->device->lun = 1;
+			break;
 
 #endif
 
-  default:
-    US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
-    ret = USB_STOR_TRANSPORT_ERROR;
-    break;
-  }
-  return ret;
+		default:
+			US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+			ret = USB_STOR_TRANSPORT_ERROR;
+			break;
+	}
+	return ret;
 }
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d353693..dfd42fe 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -57,9 +57,10 @@
 	struct usb_onetouch *onetouch = urb->context;
 	signed char *data = onetouch->data;
 	struct input_dev *dev = onetouch->dev;
-	int status;
+	int status = urb->status;
+	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -75,11 +76,11 @@
 	input_sync(dev);
 
 resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("can't resubmit intr, %s-%s/input0, retval %d",
 			onetouch->udev->bus->bus_name,
-			onetouch->udev->devpath, status);
+			onetouch->udev->devpath, retval);
 }
 
 static int usb_onetouch_open(struct input_dev *dev)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b6bf31a..a624e72 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -313,6 +313,13 @@
 		US_SC_DEVICE, US_PR_DEVICE,NULL,
 		US_FL_NOT_LOCKABLE ),
 
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV(  0x04b0, 0x0401, 0x0200, 0x0200,
+		"NIKON",
+		"NIKON DSC D100",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
 /* Reported by Andreas Bockhold <andreas@bockionline.de> */
 UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
 		"NIKON",
@@ -1384,6 +1391,17 @@
 		US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
 		0 ),
 
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV(  0x1199, 0x0fff, 0x0000, 0x9999,
+		"Sierra Wireless",
+		"USB MMC Storage",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE),
+
 /* Reported by Jaco Kroon <jaco@kroon.co.za>
  * The usb-storage module found on the Digitech GNX4 (and supposedly other
  * devices) misbehaves and causes a bunch of invalid I/O errors.
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0c5644bb..564cc9b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -12,6 +12,13 @@
        tristate
        default n
 
+config VIDEO_OUTPUT_CONTROL
+	tristate "Lowlevel video output switch controls"
+	default m
+	help
+	  This framework adds support for low-level control of the video 
+	  output switch.
+
 config FB
 	tristate "Support for frame buffer devices"
 	---help---
@@ -849,6 +856,16 @@
 	  Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
 	  to let frame buffer in external SDRAM.
 
+config FB_ATMEL_STN
+	bool "Use a STN display with AT91/AT32 LCD Controller"
+	depends on FB_ATMEL && MACH_AT91SAM9261EK
+	default n
+	help
+	  Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
+	  Controller. Say N if you want to connect a TFT.
+
+	  If unsure, say N.
+
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
 	depends on FB && PCI
@@ -1796,13 +1813,14 @@
 	select FB_SYS_COPYAREA
 	select FB_SYS_IMAGEBLIT
 	select FB_SYS_FOPS
+	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	---help---
 	  Include support for the virtual frame buffer in the PS3 platform.
 
 config FB_PS3_DEFAULT_SIZE_M
 	int "PS3 default frame buffer size (in MiB)"
 	depends on FB_PS3
-	default 18
+	default 9
 	---help---
 	  This is the default size (in MiB) of the virtual frame buffer in
 	  the PS3.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a562f9d..518933d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -123,3 +123,6 @@
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+
+#video output switch sysfs driver
+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index e1d5bd0..235b618 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -79,6 +79,29 @@
 	.accel		= FB_ACCEL_NONE,
 };
 
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+	unsigned long value;
+
+	if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+		return xres;
+
+	value = xres;
+	if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+		/* STN display */
+		if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+			value *= 3;
+		}
+		if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+		   || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+		      && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+			value = DIV_ROUND_UP(value, 4);
+		else
+			value = DIV_ROUND_UP(value, 8);
+	}
+
+	return value;
+}
 
 static void atmel_lcdfb_update_dma(struct fb_info *info,
 			       struct fb_var_screeninfo *var)
@@ -181,6 +204,7 @@
 	var->xoffset = var->yoffset = 0;
 
 	switch (var->bits_per_pixel) {
+	case 1:
 	case 2:
 	case 4:
 	case 8:
@@ -195,8 +219,11 @@
 		var->blue.offset = 10;
 		var->red.length = var->green.length = var->blue.length = 5;
 		break;
-	case 24:
 	case 32:
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		/* fall through */
+	case 24:
 		var->red.offset = 0;
 		var->green.offset = 8;
 		var->blue.offset = 16;
@@ -228,8 +255,10 @@
 static int atmel_lcdfb_set_par(struct fb_info *info)
 {
 	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long hozval_linesz;
 	unsigned long value;
 	unsigned long clk_value_khz;
+	unsigned long bits_per_line;
 
 	dev_dbg(info->device, "%s:\n", __func__);
 	dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
@@ -241,12 +270,15 @@
 
 	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
 
-	if (info->var.bits_per_pixel <= 8)
+	if (info->var.bits_per_pixel == 1)
+		info->fix.visual = FB_VISUAL_MONO01;
+	else if (info->var.bits_per_pixel <= 8)
 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 	else
 		info->fix.visual = FB_VISUAL_TRUECOLOR;
 
-	info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+	bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+	info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
 
 	/* Re-initialize the DMA engine... */
 	dev_dbg(info->device, "  * update DMA engine\n");
@@ -262,18 +294,21 @@
 	/* Set pixel clock */
 	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
 
-	value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
-
-	if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
-		value++;
+	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
 
 	value = (value / 2) - 1;
+	dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n", value);
 
 	if (value <= 0) {
 		dev_notice(info->device, "Bypassing pixel clock divider\n");
 		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-	} else
+	} else {
 		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+		info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
+		dev_dbg(info->device, "  updated pixclk:     %lu KHz\n",
+					PICOS2KHZ(info->var.pixclock));
+	}
+
 
 	/* Initialize control register 2 */
 	value = sinfo->default_lcdcon2;
@@ -311,9 +346,14 @@
 	dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
 	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
 
+	/* Horizontal value (aka line size) */
+	hozval_linesz = compute_hozval(info->var.xres,
+					lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
 	/* Display size */
-	value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
 	value |= info->var.yres - 1;
+	dev_dbg(info->device, "  * LCDFRMCFG = %08lx\n", value);
 	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
 
 	/* FIFO Threshold: Use formula from data sheet */
@@ -421,6 +461,15 @@
 			ret = 0;
 		}
 		break;
+
+	case FB_VISUAL_MONO01:
+		if (regno < 2) {
+			val = (regno == 0) ? 0x00 : 0x1F;
+			lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+			ret = 0;
+		}
+		break;
+
 	}
 
 	return ret;
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 7fea4d8..cfcbe37 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1733,7 +1733,7 @@
 
 static int aty128_bl_update_status(struct backlight_device *bd)
 {
-	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+	struct aty128fb_par *par = bl_get_data(bd);
 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
 	int level;
 
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 0c7bf75..bc6f009 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2141,7 +2141,7 @@
 
 static int aty_bl_update_status(struct backlight_device *bd)
 {
-	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+	struct atyfb_par *par = bl_get_data(bd);
 	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
 	int level;
 
@@ -2913,10 +2913,6 @@
 	int node, len, i, j, ret;
 	u32 mem, chip_id;
 
-	/* Do not attach when we have a serial console. */
-	if (!con_is_present())
-		return -ENXIO;
-
 	/*
 	 * Map memory-mapped registers.
 	 */
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 0be25fa..1a056ad 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -47,7 +47,7 @@
 
 static int radeon_bl_update_status(struct backlight_device *bd)
 {
-	struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+	struct radeon_bl_privdata *pdata = bl_get_data(bd);
 	struct radeonfb_info *rinfo = pdata->rinfo;
 	u32 lvds_gen_cntl, tmpPixclksCntl;
 	int level;
@@ -206,7 +206,7 @@
 	if (bd) {
 		struct radeon_bl_privdata *pdata;
 
-		pdata = class_get_devdata(&bd->class_dev);
+		pdata = bl_get_data(bd);
 		backlight_device_unregister(bd);
 		kfree(pdata);
 		rinfo->info->bl_dev = NULL;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index fbef663..2580f5f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,17 +8,9 @@
 	  Enable this to be able to choose the drivers for controlling the
 	  backlight and the LCD panel on some platforms, for example on PDAs.
 
-config BACKLIGHT_CLASS_DEVICE
-        tristate "Lowlevel Backlight controls"
-	depends on BACKLIGHT_LCD_SUPPORT
-	default m
-	help
-	  This framework adds support for low-level control of the LCD
-          backlight. This includes support for brightness and power.
-
-	  To have support for your specific LCD panel you will have to
-	  select the proper drivers which depend on this option.
-
+#
+# LCD
+#
 config LCD_CLASS_DEVICE
         tristate "Lowlevel LCD controls"
 	depends on BACKLIGHT_LCD_SUPPORT
@@ -32,6 +24,20 @@
 	  To have support for your specific LCD panel you will have to
 	  select the proper drivers which depend on this option.
 
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
+	depends on BACKLIGHT_LCD_SUPPORT
+	default m
+	help
+	  This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
 config BACKLIGHT_CORGI
 	tristate "Sharp Corgi Backlight Driver (SL Series)"
 	depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 7e06223..b26de8c 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -69,18 +69,20 @@
 }
 #endif /* CONFIG_FB */
 
-static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_power(struct device *dev,
+		struct device_attribute *attr,char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.power);
 }
 
-static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_power(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 	int power = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -101,18 +103,20 @@
 	return rc;
 }
 
-static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.brightness);
 }
 
-static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_brightness(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 	int brightness = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -138,18 +142,19 @@
 	return rc;
 }
 
-static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_max_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.max_brightness);
 }
 
-static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
-						char *buf)
+static ssize_t backlight_show_actual_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	mutex_lock(&bd->ops_lock);
 	if (bd->ops && bd->ops->get_brightness)
@@ -159,31 +164,22 @@
 	return rc;
 }
 
-static void backlight_class_release(struct class_device *dev)
+struct class *backlight_class;
+
+static void bl_device_release(struct device *dev)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
 	kfree(bd);
 }
 
-static struct class backlight_class = {
-	.name = "backlight",
-	.release = backlight_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)			\
-{							 	\
-	.attr	= { .name = __stringify(_name), .mode = _mode }, \
-	.show	= _show,					\
-	.store	= _store,					\
-}
-
-static const struct class_device_attribute bl_class_device_attributes[] = {
-	DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
-	DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+static struct device_attribute bl_device_attributes[] = {
+	__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
+	__ATTR(brightness, 0644, backlight_show_brightness,
 		     backlight_store_brightness),
-	DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
 		     NULL),
-	DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR_NULL,
 };
 
 /**
@@ -191,22 +187,20 @@
  *   backlight_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @devdata: an optional pointer to be stored for private driver use. The
+ *   methods may retrieve it by using bl_get_data(bd).
  * @ops: the backlight operations structure.
  *
- * Creates and registers new backlight class_device. Returns either an
+ * Creates and registers new backlight device. Returns either an
  * ERR_PTR() or a pointer to the newly allocated device.
  */
 struct backlight_device *backlight_device_register(const char *name,
-	struct device *dev,
-	void *devdata,
-	struct backlight_ops *ops)
+		struct device *parent, void *devdata, struct backlight_ops *ops)
 {
-	int i, rc;
 	struct backlight_device *new_bd;
+	int rc;
 
-	pr_debug("backlight_device_alloc: name=%s\n", name);
+	pr_debug("backlight_device_register: name=%s\n", name);
 
 	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
 	if (!new_bd)
@@ -214,13 +208,14 @@
 
 	mutex_init(&new_bd->update_lock);
 	mutex_init(&new_bd->ops_lock);
-	new_bd->ops = ops;
-	new_bd->class_dev.class = &backlight_class;
-	new_bd->class_dev.dev = dev;
-	strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
-	class_set_devdata(&new_bd->class_dev, devdata);
 
-	rc = class_device_register(&new_bd->class_dev);
+	new_bd->dev.class = backlight_class;
+	new_bd->dev.parent = parent;
+	new_bd->dev.release = bl_device_release;
+	strlcpy(new_bd->dev.bus_id, name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_bd->dev, devdata);
+
+	rc = device_register(&new_bd->dev);
 	if (rc) {
 		kfree(new_bd);
 		return ERR_PTR(rc);
@@ -228,23 +223,11 @@
 
 	rc = backlight_register_fb(new_bd);
 	if (rc) {
-		class_device_unregister(&new_bd->class_dev);
+		device_unregister(&new_bd->dev);
 		return ERR_PTR(rc);
 	}
 
-
-	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
-		rc = class_device_create_file(&new_bd->class_dev,
-					      &bl_class_device_attributes[i]);
-		if (rc) {
-			while (--i >= 0)
-				class_device_remove_file(&new_bd->class_dev,
-							 &bl_class_device_attributes[i]);
-			class_device_unregister(&new_bd->class_dev);
-			/* No need to kfree(new_bd) since release() method was called */
-			return ERR_PTR(rc);
-		}
-	}
+	new_bd->ops = ops;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 	mutex_lock(&pmac_backlight_mutex);
@@ -265,42 +248,40 @@
  */
 void backlight_device_unregister(struct backlight_device *bd)
 {
-	int i;
-
 	if (!bd)
 		return;
 
-	pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
-
 #ifdef CONFIG_PMAC_BACKLIGHT
 	mutex_lock(&pmac_backlight_mutex);
 	if (pmac_backlight == bd)
 		pmac_backlight = NULL;
 	mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
-		class_device_remove_file(&bd->class_dev,
-					 &bl_class_device_attributes[i]);
-
 	mutex_lock(&bd->ops_lock);
 	bd->ops = NULL;
 	mutex_unlock(&bd->ops_lock);
 
 	backlight_unregister_fb(bd);
-
-	class_device_unregister(&bd->class_dev);
+	device_unregister(&bd->dev);
 }
 EXPORT_SYMBOL(backlight_device_unregister);
 
 static void __exit backlight_class_exit(void)
 {
-	class_unregister(&backlight_class);
+	class_destroy(backlight_class);
 }
 
 static int __init backlight_class_init(void)
 {
-	return class_register(&backlight_class);
+	backlight_class = class_create(THIS_MODULE, "backlight");
+	if (IS_ERR(backlight_class)) {
+		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+				PTR_ERR(backlight_class));
+		return PTR_ERR(backlight_class);
+	}
+
+	backlight_class->dev_attrs = bl_device_attributes;
+	return 0;
 }
 
 /*
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index e9bbc34..b7904da 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -174,7 +174,7 @@
 	struct cr_panel *crp;
 	u8 dev_en;
 
-	crp = kzalloc(sizeof(crp), GFP_KERNEL);
+	crp = kzalloc(sizeof(*crp), GFP_KERNEL);
 	if (crp == NULL)
 		return -ENOMEM;
 
@@ -202,7 +202,7 @@
 	}
 
 	crp->cr_lcd_device = lcd_device_register("cr-lcd",
-							&pdev->dev,
+							&pdev->dev, NULL,
 							&cr_lcd_ops);
 
 	if (IS_ERR(crp->cr_lcd_device)) {
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 648b53c..6f652c6 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -61,10 +61,11 @@
 }
 #endif /* CONFIG_FB */
 
-static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	int rc;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	mutex_lock(&ld->ops_lock);
 	if (ld->ops && ld->ops->get_power)
@@ -76,11 +77,12 @@
 	return rc;
 }
 
-static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_power(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 	int power = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -100,10 +102,11 @@
 	return rc;
 }
 
-static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_contrast(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	mutex_lock(&ld->ops_lock);
 	if (ld->ops && ld->ops->get_contrast)
@@ -113,11 +116,12 @@
 	return rc;
 }
 
-static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_contrast(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 	int contrast = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -137,53 +141,45 @@
 	return rc;
 }
 
-static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_max_contrast(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	return sprintf(buf, "%d\n", ld->props.max_contrast);
 }
 
-static void lcd_class_release(struct class_device *dev)
+struct class *lcd_class;
+
+static void lcd_device_release(struct device *dev)
 {
 	struct lcd_device *ld = to_lcd_device(dev);
 	kfree(ld);
 }
 
-static struct class lcd_class = {
-	.name = "lcd",
-	.release = lcd_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)			\
-{							 	\
-	.attr	= { .name = __stringify(_name), .mode = _mode }, \
-	.show	= _show,					\
-	.store	= _store,					\
-}
-
-static const struct class_device_attribute lcd_class_device_attributes[] = {
-	DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
-	DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
-	DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+static struct device_attribute lcd_device_attributes[] = {
+	__ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
+	__ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+	__ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+	__ATTR_NULL,
 };
 
 /**
  * lcd_device_register - register a new object of lcd_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @devdata: an optional pointer to be stored in the device. The
+ *   methods may retrieve it by using lcd_get_data(ld).
  * @ops: the lcd operations structure.
  *
- * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * Creates and registers a new lcd device. Returns either an ERR_PTR()
  * or a pointer to the newly allocated device.
  */
-struct lcd_device *lcd_device_register(const char *name, void *devdata,
-				       struct lcd_ops *ops)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
+		void *devdata, struct lcd_ops *ops)
 {
-	int i, rc;
 	struct lcd_device *new_ld;
+	int rc;
 
 	pr_debug("lcd_device_register: name=%s\n", name);
 
@@ -193,12 +189,14 @@
 
 	mutex_init(&new_ld->ops_lock);
 	mutex_init(&new_ld->update_lock);
-	new_ld->ops = ops;
-	new_ld->class_dev.class = &lcd_class;
-	strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
-	class_set_devdata(&new_ld->class_dev, devdata);
 
-	rc = class_device_register(&new_ld->class_dev);
+	new_ld->dev.class = lcd_class;
+	new_ld->dev.parent = parent;
+	new_ld->dev.release = lcd_device_release;
+	strlcpy(new_ld->dev.bus_id, name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_ld->dev, devdata);
+
+	rc = device_register(&new_ld->dev);
 	if (rc) {
 		kfree(new_ld);
 		return ERR_PTR(rc);
@@ -206,22 +204,11 @@
 
 	rc = lcd_register_fb(new_ld);
 	if (rc) {
-		class_device_unregister(&new_ld->class_dev);
+		device_unregister(&new_ld->dev);
 		return ERR_PTR(rc);
 	}
 
-	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
-		rc = class_device_create_file(&new_ld->class_dev,
-					      &lcd_class_device_attributes[i]);
-		if (rc) {
-			while (--i >= 0)
-				class_device_remove_file(&new_ld->class_dev,
-							 &lcd_class_device_attributes[i]);
-			class_device_unregister(&new_ld->class_dev);
-			/* No need to kfree(new_ld) since release() method was called */
-			return ERR_PTR(rc);
-		}
-	}
+	new_ld->ops = ops;
 
 	return new_ld;
 }
@@ -235,33 +222,34 @@
  */
 void lcd_device_unregister(struct lcd_device *ld)
 {
-	int i;
-
 	if (!ld)
 		return;
 
-	pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
-
-	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
-		class_device_remove_file(&ld->class_dev,
-					 &lcd_class_device_attributes[i]);
-
 	mutex_lock(&ld->ops_lock);
 	ld->ops = NULL;
 	mutex_unlock(&ld->ops_lock);
 	lcd_unregister_fb(ld);
-	class_device_unregister(&ld->class_dev);
+
+	device_unregister(&ld->dev);
 }
 EXPORT_SYMBOL(lcd_device_unregister);
 
 static void __exit lcd_class_exit(void)
 {
-	class_unregister(&lcd_class);
+	class_destroy(lcd_class);
 }
 
 static int __init lcd_class_init(void)
 {
-	return class_register(&lcd_class);
+	lcd_class = class_create(THIS_MODULE, "lcd");
+	if (IS_ERR(lcd_class)) {
+		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+				PTR_ERR(lcd_class));
+		return PTR_ERR(lcd_class);
+	}
+
+	lcd_class->dev_attrs = lcd_device_attributes;
+	return 0;
 }
 
 /*
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f46fe95..d18b73a 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -187,7 +187,11 @@
 	}
 }
 
-static void vgacon_scrollback_startup(void)
+/*
+ * Called only duing init so call of alloc_bootmen is ok.
+ * Marked __init_refok to silence modpost.
+ */
+static void __init_refok vgacon_scrollback_startup(void)
 {
 	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
 					  * 1024);
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a481..b87ea21 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@
 	if (fb_get_options("igafb", NULL))
 		return -ENODEV;
 
-        /* Do not attach when we have a serial console. */
-        if (!con_is_present())
-                return -ENXIO;
-
         pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
                                PCI_DEVICE_ID_INTERG_1682, 0);
 	if (pdev == NULL) {
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 43f62d8..443e3c8 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -50,7 +50,7 @@
 
 static int nvidia_bl_update_status(struct backlight_device *bd)
 {
-	struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+	struct nvidia_par *par = bl_get_data(bd);
 	u32 tmp_pcrt, tmp_pmc, fpcontrol;
 	int level;
 
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 3972aa8..646ec82 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1067,7 +1067,7 @@
 	info->fix.smem_len = ps3fb_videomemory.size - offset;
 	info->pseudo_palette = info->par;
 	info->par = NULL;
-	info->flags = FBINFO_FLAG_DEFAULT;
+	info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
 
 	retval = fb_alloc_cmap(&info->cmap, 256, 0);
 	if (retval < 0)
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 0fe5478..5c47968 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -307,7 +307,7 @@
 
 static int riva_bl_update_status(struct backlight_device *bd)
 {
-	struct riva_par *par = class_get_devdata(&bd->class_dev);
+	struct riva_par *par = bl_get_data(bd);
 	U032 tmp_pcrt, tmp_pmc;
 	int level;
 
@@ -2146,7 +2146,7 @@
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-static int __init rivafb_setup(char *options)
+static int __devinit rivafb_setup(char *options)
 {
 	char *this_opt;
 
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 1b36f45..8ccee9e 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -792,6 +792,7 @@
 {
 	struct msghdr msg;
 	struct iovec iov[1];
+	int n;
 
 	_enter("");
 
@@ -806,22 +807,20 @@
 	msg.msg_flags		= 0;
 
 	call->state = AFS_CALL_AWAIT_ACK;
-	switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
-	case 0:
+	n = rxrpc_kernel_send_data(call->rxcall, &msg, len);
+	if (n >= 0) {
 		_leave(" [replied]");
 		return;
-
-	case -ENOMEM:
+	}
+	if (n == -ENOMEM) {
 		_debug("oom");
 		rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
-	default:
-		rxrpc_kernel_end_call(call->rxcall);
-		call->rxcall = NULL;
-		call->type->destructor(call);
-		afs_free_call(call);
-		_leave(" [error]");
-		return;
 	}
+	rxrpc_kernel_end_call(call->rxcall);
+	call->rxcall = NULL;
+	call->type->destructor(call);
+	afs_free_call(call);
+	_leave(" [error]");
 }
 
 /*
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index ba24cb2..4482a06 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -45,7 +45,7 @@
 
 static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(struct file *);
-static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
+static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
 
 /*
  * If we don't support core dumping, then supply a NULL so we
@@ -80,7 +80,7 @@
 		.hasvdso	= 1
 };
 
-#define BAD_ADDR(x) IS_ERR_VALUE(x)
+#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
 
 static int set_brk(unsigned long start, unsigned long end)
 {
@@ -295,70 +295,33 @@
 #ifndef elf_map
 
 static unsigned long elf_map(struct file *filep, unsigned long addr,
-		struct elf_phdr *eppnt, int prot, int type,
-		unsigned long total_size)
+		struct elf_phdr *eppnt, int prot, int type)
 {
 	unsigned long map_addr;
-	unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
-	unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
-	addr = ELF_PAGESTART(addr);
-	size = ELF_PAGEALIGN(size);
-
-	/* mmap() will return -EINVAL if given a zero size, but a
-	 * segment with zero filesize is perfectly valid */
-	if (!size)
-		return addr;
+	unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr);
 
 	down_write(&current->mm->mmap_sem);
-	/*
-	* total_size is the size of the ELF (interpreter) image.
-	* The _first_ mmap needs to know the full size, otherwise
-	* randomization might put this image into an overlapping
-	* position with the ELF binary image. (since size < total_size)
-	* So we first map the 'big' image - and unmap the remainder at
-	* the end. (which unmap is needed for ELF images with holes.)
-	*/
-	if (total_size) {
-		total_size = ELF_PAGEALIGN(total_size);
-		map_addr = do_mmap(filep, addr, total_size, prot, type, off);
-		if (!BAD_ADDR(map_addr))
-			do_munmap(current->mm, map_addr+size, total_size-size);
-	} else
-		map_addr = do_mmap(filep, addr, size, prot, type, off);
-
+	/* mmap() will return -EINVAL if given a zero size, but a
+	 * segment with zero filesize is perfectly valid */
+	if (eppnt->p_filesz + pageoffset)
+		map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+				   eppnt->p_filesz + pageoffset, prot, type,
+				   eppnt->p_offset - pageoffset);
+	else
+		map_addr = ELF_PAGESTART(addr);
 	up_write(&current->mm->mmap_sem);
 	return(map_addr);
 }
 
 #endif /* !elf_map */
 
-static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
-{
-	int i, first_idx = -1, last_idx = -1;
-
-	for (i = 0; i < nr; i++) {
-		if (cmds[i].p_type == PT_LOAD) {
-			last_idx = i;
-			if (first_idx == -1)
-				first_idx = i;
-		}
-	}
-	if (first_idx == -1)
-		return 0;
-
-	return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
-				ELF_PAGESTART(cmds[first_idx].p_vaddr);
-}
-
-
 /* This is much more generalized than the library routine read function,
    so we keep this separate.  Technically the library read function
    is only provided so that we can read a.out libraries that have
    an ELF header */
 
 static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
-		struct file *interpreter, unsigned long *interp_map_addr,
-		unsigned long no_base)
+		struct file *interpreter, unsigned long *interp_load_addr)
 {
 	struct elf_phdr *elf_phdata;
 	struct elf_phdr *eppnt;
@@ -366,7 +329,6 @@
 	int load_addr_set = 0;
 	unsigned long last_bss = 0, elf_bss = 0;
 	unsigned long error = ~0UL;
-	unsigned long total_size;
 	int retval, i, size;
 
 	/* First of all, some simple consistency checks */
@@ -405,12 +367,6 @@
 		goto out_close;
 	}
 
-	total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
-	if (!total_size) {
-		error = -EINVAL;
-		goto out_close;
-	}
-
 	eppnt = elf_phdata;
 	for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
 		if (eppnt->p_type == PT_LOAD) {
@@ -428,14 +384,9 @@
 			vaddr = eppnt->p_vaddr;
 			if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
 				elf_type |= MAP_FIXED;
-			else if (no_base && interp_elf_ex->e_type == ET_DYN)
-				load_addr = -vaddr;
 
 			map_addr = elf_map(interpreter, load_addr + vaddr,
-					   eppnt, elf_prot, elf_type, total_size);
-			total_size = 0;
-			if (!*interp_map_addr)
-				*interp_map_addr = map_addr;
+					   eppnt, elf_prot, elf_type);
 			error = map_addr;
 			if (BAD_ADDR(map_addr))
 				goto out_close;
@@ -501,7 +452,8 @@
 			goto out_close;
 	}
 
-	error = load_addr;
+	*interp_load_addr = load_addr;
+	error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
 
 out_close:
 	kfree(elf_phdata);
@@ -598,8 +550,7 @@
 	int elf_exec_fileno;
 	int retval, i;
 	unsigned int size;
-	unsigned long elf_entry;
-	unsigned long interp_load_addr = 0;
+	unsigned long elf_entry, interp_load_addr = 0;
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long reloc_func_desc = 0;
 	char passed_fileno[6];
@@ -863,7 +814,9 @@
 	current->mm->start_stack = bprm->p;
 
 	/* Now we do a little grungy work by mmaping the ELF image into
-	   the correct location in memory. */
+	   the correct location in memory.  At this point, we assume that
+	   the image should be loaded at fixed address, not at a variable
+	   address. */
 	for(i = 0, elf_ppnt = elf_phdata;
 	    i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
 		int elf_prot = 0, elf_flags;
@@ -917,15 +870,11 @@
 			 * default mmap base, as well as whatever program they
 			 * might try to exec.  This is because the brk will
 			 * follow the loader, and is not movable.  */
-#ifdef CONFIG_X86
-			load_bias = 0;
-#else
 			load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
-#endif
 		}
 
 		error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
-				elf_prot, elf_flags,0);
+				elf_prot, elf_flags);
 		if (BAD_ADDR(error)) {
 			send_sig(SIGKILL, current, 0);
 			retval = IS_ERR((void *)error) ?
@@ -1001,25 +950,13 @@
 	}
 
 	if (elf_interpreter) {
-		if (interpreter_type == INTERPRETER_AOUT) {
+		if (interpreter_type == INTERPRETER_AOUT)
 			elf_entry = load_aout_interp(&loc->interp_ex,
 						     interpreter);
-		} else {
-			unsigned long uninitialized_var(interp_map_addr);
-
+		else
 			elf_entry = load_elf_interp(&loc->interp_elf_ex,
 						    interpreter,
-						    &interp_map_addr,
-						    load_bias);
-			if (!BAD_ADDR(elf_entry)) {
-				/*
-				 * load_elf_interp() returns relocation
-				 * adjustment
-				 */
-				interp_load_addr = elf_entry;
-				elf_entry += loc->interp_elf_ex.e_entry;
-			}
-		}
+						    &interp_load_addr);
 		if (BAD_ADDR(elf_entry)) {
 			force_sig(SIGSEGV, current);
 			retval = IS_ERR((void *)elf_entry) ?
diff --git a/fs/buffer.c b/fs/buffer.c
index 02ebb1f..0e5ec37 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2221,7 +2221,7 @@
 	lock_page(page);
 	size = i_size_read(inode);
 	if ((page->mapping != inode->i_mapping) ||
-	    ((page->index << PAGE_CACHE_SHIFT) > size)) {
+	    (page_offset(page) > size)) {
 		/* page got truncated out from underneath us */
 		goto out_unlock;
 	}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 8e61236..f89ff08 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -86,7 +86,6 @@
 	.read		= generic_read_dir,
 	.readdir	= coda_readdir,
 	.open		= coda_open,
-	.flush		= coda_flush,
 	.release	= coda_release,
 	.fsync		= coda_fsync,
 };
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 7594962..29137ff 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -25,10 +25,6 @@
 
 #include "coda_int.h"
 
-/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
- * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
-static int use_coda_close;
-
 static ssize_t
 coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
 {
@@ -163,47 +159,6 @@
 	return 0;
 }
 
-int coda_flush(struct file *coda_file, fl_owner_t id)
-{
-	unsigned short flags = coda_file->f_flags & ~O_EXCL;
-	unsigned short coda_flags = coda_flags_to_cflags(flags);
-	struct coda_file_info *cfi;
-	struct inode *coda_inode;
-	int err = 0, fcnt;
-
-	lock_kernel();
-
-	/* last close semantics */
-	fcnt = file_count(coda_file);
-	if (fcnt > 1)
-		goto out;
-
-	/* No need to make an upcall when we have not made any modifications
-	 * to the file */
-	if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
-		goto out;
-
-	if (use_coda_close)
-		goto out;
-
-	cfi = CODA_FTOC(coda_file);
-	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
-
-	coda_inode = coda_file->f_path.dentry->d_inode;
-
-	err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
-			  coda_file->f_uid);
-
-	if (err == -EOPNOTSUPP) {
-		use_coda_close = 1;
-		err = 0;
-	}
-
-out:
-	unlock_kernel();
-	return err;
-}
-
 int coda_release(struct inode *coda_inode, struct file *coda_file)
 {
 	unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
@@ -215,21 +170,11 @@
 
 	lock_kernel();
 
-	if (!use_coda_close) {
-		err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
-				    coda_flags);
-		if (err == -EOPNOTSUPP) {
-			use_coda_close = 1;
-			err = 0;
-		}
-	}
-
 	cfi = CODA_FTOC(coda_file);
 	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
 
-	if (use_coda_close)
-		err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
-				  coda_flags, coda_file->f_uid);
+	err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
+			  coda_flags, coda_file->f_uid);
 
 	host_inode = cfi->cfi_container->f_path.dentry->d_inode;
 	cii = ITOC(coda_inode);
@@ -246,7 +191,10 @@
 	coda_file->private_data = NULL;
 
 	unlock_kernel();
-	return err;
+
+	/* VFS fput ignores the return value from file_operations->release, so
+	 * there is no use returning an error here */
+	return 0;
 }
 
 int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
@@ -288,7 +236,6 @@
 	.write		= coda_file_write,
 	.mmap		= coda_file_mmap,
 	.open		= coda_open,
-	.flush		= coda_flush,
 	.release	= coda_release,
 	.fsync		= coda_fsync,
 	.splice_read	= coda_file_splice_read,
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index cd561d2..cdb4c07 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -160,55 +160,8 @@
 	return error;
 }
 
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
-                vuid_t uid)
-{
-        union inputArgs *inp;
-        union outputArgs *outp;
-        int insize, outsize, error;
-#ifdef CONFIG_CODA_FS_OLD_API
-	struct coda_cred cred = { 0, };
-	cred.cr_fsuid = uid;
-#endif
-	
-	insize = SIZE(store);
-	UPARG(CODA_STORE);
-	
-#ifdef CONFIG_CODA_FS_OLD_API
-	memcpy(&(inp->ih.cred), &cred, sizeof(cred));
-#else
-	inp->ih.uid = uid;
-#endif
-	
-        inp->coda_store.VFid = *fid;
-        inp->coda_store.flags = flags;
-
-	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
-
-	CODA_FREE(inp, insize);
-        return error;
-}
-
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
-{
-        union inputArgs *inp;
-        union outputArgs *outp;
-        int insize, outsize, error;
-	
-	insize = SIZE(release);
-	UPARG(CODA_RELEASE);
-	
-	inp->coda_release.VFid = *fid;
-	inp->coda_release.flags = flags;
-
-	error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
-
-	CODA_FREE(inp, insize);
-	return error;
-}
-
 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
-                vuid_t uid)
+		vuid_t uid)
 {
 	union inputArgs *inp;
 	union outputArgs *outp;
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 7d5a43c..e4ab7bc 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -409,8 +409,7 @@
 	if (!PageUptodate(page))
 		rc = ecryptfs_do_readpage(file, page, page->index);
 	if (page->index != 0) {
-		loff_t end_of_prev_pg_pos =
-			(((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
+		loff_t end_of_prev_pg_pos = page_offset(page) - 1;
 
 		if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
 			rc = ecryptfs_truncate(file->f_path.dentry,
@@ -736,7 +735,7 @@
 		goto out;
 	}
 	inode->i_blocks = lower_inode->i_blocks;
-	pos = (page->index << PAGE_CACHE_SHIFT) + to;
+	pos = page_offset(page) + to;
 	if (pos > i_size_read(inode)) {
 		i_size_write(inode, pos);
 		ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b34b7a7..b2a851c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -732,7 +732,7 @@
 				return 0;
 			if (option < 0 || option > 65535)
 				return 0;
-			mnt->nfs_server.address.sin_port = htonl(option);
+			mnt->nfs_server.address.sin_port = htons(option);
 			break;
 		case Opt_rsize:
 			if (match_int(args, &mnt->rsize))
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 6ab8de4..2d295dd 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1503,9 +1503,9 @@
 	if (flag & NFSEXP_FSID)
 		seq_printf(m, ",fsid=%d", fsid);
 	if (anonu != (uid_t)-2 && anonu != (0x10000-2))
-		seq_printf(m, ",sanonuid=%d", anonu);
+		seq_printf(m, ",anonuid=%u", anonu);
 	if (anong != (gid_t)-2 && anong != (0x10000-2))
-		seq_printf(m, ",sanongid=%d", anong);
+		seq_printf(m, ",anongid=%u", anong);
 	if (fsloc && fsloc->locations_count > 0) {
 		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
 		int i;
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index ee64749..9875615 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -89,7 +89,7 @@
 {
 	int ret;
 	struct address_space *mapping = inode->i_mapping;
-	loff_t pos = page->index << PAGE_CACHE_SHIFT;
+	loff_t pos = page_offset(page);
 	unsigned int len = PAGE_CACHE_SIZE;
 	pgoff_t last_index;
 	struct page *locked_page = NULL;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index f133afe..bee251c 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -507,7 +507,8 @@
 	}
 	seq_printf(p, "intr %llu", (unsigned long long)sum);
 
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
+#ifndef CONFIG_SMP
+	/* Touches too many cache lines on SMP setups */
 	for (i = 0; i < NR_IRQS; i++)
 		seq_printf(p, " %u", per_irq_sum[i]);
 #endif
diff --git a/fs/splice.c b/fs/splice.c
index 22496d2..0a09732 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -594,7 +594,7 @@
 		ret = add_to_page_cache_lru(page, mapping, index,
 					    GFP_KERNEL);
 		if (unlikely(ret))
-			goto out;
+			goto out_release;
 	}
 
 	ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
@@ -650,8 +650,9 @@
 	 */
 	mark_page_accessed(page);
 out:
-	page_cache_release(page);
 	unlock_page(page);
+out_release:
+	page_cache_release(page);
 out_ret:
 	return ret;
 }
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index ef48d09..276f720 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -70,9 +70,9 @@
 	if (!size)
 		return result;
 	tmp = leBPL_to_cpup(p);
-      found_first:
+found_first:
 	tmp &= ~0UL >> (BITS_PER_LONG - size);
-      found_middle:
+found_middle:
 	return result + ffz(~tmp);
 }
 
@@ -110,11 +110,11 @@
 			  nr_groups);
 	}
 
-	if (bitmap->s_block_bitmap[block_group])
+	if (bitmap->s_block_bitmap[block_group]) {
 		return block_group;
-	else {
-		retval =
-		    read_block_bitmap(sb, bitmap, block_group, block_group);
+	} else {
+		retval = read_block_bitmap(sb, bitmap, block_group,
+					   block_group);
 		if (retval < 0)
 			return retval;
 		return block_group;
@@ -155,22 +155,16 @@
 
 	mutex_lock(&sbi->s_alloc_mutex);
 	if (bloc.logicalBlockNum < 0 ||
-	    (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb,
-							    bloc.
-							    partitionReferenceNum))
-	{
-		udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0,
-			  bloc.logicalBlockNum, count, UDF_SB_PARTLEN(sb,
-								      bloc.
-								      partitionReferenceNum));
+	    (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
+		udf_debug("%d < %d || %d + %d > %d\n",
+			  bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+			  UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
 		goto error_return;
 	}
 
-	block =
-	    bloc.logicalBlockNum + offset +
-	    (sizeof(struct spaceBitmapDesc) << 3);
+	block = bloc.logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3);
 
-      do_more:
+do_more:
 	overflow = 0;
 	block_group = block >> (sb->s_blocksize_bits + 3);
 	bit = block % (sb->s_blocksize << 3);
@@ -190,18 +184,13 @@
 	for (i = 0; i < count; i++) {
 		if (udf_set_bit(bit + i, bh->b_data)) {
 			udf_debug("bit %ld already set\n", bit + i);
-			udf_debug("byte=%2x\n",
-				  ((char *)bh->b_data)[(bit + i) >> 3]);
+			udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
 		} else {
 			if (inode)
 				DQUOT_FREE_BLOCK(inode, 1);
 			if (UDF_SB_LVIDBH(sb)) {
-				UDF_SB_LVID(sb)->
-				    freeSpaceTable[UDF_SB_PARTITION(sb)] =
-				    cpu_to_le32(le32_to_cpu
-						(UDF_SB_LVID(sb)->
-						 freeSpaceTable[UDF_SB_PARTITION
-								(sb)]) + 1);
+				UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
+					cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + 1);
 			}
 		}
 	}
@@ -211,7 +200,7 @@
 		count = overflow;
 		goto do_more;
 	}
-      error_return:
+error_return:
 	sb->s_dirt = 1;
 	if (UDF_SB_LVIDBH(sb))
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
@@ -238,7 +227,7 @@
 	if (first_block + block_count > UDF_SB_PARTLEN(sb, partition))
 		block_count = UDF_SB_PARTLEN(sb, partition) - first_block;
 
-      repeat:
+repeat:
 	nr_groups = (UDF_SB_PARTLEN(sb, partition) +
 		     (sizeof(struct spaceBitmapDesc) << 3) +
 		     (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
@@ -254,11 +243,11 @@
 	bit = block % (sb->s_blocksize << 3);
 
 	while (bit < (sb->s_blocksize << 3) && block_count > 0) {
-		if (!udf_test_bit(bit, bh->b_data))
+		if (!udf_test_bit(bit, bh->b_data)) {
 			goto out;
-		else if (DQUOT_PREALLOC_BLOCK(inode, 1))
+		} else if (DQUOT_PREALLOC_BLOCK(inode, 1)) {
 			goto out;
-		else if (!udf_clear_bit(bit, bh->b_data)) {
+		} else if (!udf_clear_bit(bit, bh->b_data)) {
 			udf_debug("bit already cleared for block %d\n", bit);
 			DQUOT_FREE_BLOCK(inode, 1);
 			goto out;
@@ -271,12 +260,10 @@
 	mark_buffer_dirty(bh);
 	if (block_count > 0)
 		goto repeat;
-      out:
+out:
 	if (UDF_SB_LVIDBH(sb)) {
 		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-		    cpu_to_le32(le32_to_cpu
-				(UDF_SB_LVID(sb)->freeSpaceTable[partition]) -
-				alloc_count);
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 	sb->s_dirt = 1;
@@ -299,7 +286,7 @@
 	*err = -ENOSPC;
 	mutex_lock(&sbi->s_alloc_mutex);
 
-      repeat:
+repeat:
 	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
 		goal = 0;
 
@@ -312,31 +299,27 @@
 	if (bitmap_nr < 0)
 		goto error_return;
 	bh = bitmap->s_block_bitmap[bitmap_nr];
-	ptr =
-	    memscan((char *)bh->b_data + group_start, 0xFF,
-		    sb->s_blocksize - group_start);
+	ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+		      sb->s_blocksize - group_start);
 
 	if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
 		bit = block % (sb->s_blocksize << 3);
-
-		if (udf_test_bit(bit, bh->b_data)) {
+		if (udf_test_bit(bit, bh->b_data))
 			goto got_block;
-		}
+
 		end_goal = (bit + 63) & ~63;
 		bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
 		if (bit < end_goal)
 			goto got_block;
-		ptr =
-		    memscan((char *)bh->b_data + (bit >> 3), 0xFF,
-			    sb->s_blocksize - ((bit + 7) >> 3));
+
+		ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
 		newbit = (ptr - ((char *)bh->b_data)) << 3;
 		if (newbit < sb->s_blocksize << 3) {
 			bit = newbit;
 			goto search_back;
 		}
-		newbit =
-		    udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3,
-					  bit);
+
+		newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
 		if (newbit < sb->s_blocksize << 3) {
 			bit = newbit;
 			goto got_block;
@@ -354,18 +337,16 @@
 			goto error_return;
 		bh = bitmap->s_block_bitmap[bitmap_nr];
 		if (i < nr_groups) {
-			ptr =
-			    memscan((char *)bh->b_data + group_start, 0xFF,
-				    sb->s_blocksize - group_start);
+			ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+				      sb->s_blocksize - group_start);
 			if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
 				bit = (ptr - ((char *)bh->b_data)) << 3;
 				break;
 			}
 		} else {
-			bit =
-			    udf_find_next_one_bit((char *)bh->b_data,
-						  sb->s_blocksize << 3,
-						  group_start << 3);
+			bit = udf_find_next_one_bit((char *)bh->b_data,
+						    sb->s_blocksize << 3,
+						    group_start << 3);
 			if (bit < sb->s_blocksize << 3)
 				break;
 		}
@@ -377,20 +358,17 @@
 	if (bit < sb->s_blocksize << 3)
 		goto search_back;
 	else
-		bit =
-		    udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3,
-					  group_start << 3);
+		bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
 	if (bit >= sb->s_blocksize << 3) {
 		mutex_unlock(&sbi->s_alloc_mutex);
 		return 0;
 	}
 
-      search_back:
-	for (i = 0;
-	     i < 7 && bit > (group_start << 3)
-	     && udf_test_bit(bit - 1, bh->b_data); i++, bit--) ;
+search_back:
+	for (i = 0; i < 7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--)
+		; /* empty loop */
 
-      got_block:
+got_block:
 
 	/*
 	 * Check quota for allocation of this block.
@@ -402,7 +380,7 @@
 	}
 
 	newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
-	    (sizeof(struct spaceBitmapDesc) << 3);
+		(sizeof(struct spaceBitmapDesc) << 3);
 
 	if (!udf_clear_bit(bit, bh->b_data)) {
 		udf_debug("bit already cleared for block %d\n", bit);
@@ -413,9 +391,7 @@
 
 	if (UDF_SB_LVIDBH(sb)) {
 		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-		    cpu_to_le32(le32_to_cpu
-				(UDF_SB_LVID(sb)->freeSpaceTable[partition]) -
-				1);
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 	sb->s_dirt = 1;
@@ -423,7 +399,7 @@
 	*err = 0;
 	return newblock;
 
-      error_return:
+error_return:
 	*err = -EIO;
 	mutex_unlock(&sbi->s_alloc_mutex);
 	return 0;
@@ -445,14 +421,10 @@
 
 	mutex_lock(&sbi->s_alloc_mutex);
 	if (bloc.logicalBlockNum < 0 ||
-	    (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb,
-							    bloc.
-							    partitionReferenceNum))
-	{
-		udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0,
-			  bloc.logicalBlockNum, count, UDF_SB_PARTLEN(sb,
-								      bloc.
-								      partitionReferenceNum));
+	    (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
+		udf_debug("%d < %d || %d + %d > %d\n",
+			  bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+			  UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
 		goto error_return;
 	}
 
@@ -462,9 +434,7 @@
 		DQUOT_FREE_BLOCK(inode, count);
 	if (UDF_SB_LVIDBH(sb)) {
 		UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
-		    cpu_to_le32(le32_to_cpu
-				(UDF_SB_LVID(sb)->
-				 freeSpaceTable[UDF_SB_PARTITION(sb)]) + count);
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + count);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 
@@ -476,47 +446,28 @@
 	epos.block = oepos.block = UDF_I_LOCATION(table);
 	epos.bh = oepos.bh = NULL;
 
-	while (count && (etype =
-			 udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
-		if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
-		     start)) {
-			if ((0x3FFFFFFF - elen) <
-			    (count << sb->s_blocksize_bits)) {
-				count -=
-				    ((0x3FFFFFFF -
-				      elen) >> sb->s_blocksize_bits);
-				start +=
-				    ((0x3FFFFFFF -
-				      elen) >> sb->s_blocksize_bits);
-				elen =
-				    (etype << 30) | (0x40000000 -
-						     sb->s_blocksize);
+	while (count &&
+	       (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+		if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) {
+			if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
+				count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
 			} else {
-				elen = (etype << 30) |
-				    (elen + (count << sb->s_blocksize_bits));
+				elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
 				start += count;
 				count = 0;
 			}
 			udf_write_aext(table, &oepos, eloc, elen, 1);
 		} else if (eloc.logicalBlockNum == (end + 1)) {
-			if ((0x3FFFFFFF - elen) <
-			    (count << sb->s_blocksize_bits)) {
-				count -=
-				    ((0x3FFFFFFF -
-				      elen) >> sb->s_blocksize_bits);
-				end -=
-				    ((0x3FFFFFFF -
-				      elen) >> sb->s_blocksize_bits);
-				eloc.logicalBlockNum -=
-				    ((0x3FFFFFFF -
-				      elen) >> sb->s_blocksize_bits);
-				elen =
-				    (etype << 30) | (0x40000000 -
-						     sb->s_blocksize);
+			if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
+				count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				eloc.logicalBlockNum -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+				elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
 			} else {
 				eloc.logicalBlockNum = start;
-				elen = (etype << 30) |
-				    (elen + (count << sb->s_blocksize_bits));
+				elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
 				end -= count;
 				count = 0;
 			}
@@ -530,21 +481,23 @@
 			get_bh(epos.bh);
 			oepos.bh = epos.bh;
 			oepos.offset = 0;
-		} else
+		} else {
 			oepos.offset = epos.offset;
+		}
 	}
 
 	if (count) {
-		/* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
-		   a new block, and since we hold the super block lock already
-		   very bad things would happen :)
-
-		   We copy the behavior of udf_add_aext, but instead of
-		   trying to allocate a new block close to the existing one,
-		   we just steal a block from the extent we are trying to add.
-
-		   It would be nice if the blocks were close together, but it
-		   isn't required.
+		/*
+		 * NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
+		 * a new block, and since we hold the super block lock already
+		 * very bad things would happen :)
+		 *
+		 * We copy the behavior of udf_add_aext, but instead of
+		 * trying to allocate a new block close to the existing one,
+		 * we just steal a block from the extent we are trying to add.
+		 *
+		 * It would be nice if the blocks were close together, but it
+		 * isn't required.
 		 */
 
 		int adsize;
@@ -553,13 +506,14 @@
 		struct allocExtDesc *aed;
 
 		eloc.logicalBlockNum = start;
-		elen = EXT_RECORDED_ALLOCATED | (count << sb->s_blocksize_bits);
+		elen = EXT_RECORDED_ALLOCATED |
+			(count << sb->s_blocksize_bits);
 
-		if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
+		if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) {
 			adsize = sizeof(short_ad);
-		else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
+		} else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) {
 			adsize = sizeof(long_ad);
-		else {
+		} else {
 			brelse(oepos.bh);
 			brelse(epos.bh);
 			goto error_return;
@@ -577,28 +531,21 @@
 			eloc.logicalBlockNum++;
 			elen -= sb->s_blocksize;
 
-			if (!(epos.bh = udf_tread(sb,
-						  udf_get_lb_pblock(sb,
-								    epos.block,
-								    0)))) {
+			if (!(epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, epos.block, 0)))) {
 				brelse(oepos.bh);
 				goto error_return;
 			}
 			aed = (struct allocExtDesc *)(epos.bh->b_data);
-			aed->previousAllocExtLocation =
-			    cpu_to_le32(oepos.block.logicalBlockNum);
+			aed->previousAllocExtLocation = cpu_to_le32(oepos.block.logicalBlockNum);
 			if (epos.offset + adsize > sb->s_blocksize) {
 				loffset = epos.offset;
 				aed->lengthAllocDescs = cpu_to_le32(adsize);
 				sptr = UDF_I_DATA(inode) + epos.offset -
-				    udf_file_entry_alloc_offset(inode) +
-				    UDF_I_LENEATTR(inode) - adsize;
-				dptr =
-				    epos.bh->b_data +
-				    sizeof(struct allocExtDesc);
+					udf_file_entry_alloc_offset(inode) +
+					UDF_I_LENEATTR(inode) - adsize;
+				dptr = epos.bh->b_data + sizeof(struct allocExtDesc);
 				memcpy(dptr, sptr, adsize);
-				epos.offset =
-				    sizeof(struct allocExtDesc) + adsize;
+				epos.offset = sizeof(struct allocExtDesc) + adsize;
 			} else {
 				loffset = epos.offset + adsize;
 				aed->lengthAllocDescs = cpu_to_le32(0);
@@ -606,60 +553,46 @@
 				epos.offset = sizeof(struct allocExtDesc);
 
 				if (oepos.bh) {
-					aed =
-					    (struct allocExtDesc *)oepos.bh->
-					    b_data;
+					aed = (struct allocExtDesc *)oepos.bh->b_data;
 					aed->lengthAllocDescs =
-					    cpu_to_le32(le32_to_cpu
-							(aed->
-							 lengthAllocDescs) +
-							adsize);
+						cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 				} else {
 					UDF_I_LENALLOC(table) += adsize;
 					mark_inode_dirty(table);
 				}
 			}
 			if (UDF_SB_UDFREV(sb) >= 0x0200)
-				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3,
-					    1, epos.block.logicalBlockNum,
-					    sizeof(tag));
+				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1,
+					    epos.block.logicalBlockNum, sizeof(tag));
 			else
-				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2,
-					    1, epos.block.logicalBlockNum,
-					    sizeof(tag));
+				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2, 1,
+					    epos.block.logicalBlockNum, sizeof(tag));
+
 			switch (UDF_I_ALLOCTYPE(table)) {
-			case ICBTAG_FLAG_AD_SHORT:
-				{
-					sad = (short_ad *) sptr;
-					sad->extLength =
-					    cpu_to_le32
-					    (EXT_NEXT_EXTENT_ALLOCDECS | sb->
-					     s_blocksize);
-					sad->extPosition =
-					    cpu_to_le32(epos.block.
-							logicalBlockNum);
+				case ICBTAG_FLAG_AD_SHORT:
+					sad = (short_ad *)sptr;
+					sad->extLength = cpu_to_le32(
+						EXT_NEXT_EXTENT_ALLOCDECS |
+						sb->s_blocksize);
+					sad->extPosition = cpu_to_le32(epos.block.logicalBlockNum);
 					break;
-				}
-			case ICBTAG_FLAG_AD_LONG:
-				{
-					lad = (long_ad *) sptr;
-					lad->extLength =
-					    cpu_to_le32
-					    (EXT_NEXT_EXTENT_ALLOCDECS | sb->
-					     s_blocksize);
-					lad->extLocation =
-					    cpu_to_lelb(epos.block);
+				case ICBTAG_FLAG_AD_LONG:
+					lad = (long_ad *)sptr;
+					lad->extLength = cpu_to_le32(
+						EXT_NEXT_EXTENT_ALLOCDECS |
+						sb->s_blocksize);
+					lad->extLocation = cpu_to_lelb(epos.block);
 					break;
-				}
 			}
 			if (oepos.bh) {
 				udf_update_tag(oepos.bh->b_data, loffset);
 				mark_buffer_dirty(oepos.bh);
-			} else
+			} else {
 				mark_inode_dirty(table);
+			}
 		}
 
-		if (elen) {	/* It's possible that stealing the block emptied the extent */
+		if (elen) { /* It's possible that stealing the block emptied the extent */
 			udf_write_aext(table, &epos, eloc, elen, 1);
 
 			if (!epos.bh) {
@@ -668,9 +601,7 @@
 			} else {
 				aed = (struct allocExtDesc *)epos.bh->b_data;
 				aed->lengthAllocDescs =
-				    cpu_to_le32(le32_to_cpu
-						(aed->lengthAllocDescs) +
-						adsize);
+					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 				udf_update_tag(epos.bh->b_data, epos.offset);
 				mark_buffer_dirty(epos.bh);
 			}
@@ -680,7 +611,7 @@
 	brelse(epos.bh);
 	brelse(oepos.bh);
 
-      error_return:
+error_return:
 	sb->s_dirt = 1;
 	mutex_unlock(&sbi->s_alloc_mutex);
 	return;
@@ -714,47 +645,36 @@
 	epos.bh = NULL;
 	eloc.logicalBlockNum = 0xFFFFFFFF;
 
-	while (first_block != eloc.logicalBlockNum && (etype =
-						       udf_next_aext(table,
-								     &epos,
-								     &eloc,
-								     &elen,
-								     1)) !=
-	       -1) {
+	while (first_block != eloc.logicalBlockNum &&
+	       (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
 		udf_debug("eloc=%d, elen=%d, first_block=%d\n",
 			  eloc.logicalBlockNum, elen, first_block);
-		;		/* empty loop body */
+		; /* empty loop body */
 	}
 
 	if (first_block == eloc.logicalBlockNum) {
 		epos.offset -= adsize;
 
 		alloc_count = (elen >> sb->s_blocksize_bits);
-		if (inode
-		    && DQUOT_PREALLOC_BLOCK(inode,
-					    alloc_count >
-					    block_count ? block_count :
-					    alloc_count))
+		if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count)) {
 			alloc_count = 0;
-		else if (alloc_count > block_count) {
+		} else if (alloc_count > block_count) {
 			alloc_count = block_count;
 			eloc.logicalBlockNum += alloc_count;
 			elen -= (alloc_count << sb->s_blocksize_bits);
-			udf_write_aext(table, &epos, eloc, (etype << 30) | elen,
-				       1);
-		} else
-			udf_delete_aext(table, epos, eloc,
-					(etype << 30) | elen);
-	} else
+			udf_write_aext(table, &epos, eloc, (etype << 30) | elen, 1);
+		} else {
+			udf_delete_aext(table, epos, eloc, (etype << 30) | elen);
+		}
+	} else {
 		alloc_count = 0;
+	}
 
 	brelse(epos.bh);
 
 	if (alloc_count && UDF_SB_LVIDBH(sb)) {
 		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-		    cpu_to_le32(le32_to_cpu
-				(UDF_SB_LVID(sb)->freeSpaceTable[partition]) -
-				alloc_count);
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 		sb->s_dirt = 1;
 	}
@@ -797,18 +717,17 @@
 	epos.block = UDF_I_LOCATION(table);
 	epos.bh = goal_epos.bh = NULL;
 
-	while (spread && (etype =
-			  udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+	while (spread &&
+	       (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
 		if (goal >= eloc.logicalBlockNum) {
-			if (goal <
-			    eloc.logicalBlockNum +
-			    (elen >> sb->s_blocksize_bits))
+			if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
 				nspread = 0;
 			else
 				nspread = goal - eloc.logicalBlockNum -
-				    (elen >> sb->s_blocksize_bits);
-		} else
+					(elen >> sb->s_blocksize_bits);
+		} else {
 			nspread = eloc.logicalBlockNum - goal;
+		}
 
 		if (nspread < spread) {
 			spread = nspread;
@@ -856,9 +775,7 @@
 
 	if (UDF_SB_LVIDBH(sb)) {
 		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
-		    cpu_to_le32(le32_to_cpu
-				(UDF_SB_LVID(sb)->freeSpaceTable[partition]) -
-				1);
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
 
@@ -877,27 +794,23 @@
 
 	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
 		return udf_bitmap_free_blocks(sb, inode,
-					      UDF_SB_PARTMAPS(sb)[partition].
-					      s_uspace.s_bitmap, bloc, offset,
-					      count);
-	} else if (UDF_SB_PARTFLAGS(sb, partition) &
-		   UDF_PART_FLAG_UNALLOC_TABLE) {
+					      UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+					      bloc, offset, count);
+	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
 		return udf_table_free_blocks(sb, inode,
-					     UDF_SB_PARTMAPS(sb)[partition].
-					     s_uspace.s_table, bloc, offset,
-					     count);
+					     UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+					     bloc, offset, count);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
 		return udf_bitmap_free_blocks(sb, inode,
-					      UDF_SB_PARTMAPS(sb)[partition].
-					      s_fspace.s_bitmap, bloc, offset,
-					      count);
+					      UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+					      bloc, offset, count);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
 		return udf_table_free_blocks(sb, inode,
-					     UDF_SB_PARTMAPS(sb)[partition].
-					     s_fspace.s_table, bloc, offset,
-					     count);
-	} else
+					     UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+					     bloc, offset, count);
+	} else {
 		return;
+	}
 }
 
 inline int udf_prealloc_blocks(struct super_block *sb,
@@ -907,29 +820,23 @@
 {
 	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
 		return udf_bitmap_prealloc_blocks(sb, inode,
-						  UDF_SB_PARTMAPS(sb)
-						  [partition].s_uspace.s_bitmap,
-						  partition, first_block,
-						  block_count);
-	} else if (UDF_SB_PARTFLAGS(sb, partition) &
-		   UDF_PART_FLAG_UNALLOC_TABLE) {
+						  UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+						  partition, first_block, block_count);
+	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
 		return udf_table_prealloc_blocks(sb, inode,
-						 UDF_SB_PARTMAPS(sb)[partition].
-						 s_uspace.s_table, partition,
-						 first_block, block_count);
+						 UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+						 partition, first_block, block_count);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
 		return udf_bitmap_prealloc_blocks(sb, inode,
-						  UDF_SB_PARTMAPS(sb)
-						  [partition].s_fspace.s_bitmap,
-						  partition, first_block,
-						  block_count);
+						  UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+						  partition, first_block, block_count);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
 		return udf_table_prealloc_blocks(sb, inode,
-						 UDF_SB_PARTMAPS(sb)[partition].
-						 s_fspace.s_table, partition,
-						 first_block, block_count);
-	} else
+						 UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+						 partition, first_block, block_count);
+	} else {
 		return 0;
+	}
 }
 
 inline int udf_new_block(struct super_block *sb,
@@ -940,26 +847,21 @@
 
 	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
 		ret = udf_bitmap_new_block(sb, inode,
-					   UDF_SB_PARTMAPS(sb)[partition].
-					   s_uspace.s_bitmap, partition, goal,
-					   err);
+					   UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+					   partition, goal, err);
 		return ret;
-	} else if (UDF_SB_PARTFLAGS(sb, partition) &
-		   UDF_PART_FLAG_UNALLOC_TABLE) {
+	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
 		return udf_table_new_block(sb, inode,
-					   UDF_SB_PARTMAPS(sb)[partition].
-					   s_uspace.s_table, partition, goal,
-					   err);
+					   UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+					   partition, goal, err);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
 		return udf_bitmap_new_block(sb, inode,
-					    UDF_SB_PARTMAPS(sb)[partition].
-					    s_fspace.s_bitmap, partition, goal,
-					    err);
+					    UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+					    partition, goal, err);
 	} else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
 		return udf_table_new_block(sb, inode,
-					   UDF_SB_PARTMAPS(sb)[partition].
-					   s_fspace.s_table, partition, goal,
-					   err);
+					   UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+					   partition, goal, err);
 	} else {
 		*err = -EIO;
 		return 0;
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
index ae3d497..85aaee5 100644
--- a/fs/udf/crc.c
+++ b/fs/udf/crc.c
@@ -111,7 +111,7 @@
 	return 0;
 }
 
-#endif				/* defined(TEST) */
+#endif /* defined(TEST) */
 
 /****************************************************************************/
 #if defined(GENERATE)
@@ -169,4 +169,4 @@
 	return 0;
 }
 
-#endif				/* defined(GENERATE) */
+#endif /* defined(GENERATE) */
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 79bab9f..9e3b9f9 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -43,10 +43,10 @@
 /* readdir and lookup functions */
 
 const struct file_operations udf_dir_operations = {
-	.read = generic_read_dir,
-	.readdir = udf_readdir,
-	.ioctl = udf_ioctl,
-	.fsync = udf_fsync_file,
+	.read			= generic_read_dir,
+	.readdir		= udf_readdir,
+	.ioctl			= udf_ioctl,
+	.fsync			= udf_fsync_file,
 };
 
 /*
@@ -83,8 +83,7 @@
 	lock_kernel();
 
 	if (filp->f_pos == 0) {
-		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) <
-		    0) {
+		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
 			unlock_kernel();
 			return 0;
 		}
@@ -93,7 +92,7 @@
 
 	result = do_udf_readdir(dir, filp, filldir, dirent);
 	unlock_kernel();
-	return result;
+ 	return result;
 }
 
 static int
@@ -125,21 +124,20 @@
 	if (nf_pos == 0)
 		nf_pos = (udf_ext0_offset(dir) >> 2);
 
-	fibh.soffset = fibh.eoffset =
-	    (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+	fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		fibh.sbh = fibh.ebh = NULL;
-	else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
-			    &epos, &eloc, &elen,
-			    &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
+	} else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
+			      &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
 				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
 				epos.offset -= sizeof(long_ad);
-		} else
+		} else {
 			offset = 0;
+		}
 
 		if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
 			brelse(epos.bh);
@@ -149,15 +147,11 @@
 		if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
 			i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
 			if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
-				i = (elen >> dir->i_sb->s_blocksize_bits) -
-				    offset;
+				i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
 			for (num = 0; i > 0; i--) {
-				block =
-				    udf_get_lb_pblock(dir->i_sb, eloc,
-						      offset + i);
+				block = udf_get_lb_pblock(dir->i_sb, eloc, offset + i);
 				tmp = udf_tgetblk(dir->i_sb, block);
-				if (tmp && !buffer_uptodate(tmp)
-				    && !buffer_locked(tmp))
+				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
 					bha[num++] = tmp;
 				else
 					brelse(tmp);
@@ -178,7 +172,6 @@
 
 		fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
 					&elen, &offset);
-
 		if (!fi) {
 			if (fibh.sbh != fibh.ebh)
 				brelse(fibh.ebh);
@@ -190,19 +183,16 @@
 		liu = le16_to_cpu(cfi.lengthOfImpUse);
 		lfi = cfi.lengthFileIdent;
 
-		if (fibh.sbh == fibh.ebh)
+		if (fibh.sbh == fibh.ebh) {
 			nameptr = fi->fileIdent + liu;
-		else {
+		} else {
 			int poffset;	/* Unpaded ending offset */
 
-			poffset =
-			    fibh.soffset + sizeof(struct fileIdentDesc) + liu +
-			    lfi;
+			poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-			if (poffset >= lfi)
-				nameptr =
-				    (char *)(fibh.ebh->b_data + poffset - lfi);
-			else {
+			if (poffset >= lfi) {
+				nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
+			} else {
 				nameptr = fname;
 				memcpy(nameptr, fi->fileIdent + liu,
 				       lfi - poffset);
@@ -235,17 +225,15 @@
 		}
 
 		if (flen) {
-			if (filldir
-			    (dirent, fname, flen, filp->f_pos, iblock,
-			     dt_type) < 0) {
+			if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) {
 				if (fibh.sbh != fibh.ebh)
 					brelse(fibh.ebh);
 				brelse(fibh.sbh);
 				brelse(epos.bh);
-				return 0;
+	 			return 0;
 			}
 		}
-	}			/* end while */
+	} /* end while */
 
 	filp->f_pos = nf_pos + 1;
 
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index 8adc77c..ff8c08f 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -31,7 +31,7 @@
 
 	*error = 0;
 
-	ad = (uint8_t *) (*bh)->b_data + *offset;
+	ad = (uint8_t *)(*bh)->b_data + *offset;
 	*offset += ad_size;
 
 	if (!ad) {
@@ -51,7 +51,7 @@
 		ad = tmpad;
 
 		remainder = dir->i_sb->s_blocksize - loffset;
-		memcpy((uint8_t *) ad, (*bh)->b_data + loffset, remainder);
+		memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
 
 		brelse(*bh);
 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
@@ -60,10 +60,10 @@
 		if (!((*bh) = udf_tread(dir->i_sb, block)))
 			return NULL;
 
-		memcpy((uint8_t *) ad + remainder, (*bh)->b_data,
-		       ad_size - remainder);
+		memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
 		*offset = ad_size - remainder;
 	}
+
 	return ad;
 }
 #endif
@@ -86,15 +86,13 @@
 				       (UDF_I_EFE(dir) ?
 					sizeof(struct extendedFileEntry) :
 					sizeof(struct fileEntry)),
-				       dir->i_sb->s_blocksize,
-				       &(fibh->eoffset));
-
+				       dir->i_sb->s_blocksize, &(fibh->eoffset));
 		if (!fi)
 			return NULL;
 
 		*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
 
-		memcpy((uint8_t *) cfi, (uint8_t *) fi,
+		memcpy((uint8_t *)cfi, (uint8_t *)fi,
 		       sizeof(struct fileIdentDesc));
 
 		return fi;
@@ -121,21 +119,14 @@
 			return NULL;
 		fibh->soffset = fibh->eoffset = 0;
 
-		if (!
-		    (*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1)))
-		{
+		if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
 			i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
-			if (i + *offset >
-			    (*elen >> dir->i_sb->s_blocksize_bits))
-				i = (*elen >> dir->i_sb->s_blocksize_bits) -
-				    *offset;
+			if (i + *offset > (*elen >> dir->i_sb->s_blocksize_bits))
+				i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
 			for (num = 0; i > 0; i--) {
-				block =
-				    udf_get_lb_pblock(dir->i_sb, *eloc,
-						      *offset + i);
+				block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset + i);
 				tmp = udf_tgetblk(dir->i_sb, block);
-				if (tmp && !buffer_uptodate(tmp)
-				    && !buffer_locked(tmp))
+				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
 					bha[num++] = tmp;
 				else
 					brelse(tmp);
@@ -160,7 +151,7 @@
 	*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
 
 	if (fibh->eoffset <= dir->i_sb->s_blocksize) {
-		memcpy((uint8_t *) cfi, (uint8_t *) fi,
+		memcpy((uint8_t *)cfi, (uint8_t *)fi,
 		       sizeof(struct fileIdentDesc));
 	} else if (fibh->eoffset > dir->i_sb->s_blocksize) {
 		int lextoffset = epos->offset;
@@ -187,21 +178,17 @@
 		if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
 			int fi_len;
 
-			memcpy((uint8_t *) cfi, (uint8_t *) fi, -fibh->soffset);
-			memcpy((uint8_t *) cfi - fibh->soffset,
-			       fibh->ebh->b_data,
+			memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
+			memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
 			       sizeof(struct fileIdentDesc) + fibh->soffset);
 
-			fi_len =
-			    (sizeof(struct fileIdentDesc) +
-			     cfi->lengthFileIdent +
-			     le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+			fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
+				  le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
 
-			*nf_pos +=
-			    ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
+			*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
 			fibh->eoffset = fibh->soffset + fi_len;
 		} else {
-			memcpy((uint8_t *) cfi, (uint8_t *) fi,
+			memcpy((uint8_t *)cfi, (uint8_t *)fi,
 			       sizeof(struct fileIdentDesc));
 		}
 	}
@@ -237,9 +224,10 @@
 	}
 	if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) {
 		lengthThisIdent = sizeof(struct fileIdentDesc);
-	} else
+	} else {
 		lengthThisIdent = sizeof(struct fileIdentDesc) +
-		    fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+	}
 
 	/* we need to figure padding, too! */
 	padlen = lengthThisIdent % UDF_NAME_PAD;
@@ -270,22 +258,20 @@
 		return NULL;
 	}
 
-	ptr =
-	    (uint8_t *) (fe->extendedAttr) +
-	    le32_to_cpu(fe->lengthExtendedAttr);
+	ptr = (uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
 
 	if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs))) {
 		ptr += *offset;
 	}
 
-	ext = (extent_ad *) ptr;
+	ext = (extent_ad *)ptr;
 
 	*offset = *offset + sizeof(extent_ad);
 	return ext;
 }
 #endif
 
-short_ad *udf_get_fileshortad(uint8_t * ptr, int maxoffset, int *offset,
+short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset,
 			      int inc)
 {
 	short_ad *sa;
@@ -297,7 +283,7 @@
 
 	if ((*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset))
 		return NULL;
-	else if ((sa = (short_ad *) ptr)->extLength == 0)
+	else if ((sa = (short_ad *)ptr)->extLength == 0)
 		return NULL;
 
 	if (inc)
@@ -305,7 +291,7 @@
 	return sa;
 }
 
-long_ad *udf_get_filelongad(uint8_t * ptr, int maxoffset, int *offset, int inc)
+long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, int *offset, int inc)
 {
 	long_ad *la;
 
@@ -316,7 +302,7 @@
 
 	if ((*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset))
 		return NULL;
-	else if ((la = (long_ad *) ptr)->extLength == 0)
+	else if ((la = (long_ad *)ptr)->extLength == 0)
 		return NULL;
 
 	if (inc)
diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h
index 294ce2d..5638771 100644
--- a/fs/udf/ecma_167.h
+++ b/fs/udf/ecma_167.h
@@ -39,8 +39,8 @@
 
 /* Character set specification (ECMA 167r3 1/7.2.1) */
 typedef struct {
-	uint8_t charSetType;
-	uint8_t charSetInfo[63];
+	uint8_t		charSetType;
+	uint8_t		charSetInfo[63];
 } __attribute__ ((packed)) charspec;
 
 /* Character Set Type (ECMA 167r3 1/7.2.1.1) */
@@ -54,33 +54,33 @@
 #define CHARSPEC_TYPE_CS7		0x07	/* (1/7.2.9) */
 #define CHARSPEC_TYPE_CS8		0x08	/* (1/7.2.10) */
 
-typedef uint8_t dstring;
+typedef uint8_t		dstring;
 
 /* Timestamp (ECMA 167r3 1/7.3) */
 typedef struct {
-	__le16 typeAndTimezone;
-	__le16 year;
-	uint8_t month;
-	uint8_t day;
-	uint8_t hour;
-	uint8_t minute;
-	uint8_t second;
-	uint8_t centiseconds;
-	uint8_t hundredsOfMicroseconds;
-	uint8_t microseconds;
+	__le16		typeAndTimezone;
+	__le16		year;
+	uint8_t		month;
+	uint8_t		day;
+	uint8_t		hour;
+	uint8_t		minute;
+	uint8_t		second;
+	uint8_t		centiseconds;
+	uint8_t		hundredsOfMicroseconds;
+	uint8_t		microseconds;
 } __attribute__ ((packed)) timestamp;
 
 typedef struct {
-	uint16_t typeAndTimezone;
-	int16_t year;
-	uint8_t month;
-	uint8_t day;
-	uint8_t hour;
-	uint8_t minute;
-	uint8_t second;
-	uint8_t centiseconds;
-	uint8_t hundredsOfMicroseconds;
-	uint8_t microseconds;
+	uint16_t	typeAndTimezone;
+	int16_t		year;
+	uint8_t		month;
+	uint8_t		day;
+	uint8_t		hour;
+	uint8_t		minute;
+	uint8_t		second;
+	uint8_t		centiseconds;
+	uint8_t		hundredsOfMicroseconds;
+	uint8_t		microseconds;
 } __attribute__ ((packed)) kernel_timestamp;
 
 /* Type and Time Zone (ECMA 167r3 1/7.3.1) */
@@ -92,9 +92,9 @@
 
 /* Entity identifier (ECMA 167r3 1/7.4) */
 typedef struct {
-	uint8_t flags;
-	uint8_t ident[23];
-	uint8_t identSuffix[8];
+	uint8_t		flags;
+	uint8_t		ident[23];
+	uint8_t		identSuffix[8];
 } __attribute__ ((packed)) regid;
 
 /* Flags (ECMA 167r3 1/7.4.1) */
@@ -104,10 +104,10 @@
 /* Volume Structure Descriptor (ECMA 167r3 2/9.1) */
 #define VSD_STD_ID_LEN			5
 struct volStructDesc {
-	uint8_t structType;
-	uint8_t stdIdent[VSD_STD_ID_LEN];
-	uint8_t structVersion;
-	uint8_t structData[2041];
+	uint8_t		structType;
+	uint8_t		stdIdent[VSD_STD_ID_LEN];
+	uint8_t		structVersion;
+	uint8_t		structData[2041];
 } __attribute__ ((packed));
 
 /* Standard Identifier (EMCA 167r2 2/9.1.2) */
@@ -123,36 +123,36 @@
 
 /* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */
 struct beginningExtendedAreaDesc {
-	uint8_t structType;
-	uint8_t stdIdent[VSD_STD_ID_LEN];
-	uint8_t structVersion;
-	uint8_t structData[2041];
+	uint8_t		structType;
+	uint8_t		stdIdent[VSD_STD_ID_LEN];
+	uint8_t		structVersion;
+	uint8_t		structData[2041];
 } __attribute__ ((packed));
 
 /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
 struct terminatingExtendedAreaDesc {
-	uint8_t structType;
-	uint8_t stdIdent[VSD_STD_ID_LEN];
-	uint8_t structVersion;
-	uint8_t structData[2041];
+	uint8_t		structType;
+	uint8_t		stdIdent[VSD_STD_ID_LEN];
+	uint8_t		structVersion;
+	uint8_t		structData[2041];
 } __attribute__ ((packed));
 
 /* Boot Descriptor (ECMA 167r3 2/9.4) */
 struct bootDesc {
-	uint8_t structType;
-	uint8_t stdIdent[VSD_STD_ID_LEN];
-	uint8_t structVersion;
-	uint8_t reserved1;
-	regid archType;
-	regid bootIdent;
-	__le32 bootExtLocation;
-	__le32 bootExtLength;
-	__le64 loadAddress;
-	__le64 startAddress;
-	timestamp descCreationDateAndTime;
-	__le16 flags;
-	uint8_t reserved2[32];
-	uint8_t bootUse[1906];
+	uint8_t		structType;
+	uint8_t		stdIdent[VSD_STD_ID_LEN];
+	uint8_t		structVersion;
+	uint8_t		reserved1;
+	regid		archType;
+	regid		bootIdent;
+	__le32		bootExtLocation;
+	__le32		bootExtLength;
+	__le64		loadAddress;
+	__le64		startAddress;
+	timestamp	descCreationDateAndTime;
+	__le16		flags;
+	uint8_t		reserved2[32];
+	uint8_t		bootUse[1906];
 } __attribute__ ((packed));
 
 /* Flags (ECMA 167r3 2/9.4.12) */
@@ -160,25 +160,25 @@
 
 /* Extent Descriptor (ECMA 167r3 3/7.1) */
 typedef struct {
-	__le32 extLength;
-	__le32 extLocation;
+	__le32		extLength;
+	__le32		extLocation;
 } __attribute__ ((packed)) extent_ad;
 
 typedef struct {
-	uint32_t extLength;
-	uint32_t extLocation;
+	uint32_t	extLength;
+	uint32_t	extLocation;
 } kernel_extent_ad;
 
 /* Descriptor Tag (ECMA 167r3 3/7.2) */
 typedef struct {
-	__le16 tagIdent;
-	__le16 descVersion;
-	uint8_t tagChecksum;
-	uint8_t reserved;
-	__le16 tagSerialNum;
-	__le16 descCRC;
-	__le16 descCRCLength;
-	__le32 tagLocation;
+	__le16		tagIdent;
+	__le16		descVersion;
+	uint8_t		tagChecksum;
+	uint8_t		reserved;
+	__le16		tagSerialNum;
+	__le16		descCRC;
+	__le16		descCRCLength;
+	__le32		tagLocation;
 } __attribute__ ((packed)) tag;
 
 /* Tag Identifier (ECMA 167r3 3/7.2.1) */
@@ -194,37 +194,37 @@
 
 /* NSR Descriptor (ECMA 167r3 3/9.1) */
 struct NSRDesc {
-	uint8_t structType;
-	uint8_t stdIdent[VSD_STD_ID_LEN];
-	uint8_t structVersion;
-	uint8_t reserved;
-	uint8_t structData[2040];
+	uint8_t		structType;
+	uint8_t		stdIdent[VSD_STD_ID_LEN];
+	uint8_t		structVersion;
+	uint8_t		reserved;
+	uint8_t		structData[2040];
 } __attribute__ ((packed));
 
 /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
 struct primaryVolDesc {
-	tag descTag;
-	__le32 volDescSeqNum;
-	__le32 primaryVolDescNum;
-	dstring volIdent[32];
-	__le16 volSeqNum;
-	__le16 maxVolSeqNum;
-	__le16 interchangeLvl;
-	__le16 maxInterchangeLvl;
-	__le32 charSetList;
-	__le32 maxCharSetList;
-	dstring volSetIdent[128];
-	charspec descCharSet;
-	charspec explanatoryCharSet;
-	extent_ad volAbstract;
-	extent_ad volCopyright;
-	regid appIdent;
-	timestamp recordingDateAndTime;
-	regid impIdent;
-	uint8_t impUse[64];
-	__le32 predecessorVolDescSeqLocation;
-	__le16 flags;
-	uint8_t reserved[22];
+	tag		descTag;
+	__le32		volDescSeqNum;
+	__le32		primaryVolDescNum;
+	dstring		volIdent[32];
+	__le16		volSeqNum;
+	__le16		maxVolSeqNum;
+	__le16		interchangeLvl;
+	__le16		maxInterchangeLvl;
+	__le32		charSetList;
+	__le32		maxCharSetList;
+	dstring		volSetIdent[128];
+	charspec	descCharSet;
+	charspec	explanatoryCharSet;
+	extent_ad	volAbstract;
+	extent_ad	volCopyright;
+	regid		appIdent;
+	timestamp	recordingDateAndTime;
+	regid		impIdent;
+	uint8_t		impUse[64];
+	__le32		predecessorVolDescSeqLocation;
+	__le16		flags;
+	uint8_t		reserved[22];
 } __attribute__ ((packed));
 
 /* Flags (ECMA 167r3 3/10.1.21) */
@@ -232,26 +232,26 @@
 
 /* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
 struct anchorVolDescPtr {
-	tag descTag;
-	extent_ad mainVolDescSeqExt;
-	extent_ad reserveVolDescSeqExt;
-	uint8_t reserved[480];
+	tag		descTag;
+	extent_ad	mainVolDescSeqExt;
+	extent_ad	reserveVolDescSeqExt;
+	uint8_t	 	reserved[480];
 } __attribute__ ((packed));
 
 /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
 struct volDescPtr {
-	tag descTag;
-	__le32 volDescSeqNum;
-	extent_ad nextVolDescSeqExt;
-	uint8_t reserved[484];
+	tag		descTag;
+	__le32		volDescSeqNum;
+	extent_ad	nextVolDescSeqExt;
+	uint8_t		reserved[484];
 } __attribute__ ((packed));
 
 /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
 struct impUseVolDesc {
-	tag descTag;
-	__le32 volDescSeqNum;
-	regid impIdent;
-	uint8_t impUse[460];
+	tag		descTag;
+	__le32		volDescSeqNum;
+	regid		impIdent;
+	uint8_t		impUse[460];
 } __attribute__ ((packed));
 
 /* Partition Descriptor (ECMA 167r3 3/10.5) */
@@ -291,26 +291,26 @@
 
 /* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
 struct logicalVolDesc {
-	tag descTag;
-	__le32 volDescSeqNum;
-	charspec descCharSet;
-	dstring logicalVolIdent[128];
-	__le32 logicalBlockSize;
-	regid domainIdent;
-	uint8_t logicalVolContentsUse[16];
-	__le32 mapTableLength;
-	__le32 numPartitionMaps;
-	regid impIdent;
-	uint8_t impUse[128];
-	extent_ad integritySeqExt;
-	uint8_t partitionMaps[0];
+	tag		descTag;
+	__le32		volDescSeqNum;
+	charspec	descCharSet;
+	dstring		logicalVolIdent[128];
+	__le32		logicalBlockSize;
+	regid		domainIdent;
+	uint8_t		logicalVolContentsUse[16];
+	__le32		mapTableLength;
+	__le32		numPartitionMaps;
+	regid		impIdent;
+	uint8_t		impUse[128];
+	extent_ad	integritySeqExt;
+	uint8_t		partitionMaps[0];
 } __attribute__ ((packed));
 
 /* Generic Partition Map (ECMA 167r3 3/10.7.1) */
 struct genericPartitionMap {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	uint8_t partitionMapping[0];
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		partitionMapping[0];
 } __attribute__ ((packed));
 
 /* Partition Map Type (ECMA 167r3 3/10.7.1.1) */
@@ -320,45 +320,45 @@
 
 /* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */
 struct genericPartitionMap1 {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	__le16 volSeqNum;
-	__le16 partitionNum;
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	__le16		volSeqNum;
+	__le16		partitionNum;
 } __attribute__ ((packed));
 
 /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
 struct genericPartitionMap2 {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	uint8_t partitionIdent[62];
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		partitionIdent[62];
 } __attribute__ ((packed));
 
 /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
 struct unallocSpaceDesc {
-	tag descTag;
-	__le32 volDescSeqNum;
-	__le32 numAllocDescs;
-	extent_ad allocDescs[0];
+	tag		descTag;
+	__le32		volDescSeqNum;
+	__le32		numAllocDescs;
+	extent_ad	allocDescs[0];
 } __attribute__ ((packed));
 
 /* Terminating Descriptor (ECMA 167r3 3/10.9) */
 struct terminatingDesc {
-	tag descTag;
-	uint8_t reserved[496];
+	tag		descTag;
+	uint8_t		reserved[496];
 } __attribute__ ((packed));
 
 /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
 struct logicalVolIntegrityDesc {
-	tag descTag;
-	timestamp recordingDateAndTime;
-	__le32 integrityType;
-	extent_ad nextIntegrityExt;
-	uint8_t logicalVolContentsUse[32];
-	__le32 numOfPartitions;
-	__le32 lengthOfImpUse;
-	__le32 freeSpaceTable[0];
-	__le32 sizeTable[0];
-	uint8_t impUse[0];
+	tag		descTag;
+	timestamp	recordingDateAndTime;
+	__le32		integrityType;
+	extent_ad	nextIntegrityExt;
+	uint8_t		logicalVolContentsUse[32];
+	__le32		numOfPartitions;
+	__le32		lengthOfImpUse;
+	__le32		freeSpaceTable[0];
+	__le32		sizeTable[0];
+	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
 /* Integrity Type (ECMA 167r3 3/10.10.3) */
@@ -367,48 +367,48 @@
 
 /* Recorded Address (ECMA 167r3 4/7.1) */
 typedef struct {
-	__le32 logicalBlockNum;
-	__le16 partitionReferenceNum;
+	__le32		logicalBlockNum;
+	__le16	 	partitionReferenceNum;
 } __attribute__ ((packed)) lb_addr;
 
 /* ... and its in-core analog */
 typedef struct {
-	uint32_t logicalBlockNum;
-	uint16_t partitionReferenceNum;
+	uint32_t		logicalBlockNum;
+	uint16_t	 	partitionReferenceNum;
 } kernel_lb_addr;
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
 typedef struct {
-	__le32 extLength;
-	__le32 extPosition;
+        __le32		extLength;
+        __le32		extPosition;
 } __attribute__ ((packed)) short_ad;
 
 /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
 typedef struct {
-	__le32 extLength;
-	lb_addr extLocation;
-	uint8_t impUse[6];
+	__le32		extLength;
+	lb_addr		extLocation;
+	uint8_t		impUse[6];
 } __attribute__ ((packed)) long_ad;
 
 typedef struct {
-	uint32_t extLength;
-	kernel_lb_addr extLocation;
-	uint8_t impUse[6];
+	uint32_t	extLength;
+	kernel_lb_addr	extLocation;
+	uint8_t		impUse[6];
 } kernel_long_ad;
 
 /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
 typedef struct {
-	__le32 extLength;
-	__le32 recordedLength;
-	__le32 informationLength;
-	lb_addr extLocation;
+	__le32		extLength;
+	__le32		recordedLength;
+	__le32		informationLength;
+	lb_addr		extLocation;
 } __attribute__ ((packed)) ext_ad;
 
 typedef struct {
-	uint32_t extLength;
-	uint32_t recordedLength;
-	uint32_t informationLength;
-	kernel_lb_addr extLocation;
+	uint32_t	extLength;
+	uint32_t	recordedLength;
+	uint32_t	informationLength;
+	kernel_lb_addr	extLocation;
 } kernel_ext_ad;
 
 /* Descriptor Tag (ECMA 167r3 4/7.2 - See 3/7.2) */
@@ -428,48 +428,48 @@
 
 /* File Set Descriptor (ECMA 167r3 4/14.1) */
 struct fileSetDesc {
-	tag descTag;
-	timestamp recordingDateAndTime;
-	__le16 interchangeLvl;
-	__le16 maxInterchangeLvl;
-	__le32 charSetList;
-	__le32 maxCharSetList;
-	__le32 fileSetNum;
-	__le32 fileSetDescNum;
-	charspec logicalVolIdentCharSet;
-	dstring logicalVolIdent[128];
-	charspec fileSetCharSet;
-	dstring fileSetIdent[32];
-	dstring copyrightFileIdent[32];
-	dstring abstractFileIdent[32];
-	long_ad rootDirectoryICB;
-	regid domainIdent;
-	long_ad nextExt;
-	long_ad streamDirectoryICB;
-	uint8_t reserved[32];
+	tag		descTag;
+	timestamp	recordingDateAndTime;
+	__le16		interchangeLvl;
+	__le16		maxInterchangeLvl;
+	__le32		charSetList;
+	__le32		maxCharSetList;
+	__le32		fileSetNum;
+	__le32		fileSetDescNum;
+	charspec	logicalVolIdentCharSet;
+	dstring		logicalVolIdent[128];
+	charspec	fileSetCharSet;
+	dstring		fileSetIdent[32];
+	dstring		copyrightFileIdent[32];
+	dstring		abstractFileIdent[32];
+	long_ad		rootDirectoryICB;
+	regid		domainIdent;
+	long_ad		nextExt;
+	long_ad		streamDirectoryICB;
+	uint8_t		reserved[32];
 } __attribute__ ((packed));
 
 /* Partition Header Descriptor (ECMA 167r3 4/14.3) */
 struct partitionHeaderDesc {
-	short_ad unallocSpaceTable;
-	short_ad unallocSpaceBitmap;
-	short_ad partitionIntegrityTable;
-	short_ad freedSpaceTable;
-	short_ad freedSpaceBitmap;
-	uint8_t reserved[88];
+	short_ad	unallocSpaceTable;
+	short_ad	unallocSpaceBitmap;
+	short_ad	partitionIntegrityTable;
+	short_ad	freedSpaceTable;
+	short_ad	freedSpaceBitmap;
+	uint8_t		reserved[88];
 } __attribute__ ((packed));
 
 /* File Identifier Descriptor (ECMA 167r3 4/14.4) */
 struct fileIdentDesc {
-	tag descTag;
-	__le16 fileVersionNum;
-	uint8_t fileCharacteristics;
-	uint8_t lengthFileIdent;
-	long_ad icb;
-	__le16 lengthOfImpUse;
-	uint8_t impUse[0];
-	uint8_t fileIdent[0];
-	uint8_t padding[0];
+	tag		descTag;
+	__le16		fileVersionNum;
+	uint8_t		fileCharacteristics;
+	uint8_t		lengthFileIdent;
+	long_ad		icb;
+	__le16		lengthOfImpUse;
+	uint8_t		impUse[0];
+	uint8_t		fileIdent[0];
+	uint8_t		padding[0];
 } __attribute__ ((packed));
 
 /* File Characteristics (ECMA 167r3 4/14.4.3) */
@@ -481,21 +481,21 @@
 
 /* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
 struct allocExtDesc {
-	tag descTag;
-	__le32 previousAllocExtLocation;
-	__le32 lengthAllocDescs;
+	tag		descTag;
+	__le32		previousAllocExtLocation;
+	__le32		lengthAllocDescs;
 } __attribute__ ((packed));
 
 /* ICB Tag (ECMA 167r3 4/14.6) */
 typedef struct {
-	__le32 priorRecordedNumDirectEntries;
-	__le16 strategyType;
-	__le16 strategyParameter;
-	__le16 numEntries;
-	uint8_t reserved;
-	uint8_t fileType;
-	lb_addr parentICBLocation;
-	__le16 flags;
+	__le32		priorRecordedNumDirectEntries;
+	__le16		strategyType;
+	__le16		strategyParameter;
+	__le16		numEntries;
+	uint8_t		reserved;
+	uint8_t		fileType;
+	lb_addr		parentICBLocation;
+	__le16		flags;
 } __attribute__ ((packed)) icbtag;
 
 /* Strategy Type (ECMA 167r3 4/14.6.2) */
@@ -541,41 +541,41 @@
 
 /* Indirect Entry (ECMA 167r3 4/14.7) */
 struct indirectEntry {
-	tag descTag;
-	icbtag icbTag;
-	long_ad indirectICB;
+	tag		descTag;
+	icbtag		icbTag;
+	long_ad		indirectICB;
 } __attribute__ ((packed));
 
 /* Terminal Entry (ECMA 167r3 4/14.8) */
 struct terminalEntry {
-	tag descTag;
-	icbtag icbTag;
+	tag		descTag;
+	icbtag		icbTag;
 } __attribute__ ((packed));
 
 /* File Entry (ECMA 167r3 4/14.9) */
 struct fileEntry {
-	tag descTag;
-	icbtag icbTag;
-	__le32 uid;
-	__le32 gid;
-	__le32 permissions;
-	__le16 fileLinkCount;
-	uint8_t recordFormat;
-	uint8_t recordDisplayAttr;
-	__le32 recordLength;
-	__le64 informationLength;
-	__le64 logicalBlocksRecorded;
-	timestamp accessTime;
-	timestamp modificationTime;
-	timestamp attrTime;
-	__le32 checkpoint;
-	long_ad extendedAttrICB;
-	regid impIdent;
-	__le64 uniqueID;
-	__le32 lengthExtendedAttr;
-	__le32 lengthAllocDescs;
-	uint8_t extendedAttr[0];
-	uint8_t allocDescs[0];
+	tag		descTag;
+	icbtag		icbTag;
+	__le32		uid;
+	__le32		gid;
+	__le32		permissions;
+	__le16		fileLinkCount;
+	uint8_t		recordFormat;
+	uint8_t		recordDisplayAttr;
+	__le32		recordLength;
+	__le64		informationLength;
+	__le64		logicalBlocksRecorded;
+	timestamp	accessTime;
+	timestamp	modificationTime;
+	timestamp	attrTime;
+	__le32		checkpoint;
+	long_ad		extendedAttrICB;
+	regid		impIdent;
+	__le64		uniqueID;
+	__le32		lengthExtendedAttr;
+	__le32		lengthAllocDescs;
+	uint8_t		extendedAttr[0];
+	uint8_t		allocDescs[0];
 } __attribute__ ((packed));
 
 /* Permissions (ECMA 167r3 4/14.9.5) */
@@ -617,51 +617,51 @@
 
 /* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
 struct extendedAttrHeaderDesc {
-	tag descTag;
-	__le32 impAttrLocation;
-	__le32 appAttrLocation;
+	tag		descTag;
+	__le32		impAttrLocation;
+	__le32		appAttrLocation;
 } __attribute__ ((packed));
 
 /* Generic Format (ECMA 167r3 4/14.10.2) */
 struct genericFormat {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	uint8_t attrData[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	uint8_t		attrData[0];
 } __attribute__ ((packed));
 
 /* Character Set Information (ECMA 167r3 4/14.10.3) */
 struct charSetInfo {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 escapeSeqLength;
-	uint8_t charSetType;
-	uint8_t escapeSeq[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		escapeSeqLength;
+	uint8_t		charSetType;
+	uint8_t		escapeSeq[0];
 } __attribute__ ((packed));
 
 /* Alternate Permissions (ECMA 167r3 4/14.10.4) */
 struct altPerms {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le16 ownerIdent;
-	__le16 groupIdent;
-	__le16 permission;
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le16		ownerIdent;
+	__le16		groupIdent;
+	__le16		permission;
 } __attribute__ ((packed));
 
 /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
 struct fileTimesExtAttr {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 dataLength;
-	__le32 fileTimeExistence;
-	uint8_t fileTimes;
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		dataLength;
+	__le32		fileTimeExistence;
+	uint8_t		fileTimes;
 } __attribute__ ((packed));
 
 /* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */
@@ -672,47 +672,47 @@
 
 /* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */
 struct infoTimesExtAttr {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 dataLength;
-	__le32 infoTimeExistence;
-	uint8_t infoTimes[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		dataLength;
+	__le32		infoTimeExistence;
+	uint8_t		infoTimes[0];
 } __attribute__ ((packed));
 
 /* Device Specification (ECMA 167r3 4/14.10.7) */
 struct deviceSpec {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 impUseLength;
-	__le32 majorDeviceIdent;
-	__le32 minorDeviceIdent;
-	uint8_t impUse[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		impUseLength;
+	__le32		majorDeviceIdent;
+	__le32		minorDeviceIdent;
+	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
 /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
 struct impUseExtAttr {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 impUseLength;
-	regid impIdent;
-	uint8_t impUse[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		impUseLength;
+	regid		impIdent;
+	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
 /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
 struct appUseExtAttr {
-	__le32 attrType;
-	uint8_t attrSubtype;
-	uint8_t reserved[3];
-	__le32 attrLength;
-	__le32 appUseLength;
-	regid appIdent;
-	uint8_t appUse[0];
+	__le32		attrType;
+	uint8_t		attrSubtype;
+	uint8_t		reserved[3];
+	__le32		attrLength;
+	__le32		appUseLength;
+	regid		appIdent;
+	uint8_t		appUse[0];
 } __attribute__ ((packed));
 
 #define EXTATTR_CHAR_SET		1
@@ -725,29 +725,29 @@
 
 /* Unallocated Space Entry (ECMA 167r3 4/14.11) */
 struct unallocSpaceEntry {
-	tag descTag;
-	icbtag icbTag;
-	__le32 lengthAllocDescs;
-	uint8_t allocDescs[0];
+	tag		descTag;
+	icbtag		icbTag;
+	__le32		lengthAllocDescs;
+	uint8_t		allocDescs[0];
 } __attribute__ ((packed));
 
 /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
 struct spaceBitmapDesc {
-	tag descTag;
-	__le32 numOfBits;
-	__le32 numOfBytes;
-	uint8_t bitmap[0];
+	tag		descTag;
+	__le32		numOfBits;
+	__le32		numOfBytes;
+	uint8_t		bitmap[0];
 } __attribute__ ((packed));
 
 /* Partition Integrity Entry (ECMA 167r3 4/14.13) */
 struct partitionIntegrityEntry {
-	tag descTag;
-	icbtag icbTag;
-	timestamp recordingDateAndTime;
-	uint8_t integrityType;
-	uint8_t reserved[175];
-	regid impIdent;
-	uint8_t impUse[256];
+	tag		descTag;
+	icbtag		icbTag;
+	timestamp	recordingDateAndTime;
+	uint8_t		integrityType;
+	uint8_t		reserved[175];
+	regid		impIdent;
+	uint8_t		impUse[256];
 } __attribute__ ((packed));
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
@@ -764,46 +764,46 @@
 
 /* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */
 struct logicalVolHeaderDesc {
-	__le64 uniqueID;
-	uint8_t reserved[24];
+	__le64		uniqueID;
+	uint8_t		reserved[24];
 } __attribute__ ((packed));
 
 /* Path Component (ECMA 167r3 4/14.16.1) */
 struct pathComponent {
-	uint8_t componentType;
-	uint8_t lengthComponentIdent;
-	__le16 componentFileVersionNum;
-	dstring componentIdent[0];
+	uint8_t		componentType;
+	uint8_t		lengthComponentIdent;
+	__le16		componentFileVersionNum;
+	dstring		componentIdent[0];
 } __attribute__ ((packed));
 
 /* File Entry (ECMA 167r3 4/14.17) */
 struct extendedFileEntry {
-	tag descTag;
-	icbtag icbTag;
-	__le32 uid;
-	__le32 gid;
-	__le32 permissions;
-	__le16 fileLinkCount;
-	uint8_t recordFormat;
-	uint8_t recordDisplayAttr;
-	__le32 recordLength;
-	__le64 informationLength;
-	__le64 objectSize;
-	__le64 logicalBlocksRecorded;
-	timestamp accessTime;
-	timestamp modificationTime;
-	timestamp createTime;
-	timestamp attrTime;
-	__le32 checkpoint;
-	__le32 reserved;
-	long_ad extendedAttrICB;
-	long_ad streamDirectoryICB;
-	regid impIdent;
-	__le64 uniqueID;
-	__le32 lengthExtendedAttr;
-	__le32 lengthAllocDescs;
-	uint8_t extendedAttr[0];
-	uint8_t allocDescs[0];
+	tag		descTag;
+	icbtag		icbTag;
+	__le32		uid;
+	__le32		gid;
+	__le32		permissions;
+	__le16		fileLinkCount;
+	uint8_t		recordFormat;
+	uint8_t		recordDisplayAttr;
+	__le32		recordLength;
+	__le64		informationLength;
+	__le64		objectSize;
+	__le64		logicalBlocksRecorded;
+	timestamp	accessTime;
+	timestamp	modificationTime;
+	timestamp	createTime;
+	timestamp	attrTime;
+	__le32		checkpoint;
+	__le32		reserved;
+	long_ad		extendedAttrICB;
+	long_ad		streamDirectoryICB;
+	regid		impIdent;
+	__le64		uniqueID;
+	__le32		lengthExtendedAttr;
+	__le32		lengthAllocDescs;
+	uint8_t		extendedAttr[0];
+	uint8_t		allocDescs[0];
 } __attribute__ ((packed));
 
-#endif				/* _ECMA_167_H */
+#endif /* _ECMA_167_H */
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 67bf36b..5d7a4ea 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -30,7 +30,7 @@
 #include <linux/udf_fs.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
-#include <linux/string.h>	/* memset */
+#include <linux/string.h> /* memset */
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
@@ -55,11 +55,11 @@
 	SetPageUptodate(page);
 	kunmap(page);
 	unlock_page(page);
+
 	return 0;
 }
 
-static int udf_adinicb_writepage(struct page *page,
-				 struct writeback_control *wbc)
+static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc)
 {
 	struct inode *inode = page->mapping->host;
 	char *kaddr;
@@ -72,6 +72,7 @@
 	SetPageUptodate(page);
 	kunmap(page);
 	unlock_page(page);
+
 	return 0;
 }
 
@@ -100,11 +101,11 @@
 }
 
 const struct address_space_operations udf_adinicb_aops = {
-	.readpage = udf_adinicb_readpage,
-	.writepage = udf_adinicb_writepage,
-	.sync_page = block_sync_page,
-	.prepare_write = udf_adinicb_prepare_write,
-	.commit_write = udf_adinicb_commit_write,
+	.readpage	= udf_adinicb_readpage,
+	.writepage	= udf_adinicb_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= udf_adinicb_prepare_write,
+	.commit_write	= udf_adinicb_commit_write,
 };
 
 static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
@@ -122,8 +123,8 @@
 		else
 			pos = ppos;
 
-		if (inode->i_sb->s_blocksize <
-		    (udf_file_entry_alloc_offset(inode) + pos + count)) {
+		if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
+						pos + count)) {
 			udf_expand_file_adinicb(inode, pos + count, &err);
 			if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
 				udf_debug("udf_expand_adinicb: err=%d\n", err);
@@ -138,9 +139,9 @@
 	}
 
 	retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
-
 	if (retval > 0)
 		mark_inode_dirty(inode);
+
 	return retval;
 }
 
@@ -181,10 +182,12 @@
 int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 	      unsigned long arg)
 {
+	long old_block, new_block;
 	int result = -EINVAL;
 
 	if (file_permission(filp, MAY_READ) != 0) {
-		udf_debug("no permission to access inode %lu\n", inode->i_ino);
+		udf_debug("no permission to access inode %lu\n",
+			  inode->i_ino);
 		return -EPERM;
 	}
 
@@ -196,26 +199,19 @@
 	switch (cmd) {
 	case UDF_GETVOLIDENT:
 		return copy_to_user((char __user *)arg,
-				    UDF_SB_VOLIDENT(inode->i_sb),
-				    32) ? -EFAULT : 0;
+				    UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
 	case UDF_RELOCATE_BLOCKS:
-		{
-			long old, new;
-
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (get_user(old, (long __user *)arg))
-				return -EFAULT;
-			if ((result = udf_relocate_blocks(inode->i_sb,
-							  old, &new)) == 0)
-				result = put_user(new, (long __user *)arg);
-
-			return result;
-		}
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (get_user(old_block, (long __user *)arg))
+			return -EFAULT;
+		if ((result = udf_relocate_blocks(inode->i_sb,
+						  old_block, &new_block)) == 0)
+			result = put_user(new_block, (long __user *)arg);
+		return result;
 	case UDF_GETEASIZE:
 		result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
 		break;
-
 	case UDF_GETEABLOCK:
 		result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
 				      UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
@@ -248,16 +244,16 @@
 }
 
 const struct file_operations udf_file_operations = {
-	.read = do_sync_read,
-	.aio_read = generic_file_aio_read,
-	.ioctl = udf_ioctl,
-	.open = generic_file_open,
-	.mmap = generic_file_mmap,
-	.write = do_sync_write,
-	.aio_write = udf_file_aio_write,
-	.release = udf_release_file,
-	.fsync = udf_fsync_file,
-	.splice_read = generic_file_splice_read,
+	.read			= do_sync_read,
+	.aio_read		= generic_file_aio_read,
+	.ioctl			= udf_ioctl,
+	.open			= generic_file_open,
+	.mmap			= generic_file_mmap,
+	.write			= do_sync_write,
+	.aio_write		= udf_file_aio_write,
+	.release		= udf_release_file,
+	.fsync			= udf_fsync_file,
+	.splice_read		= generic_file_splice_read,
 };
 
 const struct inode_operations udf_file_inode_operations = {
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index 7f0901c..b2c472b 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -32,6 +32,7 @@
 int udf_fsync_file(struct file *file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
+
 	return udf_fsync_inode(inode, datasync);
 }
 
@@ -46,5 +47,6 @@
 		return err;
 
 	err |= udf_sync_inode(inode);
+
 	return err ? -EIO : 0;
 }
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 2eb5038..636d8f6 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -46,12 +46,10 @@
 	if (sbi->s_lvidbh) {
 		if (S_ISDIR(inode->i_mode))
 			UDF_SB_LVIDIU(sb)->numDirs =
-			    cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)
-					- 1);
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1);
 		else
 			UDF_SB_LVIDIU(sb)->numFiles =
-			    cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles)
-					- 1);
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
 
 		mark_buffer_dirty(sbi->s_lvidbh);
 	}
@@ -82,10 +80,8 @@
 	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 	UDF_I_STRAT4096(inode) = 0;
 
-	block =
-	    udf_new_block(dir->i_sb, NULL,
-			  UDF_I_LOCATION(dir).partitionReferenceNum, start,
-			  err);
+	block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
+			      start, err);
 	if (*err) {
 		iput(inode);
 		return NULL;
@@ -95,17 +91,13 @@
 	if (UDF_SB_LVIDBH(sb)) {
 		struct logicalVolHeaderDesc *lvhd;
 		uint64_t uniqueID;
-		lvhd =
-		    (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->
-						    logicalVolContentsUse);
+		lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
 		if (S_ISDIR(mode))
 			UDF_SB_LVIDIU(sb)->numDirs =
-			    cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)
-					+ 1);
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1);
 		else
 			UDF_SB_LVIDIU(sb)->numFiles =
-			    cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles)
-					+ 1);
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1);
 		UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID);
 		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
 			uniqueID += 16;
@@ -118,12 +110,12 @@
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
-	} else
+	} else {
 		inode->i_gid = current->fsgid;
+	}
 
 	UDF_I_LOCATION(inode).logicalBlockNum = block;
-	UDF_I_LOCATION(inode).partitionReferenceNum =
-	    UDF_I_LOCATION(dir).partitionReferenceNum;
+	UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
 	inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
 	inode->i_blocks = 0;
 	UDF_I_LENEATTR(inode) = 0;
@@ -132,14 +124,10 @@
 	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
 		UDF_I_EFE(inode) = 1;
 		UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
-		UDF_I_DATA(inode) =
-		    kzalloc(inode->i_sb->s_blocksize -
-			    sizeof(struct extendedFileEntry), GFP_KERNEL);
+		UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
 	} else {
 		UDF_I_EFE(inode) = 0;
-		UDF_I_DATA(inode) =
-		    kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry),
-			    GFP_KERNEL);
+		UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
 	}
 	if (!UDF_I_DATA(inode)) {
 		iput(inode);
@@ -154,7 +142,7 @@
 	else
 		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;
 	inode->i_mtime = inode->i_atime = inode->i_ctime =
-	    UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb);
+		UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb);
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 	mutex_unlock(&sbi->s_alloc_mutex);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index be6326f..0d2c416 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -97,7 +97,8 @@
 
 	unlock_kernel();
 	return;
-      no_delete:
+
+no_delete:
 	clear_inode(inode);
 }
 
@@ -144,12 +145,12 @@
 }
 
 const struct address_space_operations udf_aops = {
-	.readpage = udf_readpage,
-	.writepage = udf_writepage,
-	.sync_page = block_sync_page,
-	.prepare_write = udf_prepare_write,
-	.commit_write = generic_commit_write,
-	.bmap = udf_bmap,
+	.readpage	= udf_readpage,
+	.writepage	= udf_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= udf_prepare_write,
+	.commit_write	= generic_commit_write,
+	.bmap		= udf_bmap,
 };
 
 void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
@@ -230,12 +231,10 @@
 	*block = udf_new_block(inode->i_sb, inode,
 			       UDF_I_LOCATION(inode).partitionReferenceNum,
 			       UDF_I_LOCATION(inode).logicalBlockNum, err);
-
 	if (!(*block))
 		return NULL;
 	newblock = udf_get_pblock(inode->i_sb, *block,
-				  UDF_I_LOCATION(inode).partitionReferenceNum,
-				  0);
+				  UDF_I_LOCATION(inode).partitionReferenceNum, 0);
 	if (!newblock)
 		return NULL;
 	dbh = udf_tgetblk(inode->i_sb, newblock);
@@ -247,16 +246,13 @@
 	unlock_buffer(dbh);
 	mark_buffer_dirty_inode(dbh, inode);
 
-	sfibh.soffset = sfibh.eoffset =
-	    (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
+	sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
 	sfibh.sbh = sfibh.ebh = NULL;
 	dfibh.soffset = dfibh.eoffset = 0;
 	dfibh.sbh = dfibh.ebh = dbh;
 	while ((f_pos < size)) {
 		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
-		sfi =
-		    udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL,
-				       NULL, NULL);
+		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
 		if (!sfi) {
 			brelse(dbh);
 			return NULL;
@@ -267,8 +263,7 @@
 		dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
 		dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);
 		if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
-				 sfi->fileIdent +
-				 le16_to_cpu(sfi->lengthOfImpUse))) {
+				 sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse))) {
 			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
 			brelse(dbh);
 			return NULL;
@@ -276,12 +271,10 @@
 	}
 	mark_buffer_dirty_inode(dbh, inode);
 
-	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0,
-	       UDF_I_LENALLOC(inode));
+	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));
 	UDF_I_LENALLOC(inode) = 0;
 	eloc.logicalBlockNum = *block;
-	eloc.partitionReferenceNum =
-	    UDF_I_LOCATION(inode).partitionReferenceNum;
+	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 	elen = inode->i_size;
 	UDF_I_LENEXTENTS(inode) = elen;
 	epos.bh = NULL;
@@ -334,11 +327,12 @@
 	if (new)
 		set_buffer_new(bh_result);
 	map_bh(bh_result, inode->i_sb, phys);
-      abort:
+
+abort:
 	unlock_kernel();
 	return err;
 
-      abort_negative:
+abort_negative:
 	udf_warning(inode->i_sb, "udf_get_block", "block < 0");
 	goto abort;
 }
@@ -346,13 +340,13 @@
 static struct buffer_head *udf_getblk(struct inode *inode, long block,
 				      int create, int *err)
 {
+	struct buffer_head *bh;
 	struct buffer_head dummy;
 
 	dummy.b_state = 0;
 	dummy.b_blocknr = -1000;
 	*err = udf_get_block(inode, block, &dummy, create);
 	if (!*err && buffer_mapped(&dummy)) {
-		struct buffer_head *bh;
 		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (buffer_new(&dummy)) {
 			lock_buffer(bh);
@@ -363,6 +357,7 @@
 		}
 		return bh;
 	}
+
 	return NULL;
 }
 
@@ -373,42 +368,41 @@
 	sector_t add;
 	int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
 	struct super_block *sb = inode->i_sb;
-	kernel_lb_addr prealloc_loc = { 0, 0 };
+	kernel_lb_addr prealloc_loc = {};
 	int prealloc_len = 0;
 
 	/* The previous extent is fake and we should not extend by anything
 	 * - there's nothing to do... */
 	if (!blocks && fake)
 		return 0;
+
 	/* Round the last extent up to a multiple of block size */
 	if (last_ext->extLength & (sb->s_blocksize - 1)) {
 		last_ext->extLength =
-		    (last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
-		    (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
-		      sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+			(last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
+			(((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
+			  sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
 		UDF_I_LENEXTENTS(inode) =
-		    (UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
-		    ~(sb->s_blocksize - 1);
+			(UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
+			~(sb->s_blocksize - 1);
 	}
+
 	/* Last extent are just preallocated blocks? */
-	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
-	    EXT_NOT_RECORDED_ALLOCATED) {
+	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
 		/* Save the extent so that we can reattach it to the end */
 		prealloc_loc = last_ext->extLocation;
 		prealloc_len = last_ext->extLength;
 		/* Mark the extent as a hole */
 		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-		    (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+			(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
 		last_ext->extLocation.logicalBlockNum = 0;
-		last_ext->extLocation.partitionReferenceNum = 0;
+       		last_ext->extLocation.partitionReferenceNum = 0;
 	}
+
 	/* Can we merge with the previous extent? */
-	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
-	    EXT_NOT_RECORDED_NOT_ALLOCATED) {
-		add =
-		    ((1 << 30) - sb->s_blocksize -
-		     (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) >> sb->
-		    s_blocksize_bits;
+	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
+		add = ((1 << 30) - sb->s_blocksize - (last_ext->extLength &
+						      UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
 		if (add > blocks)
 			add = blocks;
 		blocks -= add;
@@ -419,19 +413,20 @@
 		udf_add_aext(inode, last_pos, last_ext->extLocation,
 			     last_ext->extLength, 1);
 		count++;
-	} else
-		udf_write_aext(inode, last_pos, last_ext->extLocation,
-			       last_ext->extLength, 1);
+	} else {
+		udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
+	}
+
 	/* Managed to do everything necessary? */
 	if (!blocks)
 		goto out;
 
 	/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
 	last_ext->extLocation.logicalBlockNum = 0;
-	last_ext->extLocation.partitionReferenceNum = 0;
-	add = (1 << (30 - sb->s_blocksize_bits)) - 1;
-	last_ext->extLength =
-	    EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+       	last_ext->extLocation.partitionReferenceNum = 0;
+	add = (1 << (30-sb->s_blocksize_bits)) - 1;
+	last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+
 	/* Create enough extents to cover the whole hole */
 	while (blocks > add) {
 		blocks -= add;
@@ -442,22 +437,23 @@
 	}
 	if (blocks) {
 		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-		    (blocks << sb->s_blocksize_bits);
+			(blocks << sb->s_blocksize_bits);
 		if (udf_add_aext(inode, last_pos, last_ext->extLocation,
 				 last_ext->extLength, 1) == -1)
 			return -1;
 		count++;
 	}
-      out:
+
+out:
 	/* Do we have some preallocated blocks saved? */
 	if (prealloc_len) {
-		if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1)
-		    == -1)
+		if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1)
 			return -1;
 		last_ext->extLocation = prealloc_loc;
 		last_ext->extLength = prealloc_len;
 		count++;
 	}
+
 	/* last_pos should point to the last written extent... */
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
 		last_pos->offset -= sizeof(short_ad);
@@ -465,6 +461,7 @@
 		last_pos->offset -= sizeof(long_ad);
 	else
 		return -1;
+
 	return count;
 }
 
@@ -490,7 +487,7 @@
 	prev_epos.block = UDF_I_LOCATION(inode);
 	prev_epos.bh = NULL;
 	cur_epos = next_epos = prev_epos;
-	b_off = (loff_t) block << inode->i_sb->s_blocksize_bits;
+	b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
 
 	/* find the extent which contains the block we are looking for.
 	   alternate between laarr[0] and laarr[1] for locations of the
@@ -515,8 +512,7 @@
 		prev_epos.offset = cur_epos.offset;
 		cur_epos.offset = next_epos.offset;
 
-		if ((etype =
-		     udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1)
+		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1)
 			break;
 
 		c = !c;
@@ -526,8 +522,8 @@
 
 		if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
 			pgoal = eloc.logicalBlockNum +
-			    ((elen + inode->i_sb->s_blocksize - 1) >>
-			     inode->i_sb->s_blocksize_bits);
+				((elen + inode->i_sb->s_blocksize - 1) >>
+				 inode->i_sb->s_blocksize_bits);
 
 		count++;
 	} while (lbcount + elen <= b_off);
@@ -547,8 +543,8 @@
 	if (etype == (EXT_RECORDED_ALLOCATED >> 30)) {
 		if (elen & (inode->i_sb->s_blocksize - 1)) {
 			elen = EXT_RECORDED_ALLOCATED |
-			    ((elen + inode->i_sb->s_blocksize - 1) &
-			     ~(inode->i_sb->s_blocksize - 1));
+				((elen + inode->i_sb->s_blocksize - 1) &
+				 ~(inode->i_sb->s_blocksize - 1));
 			etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
 		}
 		brelse(prev_epos.bh);
@@ -570,8 +566,7 @@
 			startnum = 1;
 		} else {
 			/* Create a fake extent when there's not one */
-			memset(&laarr[0].extLocation, 0x00,
-			       sizeof(kernel_lb_addr));
+			memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
 			laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
 			/* Will udf_extend_file() create real extent from a fake one? */
 			startnum = (offset > 0);
@@ -591,16 +586,14 @@
 		offset = 0;
 		count += ret;
 		/* We are not covered by a preallocated extent? */
-		if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) !=
-		    EXT_NOT_RECORDED_ALLOCATED) {
+		if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) {
 			/* Is there any real extent? - otherwise we overwrite
 			 * the fake one... */
 			if (count)
 				c = !c;
 			laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-			    inode->i_sb->s_blocksize;
-			memset(&laarr[c].extLocation, 0x00,
-			       sizeof(kernel_lb_addr));
+				inode->i_sb->s_blocksize;
+			memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
 			count++;
 			endnum++;
 		}
@@ -618,8 +611,7 @@
 		}
 
 		/* if the current block is located in an extent, read the next extent */
-		if ((etype =
-		     udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) {
+		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) {
 			laarr[c + 1].extLength = (etype << 30) | elen;
 			laarr[c + 1].extLocation = eloc;
 			count++;
@@ -631,24 +623,21 @@
 	}
 
 	/* if the current extent is not recorded but allocated, get the
-	   block in the extent corresponding to the requested block */
-	if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+	 * block in the extent corresponding to the requested block */
+	if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
 		newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
-	else {			/* otherwise, allocate a new block */
-
+	} else { /* otherwise, allocate a new block */
 		if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
 			goal = UDF_I_NEXT_ALLOC_GOAL(inode);
 
 		if (!goal) {
 			if (!(goal = pgoal))
-				goal =
-				    UDF_I_LOCATION(inode).logicalBlockNum + 1;
+				goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
 		}
 
 		if (!(newblocknum = udf_new_block(inode->i_sb, inode,
-						  UDF_I_LOCATION(inode).
-						  partitionReferenceNum, goal,
-						  err))) {
+						  UDF_I_LOCATION(inode).partitionReferenceNum,
+						  goal, err))) {
 			brelse(prev_epos.bh);
 			*err = -ENOSPC;
 			return NULL;
@@ -657,8 +646,8 @@
 	}
 
 	/* if the extent the requsted block is located in contains multiple blocks,
-	   split the extent into at most three extents. blocks prior to requested
-	   block, requested block, and blocks after requested block */
+	 * split the extent into at most three extents. blocks prior to requested
+	 * block, requested block, and blocks after requested block */
 	udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
 
 #ifdef UDF_PREALLOCATE
@@ -670,15 +659,14 @@
 	udf_merge_extents(inode, laarr, &endnum);
 
 	/* write back the new extents, inserting new extents if the new number
-	   of extents is greater than the old number, and deleting extents if
-	   the new number of extents is less than the old number */
+	 * of extents is greater than the old number, and deleting extents if
+	 * the new number of extents is less than the old number */
 	udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
 
 	brelse(prev_epos.bh);
 
 	if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
-					UDF_I_LOCATION(inode).
-					partitionReferenceNum, 0))) {
+					UDF_I_LOCATION(inode).partitionReferenceNum, 0))) {
 		return NULL;
 	}
 	*phys = newblock;
@@ -692,6 +680,7 @@
 		udf_sync_inode(inode);
 	else
 		mark_inode_dirty(inode);
+
 	return result;
 }
 
@@ -701,16 +690,15 @@
 			      int *endnum)
 {
 	if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) ||
-	    (laarr[*c].extLength >> 30) ==
-	    (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
+	    (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
 		int curr = *c;
 		int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
-			    inode->i_sb->s_blocksize -
-			    1) >> inode->i_sb->s_blocksize_bits;
+			    inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
 		int8_t etype = (laarr[curr].extLength >> 30);
 
-		if (blen == 1) ;
-		else if (!offset || blen == offset + 1) {
+		if (blen == 1) {
+			;
+		} else if (!offset || blen == offset + 1) {
 			laarr[curr + 2] = laarr[curr + 1];
 			laarr[curr + 1] = laarr[curr];
 		} else {
@@ -720,20 +708,15 @@
 
 		if (offset) {
 			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
-				udf_free_blocks(inode->i_sb, inode,
-						laarr[curr].extLocation, 0,
-						offset);
-				laarr[curr].extLength =
-				    EXT_NOT_RECORDED_NOT_ALLOCATED | (offset <<
-								      inode->
-								      i_sb->
-								      s_blocksize_bits);
+				udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
+				laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+					(offset << inode->i_sb->s_blocksize_bits);
 				laarr[curr].extLocation.logicalBlockNum = 0;
-				laarr[curr].extLocation.partitionReferenceNum =
-				    0;
-			} else
+				laarr[curr].extLocation.partitionReferenceNum = 0;
+			} else {
 				laarr[curr].extLength = (etype << 30) |
-				    (offset << inode->i_sb->s_blocksize_bits);
+					(offset << inode->i_sb->s_blocksize_bits);
+			}
 			curr++;
 			(*c)++;
 			(*endnum)++;
@@ -742,18 +725,16 @@
 		laarr[curr].extLocation.logicalBlockNum = newblocknum;
 		if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
 			laarr[curr].extLocation.partitionReferenceNum =
-			    UDF_I_LOCATION(inode).partitionReferenceNum;
+				UDF_I_LOCATION(inode).partitionReferenceNum;
 		laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
-		    inode->i_sb->s_blocksize;
+			inode->i_sb->s_blocksize;
 		curr++;
 
 		if (blen != offset + 1) {
 			if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-				laarr[curr].extLocation.logicalBlockNum +=
-				    (offset + 1);
-			laarr[curr].extLength =
-			    (etype << 30) | ((blen - (offset + 1)) << inode->
-					     i_sb->s_blocksize_bits);
+				laarr[curr].extLocation.logicalBlockNum += (offset + 1);
+			laarr[curr].extLength = (etype << 30) |
+				((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
 			curr++;
 			(*endnum)++;
 		}
@@ -772,90 +753,69 @@
 		else
 			start = c;
 	} else {
-		if ((laarr[c + 1].extLength >> 30) ==
-		    (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+		if ((laarr[c + 1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
 			start = c + 1;
-			length = currlength =
-			    (((laarr[c + 1].
-			       extLength & UDF_EXTENT_LENGTH_MASK) +
-			      inode->i_sb->s_blocksize -
-			      1) >> inode->i_sb->s_blocksize_bits);
-		} else
+			length = currlength = (((laarr[c + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+						inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		} else {
 			start = c;
+		}
 	}
 
 	for (i = start + 1; i <= *endnum; i++) {
 		if (i == *endnum) {
 			if (lastblock)
 				length += UDF_DEFAULT_PREALLOC_BLOCKS;
-		} else if ((laarr[i].extLength >> 30) ==
-			   (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
-			length +=
-			    (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-			      inode->i_sb->s_blocksize -
-			      1) >> inode->i_sb->s_blocksize_bits);
-		else
+		} else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
+			length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				    inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		} else {
 			break;
+		}
 	}
 
 	if (length) {
 		int next = laarr[start].extLocation.logicalBlockNum +
-		    (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
-		      inode->i_sb->s_blocksize -
-		      1) >> inode->i_sb->s_blocksize_bits);
+			(((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
+			  inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
 		int numalloc = udf_prealloc_blocks(inode->i_sb, inode,
-						   laarr[start].extLocation.
-						   partitionReferenceNum,
-						   next,
-						   (UDF_DEFAULT_PREALLOC_BLOCKS
-						    >
-						    length ? length :
-						    UDF_DEFAULT_PREALLOC_BLOCKS)
-						   - currlength);
-
-		if (numalloc) {
-			if (start == (c + 1))
+						   laarr[start].extLocation.partitionReferenceNum,
+						   next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
+							  UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
+		if (numalloc) 	{
+			if (start == (c + 1)) {
 				laarr[start].extLength +=
-				    (numalloc << inode->i_sb->s_blocksize_bits);
-			else {
+					(numalloc << inode->i_sb->s_blocksize_bits);
+			} else {
 				memmove(&laarr[c + 2], &laarr[c + 1],
 					sizeof(long_ad) * (*endnum - (c + 1)));
 				(*endnum)++;
 				laarr[c + 1].extLocation.logicalBlockNum = next;
 				laarr[c + 1].extLocation.partitionReferenceNum =
-				    laarr[c].extLocation.partitionReferenceNum;
-				laarr[c + 1].extLength =
-				    EXT_NOT_RECORDED_ALLOCATED | (numalloc <<
-								  inode->i_sb->
-								  s_blocksize_bits);
+					laarr[c].extLocation.partitionReferenceNum;
+				laarr[c + 1].extLength = EXT_NOT_RECORDED_ALLOCATED |
+					(numalloc << inode->i_sb->s_blocksize_bits);
 				start = c + 1;
 			}
 
 			for (i = start + 1; numalloc && i < *endnum; i++) {
-				int elen =
-				    ((laarr[i].
-				      extLength & UDF_EXTENT_LENGTH_MASK) +
-				     inode->i_sb->s_blocksize -
-				     1) >> inode->i_sb->s_blocksize_bits;
+				int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					    inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
 
 				if (elen > numalloc) {
 					laarr[i].extLength -=
-					    (numalloc << inode->i_sb->
-					     s_blocksize_bits);
+						(numalloc << inode->i_sb->s_blocksize_bits);
 					numalloc = 0;
 				} else {
 					numalloc -= elen;
 					if (*endnum > (i + 1))
-						memmove(&laarr[i],
-							&laarr[i + 1],
-							sizeof(long_ad) *
-							(*endnum - (i + 1)));
+						memmove(&laarr[i], &laarr[i + 1],
+							sizeof(long_ad) * (*endnum - (i + 1)));
 					i--;
 					(*endnum)--;
 				}
 			}
-			UDF_I_LENEXTENTS(inode) +=
-			    numalloc << inode->i_sb->s_blocksize_bits;
+			UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits;
 		}
 	}
 }
@@ -867,119 +827,68 @@
 	int i;
 
 	for (i = 0; i < (*endnum - 1); i++) {
-		if ((laarr[i].extLength >> 30) ==
-		    (laarr[i + 1].extLength >> 30)) {
-			if (((laarr[i].extLength >> 30) ==
-			     (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
-			    ||
-			    ((laarr[i + 1].extLocation.logicalBlockNum -
-			      laarr[i].extLocation.logicalBlockNum) ==
+		if ((laarr[i].extLength >> 30) == (laarr[i + 1].extLength >> 30)) {
+			if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) ||
+			    ((laarr[i + 1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
 			     (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
-			       inode->i_sb->s_blocksize -
-			       1) >> inode->i_sb->s_blocksize_bits))) {
-				if (((laarr[i].
-				      extLength & UDF_EXTENT_LENGTH_MASK) +
-				     (laarr[i + 1].
-				      extLength & UDF_EXTENT_LENGTH_MASK) +
-				     inode->i_sb->s_blocksize -
-				     1) & ~UDF_EXTENT_LENGTH_MASK) {
-					laarr[i + 1].extLength =
-					    (laarr[i + 1].extLength -
-					     (laarr[i].
-					      extLength &
-					      UDF_EXTENT_LENGTH_MASK) +
-					     UDF_EXTENT_LENGTH_MASK) & ~(inode->
-									 i_sb->
-									 s_blocksize
-									 - 1);
-					laarr[i].extLength =
-					    (laarr[i].
-					     extLength & UDF_EXTENT_FLAG_MASK) +
-					    (UDF_EXTENT_LENGTH_MASK + 1) -
-					    inode->i_sb->s_blocksize;
-					laarr[i +
-					      1].extLocation.logicalBlockNum =
-					    laarr[i].extLocation.
-					    logicalBlockNum +
-					    ((laarr[i].
-					      extLength &
-					      UDF_EXTENT_LENGTH_MASK) >> inode->
-					     i_sb->s_blocksize_bits);
+			       inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))) {
+				if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				     (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+				     inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+					laarr[i + 1].extLength = (laarr[i + 1].extLength -
+								  (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+								  UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
+					laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+						(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
+					laarr[i + 1].extLocation.logicalBlockNum =
+						laarr[i].extLocation.logicalBlockNum +
+						((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
+						 inode->i_sb->s_blocksize_bits);
 				} else {
-					laarr[i].extLength =
-					    laarr[i + 1].extLength +
-					    (((laarr[i].
-					       extLength &
-					       UDF_EXTENT_LENGTH_MASK) +
-					      inode->i_sb->s_blocksize -
-					      1) & ~(inode->i_sb->s_blocksize -
-						     1));
+					laarr[i].extLength = laarr[i + 1].extLength +
+						(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+						  inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
 					if (*endnum > (i + 2))
-						memmove(&laarr[i + 1],
-							&laarr[i + 2],
-							sizeof(long_ad) *
-							(*endnum - (i + 2)));
+						memmove(&laarr[i + 1], &laarr[i + 2],
+							sizeof(long_ad) * (*endnum - (i + 2)));
 					i--;
 					(*endnum)--;
 				}
 			}
-		} else
-		    if (((laarr[i].extLength >> 30) ==
-			 (EXT_NOT_RECORDED_ALLOCATED >> 30))
-			&& ((laarr[i + 1].extLength >> 30) ==
-			    (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
-			udf_free_blocks(inode->i_sb, inode,
-					laarr[i].extLocation, 0,
-					((laarr[i].
-					  extLength & UDF_EXTENT_LENGTH_MASK) +
-					 inode->i_sb->s_blocksize -
-					 1) >> inode->i_sb->s_blocksize_bits);
+		} else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+			   ((laarr[i + 1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+					((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					 inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
 			laarr[i].extLocation.logicalBlockNum = 0;
 			laarr[i].extLocation.partitionReferenceNum = 0;
 
 			if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
 			     (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
-			     inode->i_sb->s_blocksize -
-			     1) & ~UDF_EXTENT_LENGTH_MASK) {
-				laarr[i + 1].extLength =
-				    (laarr[i + 1].extLength -
-				     (laarr[i].
-				      extLength & UDF_EXTENT_LENGTH_MASK) +
-				     UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->
-								 s_blocksize -
-								 1);
-				laarr[i].extLength =
-				    (laarr[i].
-				     extLength & UDF_EXTENT_FLAG_MASK) +
-				    (UDF_EXTENT_LENGTH_MASK + 1) -
-				    inode->i_sb->s_blocksize;
+			     inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+				laarr[i + 1].extLength = (laarr[i + 1].extLength -
+							  (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+							  UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
+				laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
+					(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
 			} else {
 				laarr[i].extLength = laarr[i + 1].extLength +
-				    (((laarr[i].
-				       extLength & UDF_EXTENT_LENGTH_MASK) +
-				      inode->i_sb->s_blocksize -
-				      1) & ~(inode->i_sb->s_blocksize - 1));
+					(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					  inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
 				if (*endnum > (i + 2))
 					memmove(&laarr[i + 1], &laarr[i + 2],
-						sizeof(long_ad) * (*endnum -
-								   (i + 2)));
+						sizeof(long_ad) * (*endnum - (i + 2)));
 				i--;
 				(*endnum)--;
 			}
-		} else if ((laarr[i].extLength >> 30) ==
-			   (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
-			udf_free_blocks(inode->i_sb, inode,
-					laarr[i].extLocation, 0,
-					((laarr[i].
-					  extLength & UDF_EXTENT_LENGTH_MASK) +
-					 inode->i_sb->s_blocksize -
-					 1) >> inode->i_sb->s_blocksize_bits);
+		} else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+			udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
+					((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					 inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
 			laarr[i].extLocation.logicalBlockNum = 0;
 			laarr[i].extLocation.partitionReferenceNum = 0;
-			laarr[i].extLength =
-			    (laarr[i].
-			     extLength & UDF_EXTENT_LENGTH_MASK) |
-			    EXT_NOT_RECORDED_NOT_ALLOCATED;
+			laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
+				EXT_NOT_RECORDED_NOT_ALLOCATED;
 		}
 	}
 }
@@ -1025,10 +934,13 @@
 
 	if (buffer_uptodate(bh))
 		return bh;
+
 	ll_rw_block(READ, 1, &bh);
+
 	wait_on_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
+
 	brelse(bh);
 	*err = -EIO;
 	return NULL;
@@ -1047,26 +959,24 @@
 
 	lock_kernel();
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
-		if (inode->i_sb->s_blocksize <
-		    (udf_file_entry_alloc_offset(inode) + inode->i_size)) {
+		if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
+						inode->i_size)) {
 			udf_expand_file_adinicb(inode, inode->i_size, &err);
 			if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
 				inode->i_size = UDF_I_LENALLOC(inode);
 				unlock_kernel();
 				return;
-			} else
+			} else {
 				udf_truncate_extents(inode);
+			}
 		} else {
 			offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
-			memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) +
-			       offset, 0x00,
-			       inode->i_sb->s_blocksize - offset -
-			       udf_file_entry_alloc_offset(inode));
+			memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00,
+			       inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
 			UDF_I_LENALLOC(inode) = inode->i_size;
 		}
 	} else {
-		block_truncate_page(inode->i_mapping, inode->i_size,
-				    udf_get_block);
+		block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
 		udf_truncate_extents(inode);
 	}
 
@@ -1097,7 +1007,6 @@
 	 *      i_op = NULL;
 	 */
 	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
-
 	if (!bh) {
 		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
 		       inode->i_ino);
@@ -1107,8 +1016,7 @@
 
 	if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
 	    ident != TAG_IDENT_USE) {
-		printk(KERN_ERR
-		       "udf: udf_read_inode(ino %ld) failed ident=%d\n",
+		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
 		       inode->i_ino, ident);
 		brelse(bh);
 		make_bad_inode(inode);
@@ -1121,9 +1029,7 @@
 		struct buffer_head *ibh = NULL, *nbh = NULL;
 		struct indirectEntry *ie;
 
-		ibh =
-		    udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1,
-				     &ident);
+		ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
 		if (ident == TAG_IDENT_IE) {
 			if (ibh) {
 				kernel_lb_addr loc;
@@ -1132,13 +1038,10 @@
 				loc = lelb_to_cpu(ie->indirectICB.extLocation);
 
 				if (ie->indirectICB.extLength &&
-				    (nbh =
-				     udf_read_ptagged(inode->i_sb, loc, 0,
-						      &ident))) {
-					if (ident == TAG_IDENT_FE
-					    || ident == TAG_IDENT_EFE) {
-						memcpy(&UDF_I_LOCATION(inode),
-						       &loc,
+				    (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident))) {
+					if (ident == TAG_IDENT_FE ||
+					    ident == TAG_IDENT_EFE) {
+						memcpy(&UDF_I_LOCATION(inode), &loc,
 						       sizeof(kernel_lb_addr));
 						brelse(bh);
 						brelse(ibh);
@@ -1149,11 +1052,13 @@
 						brelse(nbh);
 						brelse(ibh);
 					}
-				} else
+				} else {
 					brelse(ibh);
+				}
 			}
-		} else
+		} else {
 			brelse(ibh);
+		}
 	} else if (le16_to_cpu(fe->icbTag.strategyType) != 4) {
 		printk(KERN_ERR "udf: unsupported strategy type: %d\n",
 		       le16_to_cpu(fe->icbTag.strategyType));
@@ -1179,11 +1084,10 @@
 
 	if (le16_to_cpu(fe->icbTag.strategyType) == 4)
 		UDF_I_STRAT4096(inode) = 0;
-	else			/* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
+	else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
 		UDF_I_STRAT4096(inode) = 1;
 
-	UDF_I_ALLOCTYPE(inode) =
-	    le16_to_cpu(fe->icbTag.flags) & ICBTAG_FLAG_AD_MASK;
+	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICBTAG_FLAG_AD_MASK;
 	UDF_I_UNIQUE(inode) = 0;
 	UDF_I_LENEATTR(inode) = 0;
 	UDF_I_LENEXTENTS(inode) = 0;
@@ -1193,23 +1097,16 @@
 	if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE) {
 		UDF_I_EFE(inode) = 1;
 		UDF_I_USE(inode) = 0;
-		if (udf_alloc_i_data
-		    (inode,
-		     inode->i_sb->s_blocksize -
-		     sizeof(struct extendedFileEntry))) {
+		if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry))) {
 			make_bad_inode(inode);
 			return;
 		}
-		memcpy(UDF_I_DATA(inode),
-		       bh->b_data + sizeof(struct extendedFileEntry),
-		       inode->i_sb->s_blocksize -
-		       sizeof(struct extendedFileEntry));
+		memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry),
+		       inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
 	} else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE) {
 		UDF_I_EFE(inode) = 0;
 		UDF_I_USE(inode) = 0;
-		if (udf_alloc_i_data
-		    (inode,
-		     inode->i_sb->s_blocksize - sizeof(struct fileEntry))) {
+		if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry))) {
 			make_bad_inode(inode);
 			return;
 		}
@@ -1219,19 +1116,13 @@
 		UDF_I_EFE(inode) = 0;
 		UDF_I_USE(inode) = 1;
 		UDF_I_LENALLOC(inode) =
-		    le32_to_cpu(((struct unallocSpaceEntry *)bh->b_data)->
-				lengthAllocDescs);
-		if (udf_alloc_i_data
-		    (inode,
-		     inode->i_sb->s_blocksize -
-		     sizeof(struct unallocSpaceEntry))) {
+		    le32_to_cpu(((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
+		if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry))) {
 			make_bad_inode(inode);
 			return;
 		}
-		memcpy(UDF_I_DATA(inode),
-		       bh->b_data + sizeof(struct unallocSpaceEntry),
-		       inode->i_sb->s_blocksize -
-		       sizeof(struct unallocSpaceEntry));
+		memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry),
+		       inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
 		return;
 	}
 
@@ -1257,7 +1148,7 @@
 
 	if (UDF_I_EFE(inode) == 0) {
 		inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
-		    (inode->i_sb->s_blocksize_bits - 9);
+			(inode->i_sb->s_blocksize_bits - 9);
 
 		if (udf_stamp_to_time(&convtime, &convtime_usec,
 				      lets_to_cpu(fe->accessTime))) {
@@ -1326,78 +1217,56 @@
 		UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID);
 		UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
 		UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs);
-		offset =
-		    sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
+		offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
 	}
 
 	switch (fe->icbTag.fileType) {
 	case ICBTAG_FILE_TYPE_DIRECTORY:
-		{
-			inode->i_op = &udf_dir_inode_operations;
-			inode->i_fop = &udf_dir_operations;
-			inode->i_mode |= S_IFDIR;
-			inc_nlink(inode);
-			break;
-		}
+		inode->i_op = &udf_dir_inode_operations;
+		inode->i_fop = &udf_dir_operations;
+		inode->i_mode |= S_IFDIR;
+		inc_nlink(inode);
+		break;
 	case ICBTAG_FILE_TYPE_REALTIME:
 	case ICBTAG_FILE_TYPE_REGULAR:
 	case ICBTAG_FILE_TYPE_UNDEF:
-		{
-			if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
-				inode->i_data.a_ops = &udf_adinicb_aops;
-			else
-				inode->i_data.a_ops = &udf_aops;
-			inode->i_op = &udf_file_inode_operations;
-			inode->i_fop = &udf_file_operations;
-			inode->i_mode |= S_IFREG;
-			break;
-		}
+		if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+			inode->i_data.a_ops = &udf_adinicb_aops;
+		else
+			inode->i_data.a_ops = &udf_aops;
+		inode->i_op = &udf_file_inode_operations;
+		inode->i_fop = &udf_file_operations;
+		inode->i_mode |= S_IFREG;
+		break;
 	case ICBTAG_FILE_TYPE_BLOCK:
-		{
-			inode->i_mode |= S_IFBLK;
-			break;
-		}
+		inode->i_mode |= S_IFBLK;
+		break;
 	case ICBTAG_FILE_TYPE_CHAR:
-		{
-			inode->i_mode |= S_IFCHR;
-			break;
-		}
+		inode->i_mode |= S_IFCHR;
+		break;
 	case ICBTAG_FILE_TYPE_FIFO:
-		{
-			init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
-			break;
-		}
+		init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
+		break;
 	case ICBTAG_FILE_TYPE_SOCKET:
-		{
-			init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
-			break;
-		}
+		init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
+		break;
 	case ICBTAG_FILE_TYPE_SYMLINK:
-		{
-			inode->i_data.a_ops = &udf_symlink_aops;
-			inode->i_op = &page_symlink_inode_operations;
-			inode->i_mode = S_IFLNK | S_IRWXUGO;
-			break;
-		}
+		inode->i_data.a_ops = &udf_symlink_aops;
+		inode->i_op = &page_symlink_inode_operations;
+		inode->i_mode = S_IFLNK | S_IRWXUGO;
+		break;
 	default:
-		{
-			printk(KERN_ERR
-			       "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
-			       inode->i_ino, fe->icbTag.fileType);
-			make_bad_inode(inode);
-			return;
-		}
+		printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
+		       inode->i_ino, fe->icbTag.fileType);
+		make_bad_inode(inode);
+		return;
 	}
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-		struct deviceSpec *dsea = (struct deviceSpec *)
-		    udf_get_extendedattr(inode, 12, 1);
-
+		struct deviceSpec *dsea = (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
 		if (dsea) {
 			init_special_inode(inode, inode->i_mode,
-					   MKDEV(le32_to_cpu
-						 (dsea->majorDeviceIdent),
-						 le32_to_cpu(dsea->
-							     minorDeviceIdent)));
+					   MKDEV(le32_to_cpu(dsea->majorDeviceIdent),
+						 le32_to_cpu(dsea->minorDeviceIdent)));
 			/* Developer ID ??? */
 		} else {
 			make_bad_inode(inode);
@@ -1410,8 +1279,7 @@
 	UDF_I_DATA(inode) = kmalloc(size, GFP_KERNEL);
 
 	if (!UDF_I_DATA(inode)) {
-		printk(KERN_ERR
-		       "udf:udf_alloc_i_data (ino %ld) no free memory\n",
+		printk(KERN_ERR "udf:udf_alloc_i_data (ino %ld) no free memory\n",
 		       inode->i_ino);
 		return -ENOMEM;
 	}
@@ -1428,12 +1296,12 @@
 	permissions = le32_to_cpu(fe->permissions);
 	flags = le16_to_cpu(fe->icbTag.flags);
 
-	mode = ((permissions) & S_IRWXO) |
-	    ((permissions >> 2) & S_IRWXG) |
-	    ((permissions >> 4) & S_IRWXU) |
-	    ((flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) |
-	    ((flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) |
-	    ((flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0);
+	mode =	(( permissions      ) & S_IRWXO) |
+		(( permissions >> 2 ) & S_IRWXG) |
+		(( permissions >> 4 ) & S_IRWXU) |
+		(( flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) |
+		(( flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) |
+		(( flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0);
 
 	return mode;
 }
@@ -1456,9 +1324,11 @@
 int udf_write_inode(struct inode *inode, int sync)
 {
 	int ret;
+
 	lock_kernel();
 	ret = udf_update_inode(inode, sync);
 	unlock_kernel();
+
 	return ret;
 }
 
@@ -1479,10 +1349,7 @@
 	kernel_timestamp cpu_time;
 	int err = 0;
 
-	bh = udf_tread(inode->i_sb,
-		       udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode),
-					 0));
-
+	bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
 	if (!bh) {
 		udf_debug("bread failure\n");
 		return -EIO;
@@ -1495,27 +1362,21 @@
 
 	if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) {
 		struct unallocSpaceEntry *use =
-		    (struct unallocSpaceEntry *)bh->b_data;
+			(struct unallocSpaceEntry *)bh->b_data;
 
 		use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
-		memcpy(bh->b_data + sizeof(struct unallocSpaceEntry),
-		       UDF_I_DATA(inode),
-		       inode->i_sb->s_blocksize -
-		       sizeof(struct unallocSpaceEntry));
-		crclen =
-		    sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) -
-		    sizeof(tag);
-		use->descTag.tagLocation =
-		    cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+		memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode),
+		       inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+		crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) - sizeof(tag);
+		use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
 		use->descTag.descCRCLength = cpu_to_le16(crclen);
-		use->descTag.descCRC =
-		    cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
+		use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
 
 		use->descTag.tagChecksum = 0;
-		for (i = 0; i < 16; i++)
+		for (i = 0; i < 16; i++) {
 			if (i != 4)
-				use->descTag.tagChecksum +=
-				    ((uint8_t *) & (use->descTag))[i];
+				use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
+		}
 
 		mark_buffer_dirty(bh);
 		brelse(bh);
@@ -1532,13 +1393,14 @@
 	else
 		fe->gid = cpu_to_le32(inode->i_gid);
 
-	udfperms = ((inode->i_mode & S_IRWXO)) |
-	    ((inode->i_mode & S_IRWXG) << 2) | ((inode->i_mode & S_IRWXU) << 4);
+	udfperms =	((inode->i_mode & S_IRWXO)     ) |
+			((inode->i_mode & S_IRWXG) << 2) |
+			((inode->i_mode & S_IRWXU) << 4);
 
-	udfperms |= (le32_to_cpu(fe->permissions) &
-		     (FE_PERM_O_DELETE | FE_PERM_O_CHATTR |
-		      FE_PERM_G_DELETE | FE_PERM_G_CHATTR |
-		      FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
+	udfperms |=	(le32_to_cpu(fe->permissions) &
+			(FE_PERM_O_DELETE | FE_PERM_O_CHATTR |
+			 FE_PERM_G_DELETE | FE_PERM_G_CHATTR |
+			 FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
 	fe->permissions = cpu_to_le32(udfperms);
 
 	if (S_ISDIR(inode->i_mode))
@@ -1550,22 +1412,20 @@
 
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
 		regid *eid;
-		struct deviceSpec *dsea = (struct deviceSpec *)
-		    udf_get_extendedattr(inode, 12, 1);
-
+		struct deviceSpec *dsea =
+			(struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
 		if (!dsea) {
 			dsea = (struct deviceSpec *)
-			    udf_add_extendedattr(inode,
-						 sizeof(struct deviceSpec) +
-						 sizeof(regid), 12, 0x3);
+				udf_add_extendedattr(inode,
+						     sizeof(struct deviceSpec) +
+						     sizeof(regid), 12, 0x3);
 			dsea->attrType = cpu_to_le32(12);
 			dsea->attrSubtype = 1;
-			dsea->attrLength =
-			    cpu_to_le32(sizeof(struct deviceSpec) +
-					sizeof(regid));
+			dsea->attrLength = cpu_to_le32(sizeof(struct deviceSpec) +
+						       sizeof(regid));
 			dsea->impUseLength = cpu_to_le32(sizeof(regid));
 		}
-		eid = (regid *) dsea->impUse;
+		eid = (regid *)dsea->impUse;
 		memset(eid, 0, sizeof(regid));
 		strcpy(eid->ident, UDF_ID_DEVELOPER);
 		eid->identSuffix[0] = UDF_OS_CLASS_UNIX;
@@ -1577,10 +1437,9 @@
 	if (UDF_I_EFE(inode) == 0) {
 		memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode),
 		       inode->i_sb->s_blocksize - sizeof(struct fileEntry));
-		fe->logicalBlocksRecorded =
-		    cpu_to_le64((inode->i_blocks +
-				 (1 << (inode->i_sb->s_blocksize_bits - 9)) -
-				 1) >> (inode->i_sb->s_blocksize_bits - 9));
+		fe->logicalBlocksRecorded = cpu_to_le64(
+			(inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+			(inode->i_sb->s_blocksize_bits - 9));
 
 		if (udf_time_to_stamp(&cpu_time, inode->i_atime))
 			fe->accessTime = cpu_to_lets(cpu_time);
@@ -1598,19 +1457,12 @@
 		fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
 		crclen = sizeof(struct fileEntry);
 	} else {
-		memcpy(bh->b_data + sizeof(struct extendedFileEntry),
-		       UDF_I_DATA(inode),
-		       inode->i_sb->s_blocksize -
-		       sizeof(struct extendedFileEntry));
+		memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode),
+		       inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
 		efe->objectSize = cpu_to_le64(inode->i_size);
-		efe->logicalBlocksRecorded = cpu_to_le64((inode->i_blocks +
-							  (1 <<
-							   (inode->i_sb->
-							    s_blocksize_bits -
-							    9)) -
-							  1) >> (inode->i_sb->
-								 s_blocksize_bits
-								 - 9));
+		efe->logicalBlocksRecorded = cpu_to_le64(
+			(inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+			(inode->i_sb->s_blocksize_bits - 9));
 
 		if (UDF_I_CRTIME(inode).tv_sec > inode->i_atime.tv_sec ||
 		    (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
@@ -1671,13 +1523,13 @@
 	else if (S_ISSOCK(inode->i_mode))
 		fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET;
 
-	icbflags = UDF_I_ALLOCTYPE(inode) |
-	    ((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) |
-	    ((inode->i_mode & S_ISGID) ? ICBTAG_FLAG_SETGID : 0) |
-	    ((inode->i_mode & S_ISVTX) ? ICBTAG_FLAG_STICKY : 0) |
-	    (le16_to_cpu(fe->icbTag.flags) &
-	     ~(ICBTAG_FLAG_AD_MASK | ICBTAG_FLAG_SETUID |
-	       ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY));
+	icbflags =	UDF_I_ALLOCTYPE(inode) |
+			((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) |
+			((inode->i_mode & S_ISGID) ? ICBTAG_FLAG_SETGID : 0) |
+			((inode->i_mode & S_ISVTX) ? ICBTAG_FLAG_STICKY : 0) |
+			(le16_to_cpu(fe->icbTag.flags) &
+				~(ICBTAG_FLAG_AD_MASK | ICBTAG_FLAG_SETUID |
+				ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY));
 
 	fe->icbTag.flags = cpu_to_le16(icbflags);
 	if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
@@ -1685,18 +1537,16 @@
 	else
 		fe->descTag.descVersion = cpu_to_le16(2);
 	fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
-	fe->descTag.tagLocation =
-	    cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+	fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
 	crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag);
 	fe->descTag.descCRCLength = cpu_to_le16(crclen);
-	fe->descTag.descCRC =
-	    cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
+	fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
 
 	fe->descTag.tagChecksum = 0;
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < 16; i++) {
 		if (i != 4)
-			fe->descTag.tagChecksum +=
-			    ((uint8_t *) & (fe->descTag))[i];
+			fe->descTag.tagChecksum += ((uint8_t *)&(fe->descTag))[i];
+	}
 
 	/* write the data blocks */
 	mark_buffer_dirty(bh);
@@ -1709,6 +1559,7 @@
 		}
 	}
 	brelse(bh);
+
 	return err;
 }
 
@@ -1729,8 +1580,7 @@
 	if (is_bad_inode(inode))
 		goto out_iput;
 
-	if (ino.logicalBlockNum >=
-	    UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
+	if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
 		udf_debug("block=%d, partition=%d out of range\n",
 			  ino.logicalBlockNum, ino.partitionReferenceNum);
 		make_bad_inode(inode);
@@ -1739,7 +1589,7 @@
 
 	return inode;
 
-      out_iput:
+ out_iput:
 	iput(inode);
 	return NULL;
 }
@@ -1755,9 +1605,7 @@
 	uint8_t *ptr;
 
 	if (!epos->bh)
-		ptr =
-		    UDF_I_DATA(inode) + epos->offset -
-		    udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
 	else
 		ptr = epos->bh->b_data + epos->offset;
 
@@ -1774,18 +1622,13 @@
 		int err, loffset;
 		kernel_lb_addr obloc = epos->block;
 
-		if (!
-		    (epos->block.logicalBlockNum =
-		     udf_new_block(inode->i_sb, NULL,
-				   obloc.partitionReferenceNum,
-				   obloc.logicalBlockNum, &err))) {
+		if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
+								  obloc.partitionReferenceNum,
+								  obloc.logicalBlockNum, &err))) {
 			return -1;
 		}
-		if (!
-		    (nbh =
-		     udf_tgetblk(inode->i_sb,
-				 udf_get_lb_pblock(inode->i_sb, epos->block,
-						   0)))) {
+		if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
+								       epos->block, 0)))) {
 			return -1;
 		}
 		lock_buffer(nbh);
@@ -1796,8 +1639,7 @@
 
 		aed = (struct allocExtDesc *)(nbh->b_data);
 		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
-			aed->previousAllocExtLocation =
-			    cpu_to_le32(obloc.logicalBlockNum);
+			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
 		if (epos->offset + adsize > inode->i_sb->s_blocksize) {
 			loffset = epos->offset;
 			aed->lengthAllocDescs = cpu_to_le32(adsize);
@@ -1814,9 +1656,7 @@
 			if (epos->bh) {
 				aed = (struct allocExtDesc *)epos->bh->b_data;
 				aed->lengthAllocDescs =
-				    cpu_to_le32(le32_to_cpu
-						(aed->lengthAllocDescs) +
-						adsize);
+					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 			} else {
 				UDF_I_LENALLOC(inode) += adsize;
 				mark_inode_dirty(inode);
@@ -1830,37 +1670,30 @@
 				    epos->block.logicalBlockNum, sizeof(tag));
 		switch (UDF_I_ALLOCTYPE(inode)) {
 		case ICBTAG_FLAG_AD_SHORT:
-			{
-				sad = (short_ad *) sptr;
-				sad->extLength =
-				    cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
-						inode->i_sb->s_blocksize);
-				sad->extPosition =
-				    cpu_to_le32(epos->block.logicalBlockNum);
-				break;
-			}
+			sad = (short_ad *)sptr;
+			sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+						     inode->i_sb->s_blocksize);
+			sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
+			break;
 		case ICBTAG_FLAG_AD_LONG:
-			{
-				lad = (long_ad *) sptr;
-				lad->extLength =
-				    cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
-						inode->i_sb->s_blocksize);
-				lad->extLocation = cpu_to_lelb(epos->block);
-				memset(lad->impUse, 0x00, sizeof(lad->impUse));
-				break;
-			}
+			lad = (long_ad *)sptr;
+			lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+						     inode->i_sb->s_blocksize);
+			lad->extLocation = cpu_to_lelb(epos->block);
+			memset(lad->impUse, 0x00, sizeof(lad->impUse));
+			break;
 		}
 		if (epos->bh) {
-			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-			    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+			    UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
 				udf_update_tag(epos->bh->b_data, loffset);
 			else
-				udf_update_tag(epos->bh->b_data,
-					       sizeof(struct allocExtDesc));
+				udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
 			mark_buffer_dirty_inode(epos->bh, inode);
 			brelse(epos->bh);
-		} else
+		} else {
 			mark_inode_dirty(inode);
+		}
 		epos->bh = nbh;
 	}
 
@@ -1872,14 +1705,11 @@
 	} else {
 		aed = (struct allocExtDesc *)epos->bh->b_data;
 		aed->lengthAllocDescs =
-		    cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
-		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-		    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-			udf_update_tag(epos->bh->b_data,
-				       epos->offset + (inc ? 0 : adsize));
+			cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+			udf_update_tag(epos->bh->b_data, epos->offset + (inc ? 0 : adsize));
 		else
-			udf_update_tag(epos->bh->b_data,
-				       sizeof(struct allocExtDesc));
+			udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
 		mark_buffer_dirty_inode(epos->bh, inode);
 	}
 
@@ -1891,51 +1721,47 @@
 {
 	int adsize;
 	uint8_t *ptr;
+	short_ad *sad;
+	long_ad *lad;
 
 	if (!epos->bh)
-		ptr =
-		    UDF_I_DATA(inode) + epos->offset -
-		    udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
 	else
 		ptr = epos->bh->b_data + epos->offset;
 
 	switch (UDF_I_ALLOCTYPE(inode)) {
 	case ICBTAG_FLAG_AD_SHORT:
-		{
-			short_ad *sad = (short_ad *) ptr;
-			sad->extLength = cpu_to_le32(elen);
-			sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
-			adsize = sizeof(short_ad);
-			break;
-		}
+		sad = (short_ad *)ptr;
+		sad->extLength = cpu_to_le32(elen);
+		sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
+		adsize = sizeof(short_ad);
+		break;
 	case ICBTAG_FLAG_AD_LONG:
-		{
-			long_ad *lad = (long_ad *) ptr;
-			lad->extLength = cpu_to_le32(elen);
-			lad->extLocation = cpu_to_lelb(eloc);
-			memset(lad->impUse, 0x00, sizeof(lad->impUse));
-			adsize = sizeof(long_ad);
-			break;
-		}
+		lad = (long_ad *)ptr;
+		lad->extLength = cpu_to_le32(elen);
+		lad->extLocation = cpu_to_lelb(eloc);
+		memset(lad->impUse, 0x00, sizeof(lad->impUse));
+		adsize = sizeof(long_ad);
+		break;
 	default:
 		return -1;
 	}
 
 	if (epos->bh) {
-		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-		    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) {
-			struct allocExtDesc *aed =
-			    (struct allocExtDesc *)epos->bh->b_data;
+		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+		    UDF_SB_UDFREV(inode->i_sb) >= 0x0201) {
+			struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data;
 			udf_update_tag(epos->bh->b_data,
-				       le32_to_cpu(aed->lengthAllocDescs) +
-				       sizeof(struct allocExtDesc));
+				       le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
 		}
 		mark_buffer_dirty_inode(epos->bh, inode);
-	} else
+	} else {
 		mark_inode_dirty(inode);
+	}
 
 	if (inc)
 		epos->offset += adsize;
+
 	return (elen >> 30);
 }
 
@@ -1949,14 +1775,9 @@
 		epos->block = *eloc;
 		epos->offset = sizeof(struct allocExtDesc);
 		brelse(epos->bh);
-		if (!
-		    (epos->bh =
-		     udf_tread(inode->i_sb,
-			       udf_get_lb_pblock(inode->i_sb, epos->block,
-						 0)))) {
+		if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0)))) {
 			udf_debug("reading block %d failed!\n",
-				  udf_get_lb_pblock(inode->i_sb, epos->block,
-						    0));
+				  udf_get_lb_pblock(inode->i_sb, epos->block, 0));
 			return -1;
 		}
 	}
@@ -1970,75 +1791,49 @@
 	int alen;
 	int8_t etype;
 	uint8_t *ptr;
+	short_ad *sad;
+	long_ad *lad;
+
 
 	if (!epos->bh) {
 		if (!epos->offset)
 			epos->offset = udf_file_entry_alloc_offset(inode);
-		ptr =
-		    UDF_I_DATA(inode) + epos->offset -
-		    udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
-		alen =
-		    udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+		alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
 	} else {
 		if (!epos->offset)
 			epos->offset = sizeof(struct allocExtDesc);
 		ptr = epos->bh->b_data + epos->offset;
-		alen =
-		    sizeof(struct allocExtDesc) +
-		    le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->
-				lengthAllocDescs);
+		alen = sizeof(struct allocExtDesc) +
+			le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
 	}
 
 	switch (UDF_I_ALLOCTYPE(inode)) {
 	case ICBTAG_FLAG_AD_SHORT:
-		{
-			short_ad *sad;
-
-			if (!
-			    (sad =
-			     udf_get_fileshortad(ptr, alen, &epos->offset,
-						 inc)))
-				return -1;
-
-			etype = le32_to_cpu(sad->extLength) >> 30;
-			eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
-			eloc->partitionReferenceNum =
-			    UDF_I_LOCATION(inode).partitionReferenceNum;
-			*elen =
-			    le32_to_cpu(sad->
-					extLength) & UDF_EXTENT_LENGTH_MASK;
-			break;
-		}
-	case ICBTAG_FLAG_AD_LONG:
-		{
-			long_ad *lad;
-
-			if (!
-			    (lad =
-			     udf_get_filelongad(ptr, alen, &epos->offset, inc)))
-				return -1;
-
-			etype = le32_to_cpu(lad->extLength) >> 30;
-			*eloc = lelb_to_cpu(lad->extLocation);
-			*elen =
-			    le32_to_cpu(lad->
-					extLength) & UDF_EXTENT_LENGTH_MASK;
-			break;
-		}
-	default:
-		{
-			udf_debug("alloc_type = %d unsupported\n",
-				  UDF_I_ALLOCTYPE(inode));
+		if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
 			return -1;
-		}
+		etype = le32_to_cpu(sad->extLength) >> 30;
+		eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+		eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+		*elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+		break;
+	case ICBTAG_FLAG_AD_LONG:
+		if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
+			return -1;
+		etype = le32_to_cpu(lad->extLength) >> 30;
+		*eloc = lelb_to_cpu(lad->extLocation);
+		*elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+		break;
+	default:
+		udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+		return -1;
 	}
 
 	return etype;
 }
 
-static int8_t
-udf_insert_aext(struct inode *inode, struct extent_position epos,
-		kernel_lb_addr neloc, uint32_t nelen)
+static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
+			      kernel_lb_addr neloc, uint32_t nelen)
 {
 	kernel_lb_addr oeloc;
 	uint32_t oelen;
@@ -2049,12 +1844,12 @@
 
 	while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) {
 		udf_write_aext(inode, &epos, neloc, nelen, 1);
-
 		neloc = oeloc;
 		nelen = (etype << 30) | oelen;
 	}
 	udf_add_aext(inode, &epos, neloc, nelen, 1);
 	brelse(epos.bh);
+
 	return (nelen >> 30);
 }
 
@@ -2105,15 +1900,12 @@
 		} else {
 			aed = (struct allocExtDesc *)oepos.bh->b_data;
 			aed->lengthAllocDescs =
-			    cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
-					(2 * adsize));
-			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-			    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag(oepos.bh->b_data,
-					       oepos.offset - (2 * adsize));
+				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2 * adsize));
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+			    UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag(oepos.bh->b_data, oepos.offset - (2 * adsize));
 			else
-				udf_update_tag(oepos.bh->b_data,
-					       sizeof(struct allocExtDesc));
+				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
 			mark_buffer_dirty_inode(oepos.bh, inode);
 		}
 	} else {
@@ -2124,21 +1916,19 @@
 		} else {
 			aed = (struct allocExtDesc *)oepos.bh->b_data;
 			aed->lengthAllocDescs =
-			    cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
-					adsize);
-			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-			    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag(oepos.bh->b_data,
-					       epos.offset - adsize);
+				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+			    UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				udf_update_tag(oepos.bh->b_data, epos.offset - adsize);
 			else
-				udf_update_tag(oepos.bh->b_data,
-					       sizeof(struct allocExtDesc));
+				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
 			mark_buffer_dirty_inode(oepos.bh, inode);
 		}
 	}
 
 	brelse(epos.bh);
 	brelse(oepos.bh);
+
 	return (elen >> 30);
 }
 
@@ -2162,8 +1952,7 @@
 
 	do {
 		if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1) {
-			*offset =
-			    (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
+			*offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
 			UDF_I_LENEXTENTS(inode) = lbcount;
 			return -1;
 		}
@@ -2180,13 +1969,12 @@
 	kernel_lb_addr eloc;
 	uint32_t elen;
 	sector_t offset;
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 	int ret;
 
 	lock_kernel();
 
-	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
-	    (EXT_RECORDED_ALLOCATED >> 30))
+	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
 		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
 	else
 		ret = 0;
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 4826c36..579bae7 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -43,7 +43,7 @@
 		udf_debug("XA disk: %s, vol_desc_start=%d\n",
 			  (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
 #if WE_OBEY_THE_WRITTEN_STANDARDS
-		if (ms_info.xa_flag)	/* necessary for a valid ms_info.addr */
+		if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
 #endif
 			vol_desc_start = ms_info.addr.lba;
 	} else {
@@ -57,7 +57,7 @@
 	struct block_device *bdev = sb->s_bdev;
 	unsigned long lblock = 0;
 
-	if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long)&lblock))
+	if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock))
 		lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
 
 	if (lblock)
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index a7f5727..15297de 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -54,15 +54,15 @@
 	int i;
 
 	ea = UDF_I_DATA(inode);
-	if (UDF_I_LENEATTR(inode))
+	if (UDF_I_LENEATTR(inode)) {
 		ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
-	else {
+	} else {
 		ad = ea;
 		size += sizeof(struct extendedAttrHeaderDesc);
 	}
 
 	offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
-	    UDF_I_LENALLOC(inode);
+		UDF_I_LENALLOC(inode);
 
 	/* TODO - Check for FreeEASpace */
 
@@ -76,56 +76,45 @@
 
 		if (UDF_I_LENEATTR(inode)) {
 			/* check checksum/crc */
-			if (le16_to_cpu(eahd->descTag.tagIdent) !=
-			    TAG_IDENT_EAHD
-			    || le32_to_cpu(eahd->descTag.tagLocation) !=
-			    UDF_I_LOCATION(inode).logicalBlockNum) {
+			if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
+			    le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
 				return NULL;
 			}
 		} else {
 			size -= sizeof(struct extendedAttrHeaderDesc);
-			UDF_I_LENEATTR(inode) +=
-			    sizeof(struct extendedAttrHeaderDesc);
+			UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
 			eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
 			if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
 				eahd->descTag.descVersion = cpu_to_le16(3);
 			else
 				eahd->descTag.descVersion = cpu_to_le16(2);
-			eahd->descTag.tagSerialNum =
-			    cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
-			eahd->descTag.tagLocation =
-			    cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+			eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
+			eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
 			eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
 			eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
 		}
 
 		offset = UDF_I_LENEATTR(inode);
 		if (type < 2048) {
-			if (le32_to_cpu(eahd->appAttrLocation) <
-			    UDF_I_LENEATTR(inode)) {
-				uint32_t aal =
-				    le32_to_cpu(eahd->appAttrLocation);
-				memmove(&ea[offset - aal + size], &ea[aal],
-					offset - aal);
+			if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
+				uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
+				memmove(&ea[offset - aal + size],
+					&ea[aal], offset - aal);
 				offset -= aal;
 				eahd->appAttrLocation = cpu_to_le32(aal + size);
 			}
-			if (le32_to_cpu(eahd->impAttrLocation) <
-			    UDF_I_LENEATTR(inode)) {
-				uint32_t ial =
-				    le32_to_cpu(eahd->impAttrLocation);
-				memmove(&ea[offset - ial + size], &ea[ial],
-					offset - ial);
+			if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) {
+				uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
+				memmove(&ea[offset - ial + size],
+					&ea[ial], offset - ial);
 				offset -= ial;
 				eahd->impAttrLocation = cpu_to_le32(ial + size);
 			}
 		} else if (type < 65536) {
-			if (le32_to_cpu(eahd->appAttrLocation) <
-			    UDF_I_LENEATTR(inode)) {
-				uint32_t aal =
-				    le32_to_cpu(eahd->appAttrLocation);
-				memmove(&ea[offset - aal + size], &ea[aal],
-					offset - aal);
+			if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
+				uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
+				memmove(&ea[offset - aal + size],
+					&ea[aal], offset - aal);
 				offset -= aal;
 				eahd->appAttrLocation = cpu_to_le32(aal + size);
 			}
@@ -133,18 +122,18 @@
 		/* rewrite CRC + checksum of eahd */
 		crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
 		eahd->descTag.descCRCLength = cpu_to_le16(crclen);
-		eahd->descTag.descCRC =
-		    cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
+		eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd +
+							    sizeof(tag), crclen, 0));
 		eahd->descTag.tagChecksum = 0;
 		for (i = 0; i < 16; i++)
 			if (i != 4)
-				eahd->descTag.tagChecksum +=
-				    ((uint8_t *) & (eahd->descTag))[i];
+				eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
 		UDF_I_LENEATTR(inode) += size;
 		return (struct genericFormat *)&ea[offset];
 	}
 	if (loc & 0x02) {
 	}
+
 	return NULL;
 }
 
@@ -163,8 +152,7 @@
 
 		/* check checksum/crc */
 		if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
-		    le32_to_cpu(eahd->descTag.tagLocation) !=
-		    UDF_I_LOCATION(inode).logicalBlockNum) {
+		    le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
 			return NULL;
 		}
 
@@ -177,13 +165,13 @@
 
 		while (offset < UDF_I_LENEATTR(inode)) {
 			gaf = (struct genericFormat *)&ea[offset];
-			if (le32_to_cpu(gaf->attrType) == type
-			    && gaf->attrSubtype == subtype)
+			if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
 				return gaf;
 			else
 				offset += le32_to_cpu(gaf->attrLength);
 		}
 	}
+
 	return NULL;
 }
 
@@ -216,23 +204,22 @@
 		return NULL;
 	}
 
-	tag_p = (tag *) (bh->b_data);
+	tag_p = (tag *)(bh->b_data);
 
 	*ident = le16_to_cpu(tag_p->tagIdent);
 
 	if (location != le32_to_cpu(tag_p->tagLocation)) {
 		udf_debug("location mismatch block %u, tag %u != %u\n",
-			  block + UDF_SB_SESSION(sb),
-			  le32_to_cpu(tag_p->tagLocation), location);
+			  block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
 		goto error_out;
 	}
 
 	/* Verify the tag checksum */
 	checksum = 0U;
 	for (i = 0; i < 4; i++)
-		checksum += (uint8_t) (bh->b_data[i]);
+		checksum += (uint8_t)(bh->b_data[i]);
 	for (i = 5; i < 16; i++)
-		checksum += (uint8_t) (bh->b_data[i]);
+		checksum += (uint8_t)(bh->b_data[i]);
 	if (checksum != tag_p->tagChecksum) {
 		printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
 		goto error_out;
@@ -249,16 +236,14 @@
 	/* Verify the descriptor CRC */
 	if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
 	    le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
-						   le16_to_cpu(tag_p->
-							       descCRCLength),
-						   0)) {
+						   le16_to_cpu(tag_p->descCRCLength), 0)) {
 		return bh;
 	}
 	udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
 		  block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC),
 		  le16_to_cpu(tag_p->descCRCLength));
 
-      error_out:
+error_out:
 	brelse(bh);
 	return NULL;
 }
@@ -272,7 +257,7 @@
 
 void udf_update_tag(char *data, int length)
 {
-	tag *tptr = (tag *) data;
+	tag *tptr = (tag *)data;
 	int i;
 
 	length -= sizeof(tag);
@@ -283,13 +268,13 @@
 
 	for (i = 0; i < 16; i++)
 		if (i != 4)
-			tptr->tagChecksum += (uint8_t) (data[i]);
+			tptr->tagChecksum += (uint8_t)(data[i]);
 }
 
 void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
 		 uint32_t loc, int length)
 {
-	tag *tptr = (tag *) data;
+	tag *tptr = (tag *)data;
 	tptr->tagIdent = cpu_to_le16(ident);
 	tptr->descVersion = cpu_to_le16(version);
 	tptr->tagSerialNum = cpu_to_le16(snum);
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 334d363..bec96a6 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -37,6 +37,7 @@
 {
 	if (len1 != len2)
 		return 0;
+
 	return !memcmp(name1, name2, len1);
 }
 
@@ -52,7 +53,7 @@
 	uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
 	uint8_t lfi = cfi->lengthFileIdent;
 	int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
-	    sizeof(struct fileIdentDesc);
+		sizeof(struct fileIdentDesc);
 	int adinicb = 0;
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
@@ -61,85 +62,75 @@
 	offset = fibh->soffset + sizeof(struct fileIdentDesc);
 
 	if (impuse) {
-		if (adinicb || (offset + liu < 0))
-			memcpy((uint8_t *) sfi->impUse, impuse, liu);
-		else if (offset >= 0)
+		if (adinicb || (offset + liu < 0)) {
+			memcpy((uint8_t *)sfi->impUse, impuse, liu);
+		} else if (offset >= 0) {
 			memcpy(fibh->ebh->b_data + offset, impuse, liu);
-		else {
-			memcpy((uint8_t *) sfi->impUse, impuse, -offset);
-			memcpy(fibh->ebh->b_data, impuse - offset,
-			       liu + offset);
+		} else {
+			memcpy((uint8_t *)sfi->impUse, impuse, -offset);
+			memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
 		}
 	}
 
 	offset += liu;
 
 	if (fileident) {
-		if (adinicb || (offset + lfi < 0))
-			memcpy((uint8_t *) sfi->fileIdent + liu, fileident,
-			       lfi);
-		else if (offset >= 0)
+		if (adinicb || (offset + lfi < 0)) {
+			memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
+		} else if (offset >= 0) {
 			memcpy(fibh->ebh->b_data + offset, fileident, lfi);
-		else {
-			memcpy((uint8_t *) sfi->fileIdent + liu, fileident,
-			       -offset);
-			memcpy(fibh->ebh->b_data, fileident - offset,
-			       lfi + offset);
+		} else {
+			memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);
+			memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
 		}
 	}
 
 	offset += lfi;
 
-	if (adinicb || (offset + padlen < 0))
-		memset((uint8_t *) sfi->padding + liu + lfi, 0x00, padlen);
-	else if (offset >= 0)
+	if (adinicb || (offset + padlen < 0)) {
+		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
+	} else if (offset >= 0) {
 		memset(fibh->ebh->b_data + offset, 0x00, padlen);
-	else {
-		memset((uint8_t *) sfi->padding + liu + lfi, 0x00, -offset);
+	} else {
+		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
 		memset(fibh->ebh->b_data, 0x00, padlen + offset);
 	}
 
-	crc =
-	    udf_crc((uint8_t *) cfi + sizeof(tag),
-		    sizeof(struct fileIdentDesc) - sizeof(tag), 0);
+	crc = udf_crc((uint8_t *)cfi + sizeof(tag),
+		      sizeof(struct fileIdentDesc) - sizeof(tag), 0);
 
-	if (fibh->sbh == fibh->ebh)
-		crc = udf_crc((uint8_t *) sfi->impUse,
-			      crclen + sizeof(tag) -
-			      sizeof(struct fileIdentDesc), crc);
-	else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)
-		crc =
-		    udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) +
-			    fibh->soffset,
-			    crclen + sizeof(tag) - sizeof(struct fileIdentDesc),
-			    crc);
-	else {
-		crc = udf_crc((uint8_t *) sfi->impUse,
-			      -fibh->soffset - sizeof(struct fileIdentDesc),
-			      crc);
+	if (fibh->sbh == fibh->ebh) {
+		crc = udf_crc((uint8_t *)sfi->impUse,
+			      crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+	} else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
+		crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,
+			      crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+	} else {
+		crc = udf_crc((uint8_t *)sfi->impUse,
+			      -fibh->soffset - sizeof(struct fileIdentDesc), crc);
 		crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
 	}
 
 	cfi->descTag.descCRC = cpu_to_le16(crc);
 	cfi->descTag.descCRCLength = cpu_to_le16(crclen);
 
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < 16; i++) {
 		if (i != 4)
-			checksum += ((uint8_t *) & cfi->descTag)[i];
+			checksum += ((uint8_t *)&cfi->descTag)[i];
+	}
 
 	cfi->descTag.tagChecksum = checksum;
-	if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset))
-		memcpy((uint8_t *) sfi, (uint8_t *) cfi,
-		       sizeof(struct fileIdentDesc));
-	else {
-		memcpy((uint8_t *) sfi, (uint8_t *) cfi, -fibh->soffset);
-		memcpy(fibh->ebh->b_data, (uint8_t *) cfi - fibh->soffset,
+	if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
+		memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));
+	} else {
+		memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
+		memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
 		       sizeof(struct fileIdentDesc) + fibh->soffset);
 	}
 
-	if (adinicb)
+	if (adinicb) {
 		mark_inode_dirty(inode);
-	else {
+	} else {
 		if (fibh->sbh != fibh->ebh)
 			mark_buffer_dirty_inode(fibh->ebh, inode);
 		mark_buffer_dirty_inode(fibh->sbh, inode);
@@ -163,26 +154,25 @@
 	kernel_lb_addr eloc;
 	uint32_t elen;
 	sector_t offset;
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 
 	size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
-	fibh->soffset = fibh->eoffset =
-	    (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		fibh->sbh = fibh->ebh = NULL;
-	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-			    &epos, &eloc, &elen,
-			    &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
+	} else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+			      &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
 				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
 				epos.offset -= sizeof(long_ad);
-		} else
+		} else {
 			offset = 0;
+		}
 
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
 			brelse(epos.bh);
@@ -196,7 +186,6 @@
 	while ((f_pos < size)) {
 		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
 					&elen, &offset);
-
 		if (!fi) {
 			if (fibh->sbh != fibh->ebh)
 				brelse(fibh->ebh);
@@ -213,20 +202,14 @@
 		} else {
 			int poffset;	/* Unpaded ending offset */
 
-			poffset =
-			    fibh->soffset + sizeof(struct fileIdentDesc) + liu +
-			    lfi;
+			poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-			if (poffset >= lfi)
-				nameptr =
-				    (uint8_t *) (fibh->ebh->b_data + poffset -
-						 lfi);
-			else {
+			if (poffset >= lfi) {
+				nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);
+			} else {
 				nameptr = fname;
-				memcpy(nameptr, fi->fileIdent + liu,
-				       lfi - poffset);
-				memcpy(nameptr + lfi - poffset,
-				       fibh->ebh->b_data, poffset);
+				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+				memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
 			}
 		}
 
@@ -244,18 +227,18 @@
 			continue;
 
 		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi))) {
-			if (udf_match
-			    (flen, fname, dentry->d_name.len,
-			     dentry->d_name.name)) {
+			if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
 				brelse(epos.bh);
 				return fi;
 			}
 		}
 	}
+
 	if (fibh->sbh != fibh->ebh)
 		brelse(fibh->ebh);
 	brelse(fibh->sbh);
 	brelse(epos.bh);
+
 	return NULL;
 }
 
@@ -306,15 +289,19 @@
 #ifdef UDF_RECOVERY
 	/* temporary shorthand for specifying files by inode number */
 	if (!strncmp(dentry->d_name.name, ".B=", 3)) {
-		kernel_lb_addr lb =
-		    { 0, simple_strtoul(dentry->d_name.name + 3, NULL, 0) };
+		kernel_lb_addr lb = {
+			.logicalBlockNum = 0,
+			.partitionReferenceNum = simple_strtoul(dentry->d_name.name + 3,
+								NULL, 0),
+		};
 		inode = udf_iget(dir->i_sb, lb);
 		if (!inode) {
 			unlock_kernel();
 			return ERR_PTR(-EACCES);
 		}
-	} else
-#endif				/* UDF_RECOVERY */
+	}
+	else
+#endif /* UDF_RECOVERY */
 
 	if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
 		if (fibh.sbh != fibh.ebh)
@@ -329,6 +316,7 @@
 	}
 	unlock_kernel();
 	d_add(dentry, inode);
+
 	return NULL;
 }
 
@@ -352,7 +340,7 @@
 	kernel_lb_addr eloc;
 	uint32_t elen;
 	sector_t offset;
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 
 	sb = dir->i_sb;
 
@@ -361,36 +349,33 @@
 			*err = -EINVAL;
 			return NULL;
 		}
-
-		if (!
-		    (namelen =
-		     udf_put_filename(sb, dentry->d_name.name, name,
-				      dentry->d_name.len))) {
+		if (!(namelen = udf_put_filename(sb, dentry->d_name.name, name,
+						 dentry->d_name.len))) {
 			*err = -ENAMETOOLONG;
 			return NULL;
 		}
-	} else
+	} else {
 		namelen = 0;
+	}
 
 	nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
 
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
-	fibh->soffset = fibh->eoffset =
-	    (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		fibh->sbh = fibh->ebh = NULL;
-	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-			    &epos, &eloc, &elen,
-			    &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
+	} else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+			      &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
 				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
 				epos.offset -= sizeof(long_ad);
-		} else
+		} else {
 			offset = 0;
+		}
 
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
 			brelse(epos.bh);
@@ -423,40 +408,33 @@
 		liu = le16_to_cpu(cfi->lengthOfImpUse);
 		lfi = cfi->lengthFileIdent;
 
-		if (fibh->sbh == fibh->ebh)
+		if (fibh->sbh == fibh->ebh) {
 			nameptr = fi->fileIdent + liu;
-		else {
+		} else {
 			int poffset;	/* Unpaded ending offset */
 
-			poffset =
-			    fibh->soffset + sizeof(struct fileIdentDesc) + liu +
-			    lfi;
+			poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
 
-			if (poffset >= lfi)
-				nameptr =
-				    (char *)(fibh->ebh->b_data + poffset - lfi);
-			else {
+			if (poffset >= lfi) {
+				nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
+			} else {
 				nameptr = fname;
-				memcpy(nameptr, fi->fileIdent + liu,
-				       lfi - poffset);
-				memcpy(nameptr + lfi - poffset,
-				       fibh->ebh->b_data, poffset);
+				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+				memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
 			}
 		}
 
 		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
-			if (((sizeof(struct fileIdentDesc) + liu + lfi +
-			      3) & ~3) == nfidlen) {
+			if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) {
 				brelse(epos.bh);
 				cfi->descTag.tagSerialNum = cpu_to_le16(1);
 				cfi->fileVersionNum = cpu_to_le16(1);
 				cfi->fileCharacteristics = 0;
 				cfi->lengthFileIdent = namelen;
 				cfi->lengthOfImpUse = cpu_to_le16(0);
-				if (!udf_write_fi
-				    (dir, cfi, fi, fibh, NULL, name))
+				if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
 					return fi;
-				else {
+				} else {
 					*err = -EIO;
 					return NULL;
 				}
@@ -467,8 +445,7 @@
 			continue;
 
 		if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
-		    udf_match(flen, fname, dentry->d_name.len,
-			      dentry->d_name.name)) {
+		    udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
 			if (fibh->sbh != fibh->ebh)
 				brelse(fibh->ebh);
 			brelse(fibh->sbh);
@@ -478,7 +455,7 @@
 		}
 	}
 
-      add:
+add:
 	f_pos += nfidlen;
 
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
@@ -491,14 +468,11 @@
 		if (fibh->sbh != fibh->ebh)
 			brelse(fibh->ebh);
 		brelse(fibh->sbh);
-		if (!
-		    (fibh->sbh = fibh->ebh =
-		     udf_expand_dir_adinicb(dir, &block, err)))
+		if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
 			return NULL;
 		epos.block = UDF_I_LOCATION(dir);
 		eloc.logicalBlockNum = block;
-		eloc.partitionReferenceNum =
-		    UDF_I_LOCATION(dir).partitionReferenceNum;
+		eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
 		elen = dir->i_sb->s_blocksize;
 		epos.offset = udf_file_entry_alloc_offset(dir);
 		if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
@@ -517,16 +491,13 @@
 
 		if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 			block = UDF_I_LOCATION(dir).logicalBlockNum;
-			fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) +
-						      fibh->soffset -
+			fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset -
 						      udf_ext0_offset(dir) +
 						      UDF_I_LENEATTR(dir));
 		} else {
 			block = eloc.logicalBlockNum + ((elen - 1) >>
-							dir->i_sb->
-							s_blocksize_bits);
-			fi = (struct fileIdentDesc *)(fibh->sbh->b_data +
-						      fibh->soffset);
+							dir->i_sb->s_blocksize_bits);
+			fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
 		}
 	} else {
 		fibh->soffset = fibh->eoffset - sb->s_blocksize;
@@ -538,42 +509,36 @@
 
 		block = eloc.logicalBlockNum + ((elen - 1) >>
 						dir->i_sb->s_blocksize_bits);
-
-		if (!
-		    (fibh->ebh =
-		     udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-			       1, err))) {
+		fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err);
+		if (!fibh->ebh) {
 			brelse(epos.bh);
 			brelse(fibh->sbh);
 			return NULL;
 		}
 
-		if (!(fibh->soffset)) {
+		if (!fibh->soffset) {
 			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
 			    (EXT_RECORDED_ALLOCATED >> 30)) {
 				block = eloc.logicalBlockNum + ((elen - 1) >>
-								dir->i_sb->
-								s_blocksize_bits);
-			} else
+					dir->i_sb->s_blocksize_bits);
+			} else {
 				block++;
+			}
 
 			brelse(fibh->sbh);
 			fibh->sbh = fibh->ebh;
 			fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
 		} else {
 			fi = (struct fileIdentDesc *)
-			    (fibh->sbh->b_data + sb->s_blocksize +
-			     fibh->soffset);
+				(fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
 		}
 	}
 
 	memset(cfi, 0, sizeof(struct fileIdentDesc));
 	if (UDF_SB_UDFREV(sb) >= 0x0200)
-		udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
-			    sizeof(tag));
+		udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block, sizeof(tag));
 	else
-		udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
-			    sizeof(tag));
+		udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block, sizeof(tag));
 	cfi->fileVersionNum = cpu_to_le16(1);
 	cfi->lengthFileIdent = namelen;
 	cfi->lengthOfImpUse = cpu_to_le16(0);
@@ -599,8 +564,10 @@
 			    struct fileIdentDesc *cfi)
 {
 	cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
+
 	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
 		memset(&(cfi->icb), 0x00, sizeof(long_ad));
+
 	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
 }
 
@@ -637,8 +604,8 @@
 	}
 	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
-	*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-	    cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		mark_inode_dirty(dir);
@@ -648,6 +615,7 @@
 	brelse(fibh.sbh);
 	unlock_kernel();
 	d_instantiate(dentry, inode);
+
 	return 0;
 }
 
@@ -679,8 +647,8 @@
 	}
 	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
-	*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-	    cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		mark_inode_dirty(dir);
@@ -692,7 +660,8 @@
 	brelse(fibh.sbh);
 	d_instantiate(dentry, inode);
 	err = 0;
-      out:
+
+out:
 	unlock_kernel();
 	return err;
 }
@@ -725,10 +694,9 @@
 	inode->i_nlink = 2;
 	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
-	*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-	    cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
-	cfi.fileCharacteristics =
-	    FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
+	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
+	cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
 	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
 	brelse(fibh.sbh);
 	inode->i_mode = S_IFDIR | mode;
@@ -744,8 +712,8 @@
 	}
 	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
 	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
-	*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-	    cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
 	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
 	inc_nlink(dir);
@@ -755,7 +723,8 @@
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
 	err = 0;
-      out:
+
+out:
 	unlock_kernel();
 	return err;
 }
@@ -770,26 +739,25 @@
 	kernel_lb_addr eloc;
 	uint32_t elen;
 	sector_t offset;
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
-	fibh.soffset = fibh.eoffset =
-	    (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
 
-	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		fibh.sbh = fibh.ebh = NULL;
-	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-			    &epos, &eloc, &elen,
-			    &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
+	} else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+			      &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
 				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
 				epos.offset -= sizeof(long_ad);
-		} else
+		} else {
 			offset = 0;
+		}
 
 		if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
 			brelse(epos.bh);
@@ -803,7 +771,6 @@
 	while ((f_pos < size)) {
 		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
 					&elen, &offset);
-
 		if (!fi) {
 			if (fibh.sbh != fibh.ebh)
 				brelse(fibh.ebh);
@@ -812,8 +779,8 @@
 			return 0;
 		}
 
-		if (cfi.lengthFileIdent
-		    && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
+		if (cfi.lengthFileIdent &&
+		    (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
 			if (fibh.sbh != fibh.ebh)
 				brelse(fibh.ebh);
 			brelse(fibh.sbh);
@@ -821,10 +788,12 @@
 			return 0;
 		}
 	}
+
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
 	brelse(epos.bh);
+
 	return 1;
 }
 
@@ -859,15 +828,15 @@
 	clear_nlink(inode);
 	inode->i_size = 0;
 	inode_dec_link_count(dir);
-	inode->i_ctime = dir->i_ctime = dir->i_mtime =
-	    current_fs_time(dir->i_sb);
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
 	mark_inode_dirty(dir);
 
-      end_rmdir:
+end_rmdir:
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
-      out:
+
+out:
 	unlock_kernel();
 	return retval;
 }
@@ -906,11 +875,12 @@
 	inode->i_ctime = dir->i_ctime;
 	retval = 0;
 
-      end_unlink:
+end_unlink:
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
-      out:
+
+out:
 	unlock_kernel();
 	return retval;
 }
@@ -922,7 +892,7 @@
 	struct pathComponent *pc;
 	char *compstart;
 	struct udf_fileident_bh fibh;
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 	int eoffset, elen = 0;
 	struct fileIdentDesc *fi;
 	struct fileIdentDesc cfi;
@@ -945,26 +915,22 @@
 		uint32_t elen;
 
 		block = udf_new_block(inode->i_sb, inode,
-				      UDF_I_LOCATION(inode).
-				      partitionReferenceNum,
-				      UDF_I_LOCATION(inode).logicalBlockNum,
-				      &err);
+				      UDF_I_LOCATION(inode).partitionReferenceNum,
+				      UDF_I_LOCATION(inode).logicalBlockNum, &err);
 		if (!block)
 			goto out_no_entry;
 		epos.block = UDF_I_LOCATION(inode);
 		epos.offset = udf_file_entry_alloc_offset(inode);
 		epos.bh = NULL;
 		eloc.logicalBlockNum = block;
-		eloc.partitionReferenceNum =
-		    UDF_I_LOCATION(inode).partitionReferenceNum;
+		eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 		elen = inode->i_sb->s_blocksize;
 		UDF_I_LENEXTENTS(inode) = elen;
 		udf_add_aext(inode, &epos, eloc, elen, 0);
 		brelse(epos.bh);
 
 		block = udf_get_pblock(inode->i_sb, block,
-				       UDF_I_LOCATION(inode).
-				       partitionReferenceNum, 0);
+				       UDF_I_LOCATION(inode).partitionReferenceNum, 0);
 		epos.bh = udf_tread(inode->i_sb, block);
 		lock_buffer(epos.bh);
 		memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
@@ -972,8 +938,9 @@
 		unlock_buffer(epos.bh);
 		mark_buffer_dirty_inode(epos.bh, inode);
 		ea = epos.bh->b_data + udf_ext0_offset(inode);
-	} else
+	} else {
 		ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
+	}
 
 	eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
 	pc = (struct pathComponent *)ea;
@@ -1010,20 +977,17 @@
 		if (compstart[0] == '.') {
 			if ((symname - compstart) == 1)
 				pc->componentType = 4;
-			else if ((symname - compstart) == 2
-				 && compstart[1] == '.')
+			else if ((symname - compstart) == 2 && compstart[1] == '.')
 				pc->componentType = 3;
 		}
 
 		if (pc->componentType == 5) {
-			if (!
-			    (namelen =
-			     udf_put_filename(inode->i_sb, compstart, name,
-					      symname - compstart)))
+			namelen = udf_put_filename(inode->i_sb, compstart, name,
+						   symname - compstart);
+			if (!namelen)
 				goto out_no_entry;
 
-			if (elen + sizeof(struct pathComponent) + namelen >
-			    eoffset)
+			if (elen + sizeof(struct pathComponent) + namelen > eoffset)
 				goto out_no_entry;
 			else
 				pc->lengthComponentIdent = namelen;
@@ -1053,12 +1017,10 @@
 	if (UDF_SB_LVIDBH(inode->i_sb)) {
 		struct logicalVolHeaderDesc *lvhd;
 		uint64_t uniqueID;
-		lvhd =
-		    (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->
-						    logicalVolContentsUse);
+		lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
 		uniqueID = le64_to_cpu(lvhd->uniqueID);
-		*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-		    cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
+		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
 		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
 			uniqueID += 16;
 		lvhd->uniqueID = cpu_to_le64(uniqueID);
@@ -1074,11 +1036,11 @@
 	d_instantiate(dentry, inode);
 	err = 0;
 
-      out:
+out:
 	unlock_kernel();
 	return err;
 
-      out_no_entry:
+out_no_entry:
 	inode_dec_link_count(inode);
 	iput(inode);
 	goto out;
@@ -1107,12 +1069,10 @@
 	if (UDF_SB_LVIDBH(inode->i_sb)) {
 		struct logicalVolHeaderDesc *lvhd;
 		uint64_t uniqueID;
-		lvhd =
-		    (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->
-						    logicalVolContentsUse);
+		lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
 		uniqueID = le64_to_cpu(lvhd->uniqueID);
-		*(__le32 *) ((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-		    cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
+		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
+			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
 		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
 			uniqueID += 16;
 		lvhd->uniqueID = cpu_to_le64(uniqueID);
@@ -1122,6 +1082,7 @@
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
 		mark_inode_dirty(dir);
 	}
+
 	if (fibh.sbh != fibh.ebh)
 		brelse(fibh.ebh);
 	brelse(fibh.sbh);
@@ -1131,6 +1092,7 @@
 	atomic_inc(&inode->i_count);
 	d_instantiate(dentry, inode);
 	unlock_kernel();
+
 	return 0;
 }
 
@@ -1143,8 +1105,7 @@
 	struct inode *old_inode = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
 	struct udf_fileident_bh ofibh, nfibh;
-	struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi =
-	    NULL, ocfi, ncfi;
+	struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
 	struct buffer_head *dir_bh = NULL;
 	int retval = -ENOENT;
 	kernel_lb_addr tloc;
@@ -1181,36 +1142,27 @@
 		if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
 			dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) -
 						   (UDF_I_EFE(old_inode) ?
-						    sizeof(struct
-							   extendedFileEntry) :
+						    sizeof(struct extendedFileEntry) :
 						    sizeof(struct fileEntry)),
-						   old_inode->i_sb->s_blocksize,
-						   &offset);
+						   old_inode->i_sb->s_blocksize, &offset);
 		} else {
 			dir_bh = udf_bread(old_inode, 0, 0, &retval);
 			if (!dir_bh)
 				goto end_rename;
-			dir_fi =
-			    udf_get_fileident(dir_bh->b_data,
-					      old_inode->i_sb->s_blocksize,
-					      &offset);
+			dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
 		}
 		if (!dir_fi)
 			goto end_rename;
 		tloc = lelb_to_cpu(dir_fi->icb.extLocation);
-		if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0)
-		    != old_dir->i_ino)
+		if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) != old_dir->i_ino)
 			goto end_rename;
 
 		retval = -EMLINK;
-		if (!new_inode
-		    && new_dir->i_nlink >=
-		    (256 << sizeof(new_dir->i_nlink)) - 1)
+		if (!new_inode && new_dir->i_nlink >= (256 << sizeof(new_dir->i_nlink)) - 1)
 			goto end_rename;
 	}
 	if (!nfi) {
-		nfi =
-		    udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
+		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
 		if (!nfi)
 			goto end_rename;
 	}
@@ -1244,13 +1196,12 @@
 	if (dir_fi) {
 		dir_fi->icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(new_dir));
 		udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) +
-						le16_to_cpu(dir_fi->
-							    lengthOfImpUse) +
-						3) & ~3);
+						le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
 		if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
 			mark_inode_dirty(old_inode);
-		} else
+		} else {
 			mark_buffer_dirty_inode(dir_bh, old_inode);
+		}
 		inode_dec_link_count(old_dir);
 		if (new_inode) {
 			inode_dec_link_count(new_inode);
@@ -1268,7 +1219,7 @@
 
 	retval = 0;
 
-      end_rename:
+end_rename:
 	brelse(dir_bh);
 	if (nfi) {
 		if (nfibh.sbh != nfibh.ebh)
@@ -1276,17 +1227,18 @@
 		brelse(nfibh.sbh);
 	}
 	unlock_kernel();
+
 	return retval;
 }
 
 const struct inode_operations udf_dir_inode_operations = {
-	.lookup = udf_lookup,
-	.create = udf_create,
-	.link = udf_link,
-	.unlink = udf_unlink,
-	.symlink = udf_symlink,
-	.mkdir = udf_mkdir,
-	.rmdir = udf_rmdir,
-	.mknod = udf_mknod,
-	.rename = udf_rename,
+	.lookup				= udf_lookup,
+	.create				= udf_create,
+	.link				= udf_link,
+	.unlink				= udf_unlink,
+	.symlink			= udf_symlink,
+	.mkdir				= udf_mkdir,
+	.rmdir				= udf_rmdir,
+	.mknod				= udf_mknod,
+	.rename				= udf_rename,
 };
diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h
index bec5d34..65ff479 100644
--- a/fs/udf/osta_udf.h
+++ b/fs/udf/osta_udf.h
@@ -66,64 +66,64 @@
 #define IS_DF_SOFT_WRITE_PROTECT	0x02
 
 struct UDFIdentSuffix {
-	__le16 UDFRevision;
-	uint8_t OSClass;
-	uint8_t OSIdentifier;
-	uint8_t reserved[4];
+	__le16		UDFRevision;
+	uint8_t		OSClass;
+	uint8_t		OSIdentifier;
+	uint8_t		reserved[4];
 } __attribute__ ((packed));
 
 struct impIdentSuffix {
-	uint8_t OSClass;
-	uint8_t OSIdentifier;
-	uint8_t reserved[6];
+	uint8_t		OSClass;
+	uint8_t		OSIdentifier;
+	uint8_t		reserved[6];
 } __attribute__ ((packed));
 
 struct appIdentSuffix {
-	uint8_t impUse[8];
+	uint8_t		impUse[8];
 } __attribute__ ((packed));
 
 /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
 /* Implementation Use (UDF 2.50 2.2.6.4) */
 struct logicalVolIntegrityDescImpUse {
-	regid impIdent;
-	__le32 numFiles;
-	__le32 numDirs;
-	__le16 minUDFReadRev;
-	__le16 minUDFWriteRev;
-	__le16 maxUDFWriteRev;
-	uint8_t impUse[0];
+	regid		impIdent;
+	__le32		numFiles;
+	__le32		numDirs;
+	__le16		minUDFReadRev;
+	__le16		minUDFWriteRev;
+	__le16		maxUDFWriteRev;
+	uint8_t		impUse[0];
 } __attribute__ ((packed));
 
 /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
 /* Implementation Use (UDF 2.50 2.2.7.2) */
 struct impUseVolDescImpUse {
-	charspec LVICharset;
-	dstring logicalVolIdent[128];
-	dstring LVInfo1[36];
-	dstring LVInfo2[36];
-	dstring LVInfo3[36];
-	regid impIdent;
-	uint8_t impUse[128];
+	charspec	LVICharset;
+	dstring		logicalVolIdent[128];
+	dstring		LVInfo1[36];
+	dstring		LVInfo2[36];
+	dstring		LVInfo3[36];
+	regid		impIdent;
+	uint8_t		impUse[128];
 } __attribute__ ((packed));
 
 struct udfPartitionMap2 {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	uint8_t reserved1[2];
-	regid partIdent;
-	__le16 volSeqNum;
-	__le16 partitionNum;
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		reserved1[2];
+	regid		partIdent;
+	__le16		volSeqNum;
+	__le16		partitionNum;
 } __attribute__ ((packed));
 
 /* Virtual Partition Map (UDF 2.50 2.2.8) */
 struct virtualPartitionMap {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	uint8_t reserved1[2];
-	regid partIdent;
-	__le16 volSeqNum;
-	__le16 partitionNum;
-	uint8_t reserved2[24];
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		reserved1[2];
+	regid		partIdent;
+	__le16		volSeqNum;
+	__le16		partitionNum;
+	uint8_t		reserved2[24];
 } __attribute__ ((packed));
 
 /* Sparable Partition Map (UDF 2.50 2.2.9) */
@@ -143,62 +143,62 @@
 
 /* Metadata Partition Map (UDF 2.4.0 2.2.10) */
 struct metadataPartitionMap {
-	uint8_t partitionMapType;
-	uint8_t partitionMapLength;
-	uint8_t reserved1[2];
-	regid partIdent;
-	__le16 volSeqNum;
-	__le16 partitionNum;
-	__le32 metadataFileLoc;
-	__le32 metadataMirrorFileLoc;
-	__le32 metadataBitmapFileLoc;
-	__le32 allocUnitSize;
-	__le16 alignUnitSize;
-	uint8_t flags;
-	uint8_t reserved2[5];
+	uint8_t		partitionMapType;
+	uint8_t		partitionMapLength;
+	uint8_t		reserved1[2];
+	regid		partIdent;
+	__le16		volSeqNum;
+	__le16		partitionNum;
+	__le32		metadataFileLoc;
+	__le32		metadataMirrorFileLoc;
+	__le32		metadataBitmapFileLoc;
+	__le32		allocUnitSize;
+	__le16		alignUnitSize;
+	uint8_t		flags;
+	uint8_t		reserved2[5];
 } __attribute__ ((packed));
 
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
 struct virtualAllocationTable15 {
-	__le32 VirtualSector[0];
-	regid vatIdent;
-	__le32 previousVATICBLoc;
+	__le32		VirtualSector[0];
+	regid		vatIdent;
+	__le32		previousVATICBLoc;
 } __attribute__ ((packed));
 
 #define ICBTAG_FILE_TYPE_VAT15		0x00U
 
 /* Virtual Allocation Table (UDF 2.50 2.2.11) */
 struct virtualAllocationTable20 {
-	__le16 lengthHeader;
-	__le16 lengthImpUse;
-	dstring logicalVolIdent[128];
-	__le32 previousVATICBLoc;
-	__le32 numFiles;
-	__le32 numDirs;
-	__le16 minReadRevision;
-	__le16 minWriteRevision;
-	__le16 maxWriteRevision;
-	__le16 reserved;
-	uint8_t impUse[0];
-	__le32 vatEntry[0];
+	__le16		lengthHeader;
+	__le16		lengthImpUse;
+	dstring		logicalVolIdent[128];
+	__le32		previousVATICBLoc;
+	__le32		numFiles;
+	__le32		numDirs;
+	__le16		minReadRevision;
+	__le16		minWriteRevision;
+	__le16		maxWriteRevision;
+	__le16		reserved;
+	uint8_t		impUse[0];
+	__le32		vatEntry[0];
 } __attribute__ ((packed));
 
 #define ICBTAG_FILE_TYPE_VAT20		0xF8U
 
 /* Sparing Table (UDF 2.50 2.2.12) */
 struct sparingEntry {
-	__le32 origLocation;
-	__le32 mappedLocation;
+	__le32		origLocation;
+	__le32		mappedLocation;
 } __attribute__ ((packed));
 
 struct sparingTable {
-	tag descTag;
-	regid sparingIdent;
-	__le16 reallocationTableLen;
-	__le16 reserved;
-	__le32 sequenceNum;
+	tag 		descTag;
+	regid		sparingIdent;
+	__le16		reallocationTableLen;
+	__le16		reserved;
+	__le32		sequenceNum;
 	struct sparingEntry
-	 mapEntry[0];
+			mapEntry[0];
 } __attribute__ ((packed));
 
 /* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */
@@ -208,8 +208,8 @@
 
 /* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
 struct allocDescImpUse {
-	__le16 flags;
-	uint8_t impUse[4];
+	__le16		flags;
+	uint8_t		impUse[4];
 } __attribute__ ((packed));
 
 #define AD_IU_EXT_ERASED		0x0001
@@ -220,23 +220,23 @@
 /* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
 /* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
 struct freeEaSpace {
-	__le16 headerChecksum;
-	uint8_t freeEASpace[0];
+	__le16		headerChecksum;
+	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
 /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
 struct DVDCopyrightImpUse {
-	__le16 headerChecksum;
-	uint8_t CGMSInfo;
-	uint8_t dataType;
-	uint8_t protectionSystemInfo[4];
+	__le16		headerChecksum;
+	uint8_t		CGMSInfo;
+	uint8_t		dataType;
+	uint8_t		protectionSystemInfo[4];
 } __attribute__ ((packed));
 
 /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
 /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
 struct freeAppEASpace {
-	__le16 headerChecksum;
-	uint8_t freeEASpace[0];
+	__le16		headerChecksum;
+	uint8_t		freeEASpace[0];
 } __attribute__ ((packed));
 
 /* UDF Defined System Stream (UDF 2.50 3.3.7) */
@@ -276,4 +276,4 @@
 #define UDF_OS_ID_BEOS			0x00U
 #define UDF_OS_ID_WINCE			0x00U
 
-#endif				/* _OSTA_UDF_H */
+#endif /* _OSTA_UDF_H */
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index a95d830..aaab24c 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -14,7 +14,7 @@
  *
  * HISTORY
  *
- * 12/06/98 blf  Created file. 
+ * 12/06/98 blf  Created file.
  *
  */
 
@@ -32,19 +32,17 @@
 			       uint16_t partition, uint32_t offset)
 {
 	if (partition >= UDF_SB_NUMPARTS(sb)) {
-		udf_debug
-		    ("block=%d, partition=%d, offset=%d: invalid partition\n",
-		     block, partition, offset);
+		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
+			  block, partition, offset);
 		return 0xFFFFFFFF;
 	}
 	if (UDF_SB_PARTFUNC(sb, partition))
-		return UDF_SB_PARTFUNC(sb, partition) (sb, block, partition,
-						       offset);
+		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
 	else
 		return UDF_SB_PARTROOT(sb, partition) + block + offset;
 }
 
-uint32_t udf_get_pblock_virt15(struct super_block * sb, uint32_t block,
+uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
 			       uint16_t partition, uint32_t offset)
 {
 	struct buffer_head *bh = NULL;
@@ -52,14 +50,11 @@
 	uint32_t index;
 	uint32_t loc;
 
-	index =
-	    (sb->s_blocksize -
-	     UDF_SB_TYPEVIRT(sb, partition).s_start_offset) / sizeof(uint32_t);
+	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
 
-	if (block > UDF_SB_TYPEVIRT(sb, partition).s_num_entries) {
-		udf_debug
-		    ("Trying to access block beyond end of VAT (%d max %d)\n",
-		     block, UDF_SB_TYPEVIRT(sb, partition).s_num_entries);
+	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) {
+		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
+			  block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
 		return 0xFFFFFFFF;
 	}
 
@@ -69,10 +64,7 @@
 		index = block % (sb->s_blocksize / sizeof(uint32_t));
 	} else {
 		newblock = 0;
-		index =
-		    UDF_SB_TYPEVIRT(sb,
-				    partition).s_start_offset /
-		    sizeof(uint32_t) + block;
+		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
 	}
 
 	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
@@ -83,7 +75,7 @@
 		return 0xFFFFFFFF;
 	}
 
-	loc = le32_to_cpu(((__le32 *) bh->b_data)[index]);
+	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
 
 	brelse(bh);
 
@@ -93,8 +85,8 @@
 	}
 
 	return udf_get_pblock(sb, loc,
-			      UDF_I_LOCATION(UDF_SB_VAT(sb)).
-			      partitionReferenceNum, offset);
+			      UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum,
+			      offset);
 }
 
 inline uint32_t udf_get_pblock_virt20(struct super_block * sb, uint32_t block,
@@ -108,40 +100,29 @@
 {
 	int i;
 	struct sparingTable *st = NULL;
-	uint32_t packet =
-	    (block + offset) & ~(UDF_SB_TYPESPAR(sb, partition).s_packet_len -
-				 1);
+	uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
 
 	for (i = 0; i < 4; i++) {
-		if (UDF_SB_TYPESPAR(sb, partition).s_spar_map[i] != NULL) {
-			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,
-								    partition).
-			    s_spar_map[i]->b_data;
+		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL) {
+			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
 			break;
 		}
 	}
 
 	if (st) {
 		for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
-			if (le32_to_cpu(st->mapEntry[i].origLocation) >=
-			    0xFFFFFFF0)
+			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0) {
 				break;
-			else if (le32_to_cpu(st->mapEntry[i].origLocation) ==
-				 packet) {
-				return le32_to_cpu(st->mapEntry[i].
-						   mappedLocation) + ((block +
-								       offset) &
-								      (UDF_SB_TYPESPAR
-								       (sb,
-									partition).
-								       s_packet_len
-								       - 1));
-			} else if (le32_to_cpu(st->mapEntry[i].origLocation) >
-				   packet)
+			} else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet) {
+				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
+					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
+			} else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet) {
 				break;
+			}
 		}
 	}
-	return UDF_SB_PARTROOT(sb, partition) + block + offset;
+
+	return UDF_SB_PARTROOT(sb,partition) + block + offset;
 }
 
 int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
@@ -153,20 +134,14 @@
 	int i, j, k, l;
 
 	for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
-		if (old_block > UDF_SB_PARTROOT(sb, i) &&
-		    old_block < UDF_SB_PARTROOT(sb, i) + UDF_SB_PARTLEN(sb, i))
-		{
-			sdata = &UDF_SB_TYPESPAR(sb, i);
-			packet =
-			    (old_block -
-			     UDF_SB_PARTROOT(sb,
-					     i)) & ~(sdata->s_packet_len - 1);
+		if (old_block > UDF_SB_PARTROOT(sb,i) &&
+		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) {
+			sdata = &UDF_SB_TYPESPAR(sb,i);
+			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
 
 			for (j = 0; j < 4; j++) {
-				if (UDF_SB_TYPESPAR(sb, i).s_spar_map[j] !=
-				    NULL) {
-					st = (struct sparingTable *)sdata->
-					    s_spar_map[j]->b_data;
+				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
+					st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
 					break;
 				}
 			}
@@ -174,122 +149,51 @@
 			if (!st)
 				return 1;
 
-			for (k = 0; k < le16_to_cpu(st->reallocationTableLen);
-			     k++) {
-				if (le32_to_cpu(st->mapEntry[k].origLocation) ==
-				    0xFFFFFFFF) {
+			for (k = 0; k < le16_to_cpu(st->reallocationTableLen); k++) {
+				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) {
 					for (; j < 4; j++) {
 						if (sdata->s_spar_map[j]) {
-							st = (struct
-							      sparingTable *)
-							    sdata->
-							    s_spar_map[j]->
-							    b_data;
-							st->mapEntry[k].
-							    origLocation =
-							    cpu_to_le32(packet);
-							udf_update_tag((char *)
-								       st,
-								       sizeof
-								       (struct
-									sparingTable)
-								       +
-								       le16_to_cpu
-								       (st->
-									reallocationTableLen)
-								       *
-								       sizeof
-								       (struct
-									sparingEntry));
-							mark_buffer_dirty
-							    (sdata->
-							     s_spar_map[j]);
+							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
+							st->mapEntry[k].origLocation = cpu_to_le32(packet);
+							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
+							mark_buffer_dirty(sdata->s_spar_map[j]);
 						}
 					}
-					*new_block =
-					    le32_to_cpu(st->mapEntry[k].
-							mappedLocation) +
-					    ((old_block -
-					      UDF_SB_PARTROOT(sb,
-							      i)) & (sdata->
-								     s_packet_len
-								     - 1));
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
 					return 0;
-				} else
-				    if (le32_to_cpu
-					(st->mapEntry[k].origLocation) ==
-					packet) {
-					*new_block =
-					    le32_to_cpu(st->mapEntry[k].
-							mappedLocation) +
-					    ((old_block -
-					      UDF_SB_PARTROOT(sb,
-							      i)) & (sdata->
-								     s_packet_len
-								     - 1));
+				} else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) {
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
 					return 0;
-				} else
-				    if (le32_to_cpu
-					(st->mapEntry[k].origLocation) > packet)
+				} else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) {
 					break;
+				}
 			}
-			for (l = k; l < le16_to_cpu(st->reallocationTableLen);
-			     l++) {
-				if (le32_to_cpu(st->mapEntry[l].origLocation) ==
-				    0xFFFFFFFF) {
+
+			for (l = k; l < le16_to_cpu(st->reallocationTableLen); l++) {
+				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) {
 					for (; j < 4; j++) {
 						if (sdata->s_spar_map[j]) {
-							st = (struct
-							      sparingTable *)
-							    sdata->
-							    s_spar_map[j]->
-							    b_data;
-							mapEntry =
-							    st->mapEntry[l];
-							mapEntry.origLocation =
-							    cpu_to_le32(packet);
-							memmove(&st->
-								mapEntry[k + 1],
-								&st->
-								mapEntry[k],
-								(l -
-								 k) *
-								sizeof(struct
-								       sparingEntry));
-							st->mapEntry[k] =
-							    mapEntry;
-							udf_update_tag((char *)
-								       st,
-								       sizeof
-								       (struct
-									sparingTable)
-								       +
-								       le16_to_cpu
-								       (st->
-									reallocationTableLen)
-								       *
-								       sizeof
-								       (struct
-									sparingEntry));
-							mark_buffer_dirty
-							    (sdata->
-							     s_spar_map[j]);
+							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
+							mapEntry = st->mapEntry[l];
+							mapEntry.origLocation = cpu_to_le32(packet);
+							memmove(&st->mapEntry[k + 1], &st->mapEntry[k], (l - k) * sizeof(struct sparingEntry));
+							st->mapEntry[k] = mapEntry;
+							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
+							mark_buffer_dirty(sdata->s_spar_map[j]);
 						}
 					}
-					*new_block =
-					    le32_to_cpu(st->mapEntry[k].
-							mappedLocation) +
-					    ((old_block -
-					      UDF_SB_PARTROOT(sb,
-							      i)) & (sdata->
-								     s_packet_len
-								     - 1));
+					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
+						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
 					return 0;
 				}
 			}
+
 			return 1;
-		}
+		} /* if old_block */
 	}
+
 	if (i == UDF_SB_NUMPARTS(sb)) {
 		/* outside of partitions */
 		/* for now, fail =) */
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 72097ee..7b30964 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -104,11 +104,11 @@
 }
 
 static struct file_system_type udf_fstype = {
-	.owner = THIS_MODULE,
-	.name = "udf",
-	.get_sb = udf_get_sb,
-	.kill_sb = kill_block_super,
-	.fs_flags = FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "udf",
+	.get_sb		= udf_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static struct kmem_cache *udf_inode_cachep;
@@ -116,8 +116,7 @@
 static struct inode *udf_alloc_inode(struct super_block *sb)
 {
 	struct udf_inode_info *ei;
-	ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep,
-						       GFP_KERNEL);
+	ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL);
 	if (!ei)
 		return NULL;
 
@@ -150,7 +149,7 @@
 					     0, (SLAB_RECLAIM_ACCOUNT |
 						 SLAB_MEM_SPREAD),
 					     init_once);
-	if (udf_inode_cachep == NULL)
+	if (!udf_inode_cachep)
 		return -ENOMEM;
 	return 0;
 }
@@ -162,15 +161,15 @@
 
 /* Superblock operations */
 static const struct super_operations udf_sb_ops = {
-	.alloc_inode = udf_alloc_inode,
-	.destroy_inode = udf_destroy_inode,
-	.write_inode = udf_write_inode,
-	.delete_inode = udf_delete_inode,
-	.clear_inode = udf_clear_inode,
-	.put_super = udf_put_super,
-	.write_super = udf_write_super,
-	.statfs = udf_statfs,
-	.remount_fs = udf_remount_fs,
+	.alloc_inode	= udf_alloc_inode,
+	.destroy_inode	= udf_destroy_inode,
+	.write_inode	= udf_write_inode,
+	.delete_inode	= udf_delete_inode,
+	.clear_inode	= udf_clear_inode,
+	.put_super	= udf_put_super,
+	.write_super	= udf_write_super,
+	.statfs		= udf_statfs,
+	.remount_fs	= udf_remount_fs,
 };
 
 struct udf_options {
@@ -193,16 +192,20 @@
 static int __init init_udf_fs(void)
 {
 	int err;
+
 	err = init_inodecache();
 	if (err)
 		goto out1;
 	err = register_filesystem(&udf_fstype);
 	if (err)
 		goto out;
+
 	return 0;
-      out:
+
+out:
 	destroy_inodecache();
-      out1:
+
+out1:
 	return err;
 }
 
@@ -213,7 +216,7 @@
 }
 
 module_init(init_udf_fs)
-    module_exit(exit_udf_fs)
+module_exit(exit_udf_fs)
 
 /*
  * udf_parse_options
@@ -239,7 +242,7 @@
  *
  *	The remaining are for debugging and disaster recovery:
  *
- *	novrs		Skip volume sequence recognition 
+ *	novrs		Skip volume sequence recognition
  *
  *	The following expect a offset from 0.
  *
@@ -268,6 +271,7 @@
  *	July 1, 1997 - Andrew E. Mileski
  *	Written, tested, and released.
  */
+
 enum {
 	Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete,
 	Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad,
@@ -278,32 +282,32 @@
 };
 
 static match_table_t tokens = {
-	{Opt_novrs, "novrs"},
-	{Opt_nostrict, "nostrict"},
-	{Opt_bs, "bs=%u"},
-	{Opt_unhide, "unhide"},
-	{Opt_undelete, "undelete"},
-	{Opt_noadinicb, "noadinicb"},
-	{Opt_adinicb, "adinicb"},
-	{Opt_shortad, "shortad"},
-	{Opt_longad, "longad"},
-	{Opt_uforget, "uid=forget"},
-	{Opt_uignore, "uid=ignore"},
-	{Opt_gforget, "gid=forget"},
-	{Opt_gignore, "gid=ignore"},
-	{Opt_gid, "gid=%u"},
-	{Opt_uid, "uid=%u"},
-	{Opt_umask, "umask=%o"},
-	{Opt_session, "session=%u"},
-	{Opt_lastblock, "lastblock=%u"},
-	{Opt_anchor, "anchor=%u"},
-	{Opt_volume, "volume=%u"},
-	{Opt_partition, "partition=%u"},
-	{Opt_fileset, "fileset=%u"},
-	{Opt_rootdir, "rootdir=%u"},
-	{Opt_utf8, "utf8"},
-	{Opt_iocharset, "iocharset=%s"},
-	{Opt_err, NULL}
+	{Opt_novrs,	"novrs"},
+	{Opt_nostrict,	"nostrict"},
+	{Opt_bs,	"bs=%u"},
+	{Opt_unhide,	"unhide"},
+	{Opt_undelete,	"undelete"},
+	{Opt_noadinicb,	"noadinicb"},
+	{Opt_adinicb,	"adinicb"},
+	{Opt_shortad,	"shortad"},
+	{Opt_longad,	"longad"},
+	{Opt_uforget,	"uid=forget"},
+	{Opt_uignore,	"uid=ignore"},
+	{Opt_gforget,	"gid=forget"},
+	{Opt_gignore,	"gid=ignore"},
+	{Opt_gid,	"gid=%u"},
+	{Opt_uid,	"uid=%u"},
+	{Opt_umask,	"umask=%o"},
+	{Opt_session,	"session=%u"},
+	{Opt_lastblock,	"lastblock=%u"},
+	{Opt_anchor,	"anchor=%u"},
+	{Opt_volume,	"volume=%u"},
+	{Opt_partition,	"partition=%u"},
+	{Opt_fileset,	"fileset=%u"},
+	{Opt_rootdir,	"rootdir=%u"},
+	{Opt_utf8,	"utf8"},
+	{Opt_iocharset,	"iocharset=%s"},
+	{Opt_err,	NULL}
 };
 
 static int udf_parse_options(char *options, struct udf_options *uopt)
@@ -444,9 +448,11 @@
 void udf_write_super(struct super_block *sb)
 {
 	lock_kernel();
+
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_open_lvid(sb);
 	sb->s_dirt = 0;
+
 	unlock_kernel();
 }
 
@@ -455,16 +461,16 @@
 	struct udf_options uopt;
 
 	uopt.flags = UDF_SB(sb)->s_flags;
-	uopt.uid = UDF_SB(sb)->s_uid;
-	uopt.gid = UDF_SB(sb)->s_gid;
+	uopt.uid   = UDF_SB(sb)->s_uid;
+	uopt.gid   = UDF_SB(sb)->s_gid;
 	uopt.umask = UDF_SB(sb)->s_umask;
 
 	if (!udf_parse_options(options, &uopt))
 		return -EINVAL;
 
 	UDF_SB(sb)->s_flags = uopt.flags;
-	UDF_SB(sb)->s_uid = uopt.uid;
-	UDF_SB(sb)->s_gid = uopt.gid;
+	UDF_SB(sb)->s_uid   = uopt.uid;
+	UDF_SB(sb)->s_gid   = uopt.gid;
 	UDF_SB(sb)->s_umask = uopt.umask;
 
 	if (UDF_SB_LVIDBH(sb)) {
@@ -517,6 +523,7 @@
 		printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
 		return 0;
 	}
+
 	return sb->s_blocksize;
 }
 
@@ -552,15 +559,12 @@
 
 		/* Look for ISO  descriptors */
 		vsd = (struct volStructDesc *)(bh->b_data +
-					       (sector &
-						(sb->s_blocksize - 1)));
+					       (sector & (sb->s_blocksize - 1)));
 
 		if (vsd->stdIdent[0] == 0) {
 			brelse(bh);
 			break;
-		} else
-		    if (!strncmp
-			(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) {
+		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) {
 			iso9660 = sector;
 			switch (vsd->structType) {
 			case 0:
@@ -587,21 +591,13 @@
 					  vsd->structType);
 				break;
 			}
-		} else
-		    if (!strncmp
-			(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) {
-		} else
-		    if (!strncmp
-			(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) {
+		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) {
+		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) {
 			brelse(bh);
 			break;
-		} else
-		    if (!strncmp
-			(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) {
+		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) {
 			nsr02 = sector;
-		} else
-		    if (!strncmp
-			(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) {
+		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) {
 			nsr03 = sector;
 		}
 		brelse(bh);
@@ -644,11 +640,10 @@
 
 	if (lastblock) {
 		int varlastblock = udf_variable_to_fixed(lastblock);
-		int last[] = { lastblock, lastblock - 2,
-			lastblock - 150, lastblock - 152,
-			varlastblock, varlastblock - 2,
-			varlastblock - 150, varlastblock - 152
-		};
+		int last[] =  { lastblock, lastblock - 2,
+				lastblock - 150, lastblock - 152,
+				varlastblock, varlastblock - 2,
+				varlastblock - 150, varlastblock - 152 };
 
 		lastblock = 0;
 
@@ -664,88 +659,54 @@
 			if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) {
 				ident = location = 0;
 			} else {
-				ident =
-				    le16_to_cpu(((tag *) bh->b_data)->tagIdent);
-				location =
-				    le32_to_cpu(((tag *) bh->b_data)->
-						tagLocation);
+				ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+				location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 				brelse(bh);
 			}
 
 			if (ident == TAG_IDENT_AVDP) {
 				if (location == last[i] - UDF_SB_SESSION(sb)) {
-					lastblock = UDF_SB_ANCHOR(sb)[0] =
-					    last[i] - UDF_SB_SESSION(sb);
-					UDF_SB_ANCHOR(sb)[1] =
-					    last[i] - 256 - UDF_SB_SESSION(sb);
-				} else if (location ==
-					   udf_variable_to_fixed(last[i]) -
-					   UDF_SB_SESSION(sb)) {
+					lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb);
+					UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb);
+				} else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) {
 					UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-					lastblock = UDF_SB_ANCHOR(sb)[0] =
-					    udf_variable_to_fixed(last[i]) -
-					    UDF_SB_SESSION(sb);
-					UDF_SB_ANCHOR(sb)[1] =
-					    lastblock - 256 -
-					    UDF_SB_SESSION(sb);
-				} else
-					udf_debug
-					    ("Anchor found at block %d, location mismatch %d.\n",
-					     last[i], location);
-			} else if (ident == TAG_IDENT_FE
-				   || ident == TAG_IDENT_EFE) {
+					lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb);
+					UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb);
+				} else {
+					udf_debug("Anchor found at block %d, location mismatch %d.\n",
+						  last[i], location);
+				}
+			} else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) {
 				lastblock = last[i];
 				UDF_SB_ANCHOR(sb)[3] = 512;
 			} else {
-				if (last[i] < 256
-				    || !(bh = sb_bread(sb, last[i] - 256))) {
+				if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) {
 					ident = location = 0;
 				} else {
-					ident =
-					    le16_to_cpu(((tag *) bh->b_data)->
-							tagIdent);
-					location =
-					    le32_to_cpu(((tag *) bh->b_data)->
-							tagLocation);
+					ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+					location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 					brelse(bh);
 				}
 
 				if (ident == TAG_IDENT_AVDP &&
-				    location ==
-				    last[i] - 256 - UDF_SB_SESSION(sb)) {
+				    location == last[i] - 256 - UDF_SB_SESSION(sb)) {
 					lastblock = last[i];
 					UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
 				} else {
-					if (last[i] < 312 + UDF_SB_SESSION(sb)
-					    || !(bh =
-						 sb_bread(sb,
-							  last[i] - 312 -
-							  UDF_SB_SESSION(sb))))
-					{
+					if (last[i] < 312 + UDF_SB_SESSION(sb) ||
+					    !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) {
 						ident = location = 0;
 					} else {
-						ident =
-						    le16_to_cpu(((tag *) bh->
-								 b_data)->
-								tagIdent);
-						location =
-						    le32_to_cpu(((tag *) bh->
-								 b_data)->
-								tagLocation);
+						ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+						location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 						brelse(bh);
 					}
 
 					if (ident == TAG_IDENT_AVDP &&
-					    location ==
-					    udf_variable_to_fixed(last[i]) -
-					    256) {
-						UDF_SET_FLAG(sb,
-							     UDF_FLAG_VARCONV);
-						lastblock =
-						    udf_variable_to_fixed(last
-									  [i]);
-						UDF_SB_ANCHOR(sb)[1] =
-						    lastblock - 256;
+					    location == udf_variable_to_fixed(last[i]) - 256) {
+						UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+						lastblock = udf_variable_to_fixed(last[i]);
+						UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
 					}
 				}
 			}
@@ -755,9 +716,8 @@
 	if (!lastblock) {
 		/* We havn't found the lastblock. check 312 */
 		if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) {
-			ident = le16_to_cpu(((tag *) bh->b_data)->tagIdent);
-			location =
-			    le32_to_cpu(((tag *) bh->b_data)->tagLocation);
+			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
 			brelse(bh);
 
 			if (ident == TAG_IDENT_AVDP && location == 256)
@@ -767,19 +727,13 @@
 
 	for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
 		if (UDF_SB_ANCHOR(sb)[i]) {
-			if (!(bh = udf_read_tagged(sb,
-						   UDF_SB_ANCHOR(sb)[i],
-						   UDF_SB_ANCHOR(sb)[i],
-						   &ident))) {
+			if (!(bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+						   UDF_SB_ANCHOR(sb)[i], &ident))) {
 				UDF_SB_ANCHOR(sb)[i] = 0;
 			} else {
 				brelse(bh);
-				if ((ident != TAG_IDENT_AVDP) && (i ||
-								  (ident !=
-								   TAG_IDENT_FE
-								   && ident !=
-								   TAG_IDENT_EFE)))
-				{
+				if ((ident != TAG_IDENT_AVDP) &&
+				    (i || (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE))) {
 					UDF_SB_ANCHOR(sb)[i] = 0;
 				}
 			}
@@ -789,9 +743,7 @@
 	UDF_SB_LASTBLOCK(sb) = lastblock;
 }
 
-static int
-udf_find_fileset(struct super_block *sb, kernel_lb_addr * fileset,
-		 kernel_lb_addr * root)
+static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
 {
 	struct buffer_head *bh = NULL;
 	long lastblock;
@@ -801,18 +753,19 @@
 	    fileset->partitionReferenceNum != 0xFFFF) {
 		bh = udf_read_ptagged(sb, *fileset, 0, &ident);
 
-		if (!bh)
+		if (!bh) {
 			return 1;
-		else if (ident != TAG_IDENT_FSD) {
+		} else if (ident != TAG_IDENT_FSD) {
 			brelse(bh);
 			return 1;
 		}
 
 	}
 
-	if (!bh) {		/* Search backwards through the partitions */
+	if (!bh) { /* Search backwards through the partitions */
 		kernel_lb_addr newfileset;
 
+/* --> cvg: FIXME - is it reasonable? */
 		return 1;
 
 		for (newfileset.partitionReferenceNum = UDF_SB_NUMPARTS(sb) - 1;
@@ -820,14 +773,11 @@
 		      fileset->logicalBlockNum == 0xFFFFFFFF &&
 		      fileset->partitionReferenceNum == 0xFFFF);
 		     newfileset.partitionReferenceNum--) {
-			lastblock =
-			    UDF_SB_PARTLEN(sb,
-					   newfileset.partitionReferenceNum);
+			lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
 			newfileset.logicalBlockNum = 0;
 
 			do {
-				bh = udf_read_ptagged(sb, newfileset, 0,
-						      &ident);
+				bh = udf_read_ptagged(sb, newfileset, 0, &ident);
 				if (!bh) {
 					newfileset.logicalBlockNum++;
 					continue;
@@ -835,38 +785,28 @@
 
 				switch (ident) {
 				case TAG_IDENT_SBD:
-					{
-						struct spaceBitmapDesc *sp;
-						sp = (struct spaceBitmapDesc *)
-						    bh->b_data;
-						newfileset.logicalBlockNum +=
-						    1 +
-						    ((le32_to_cpu
-						      (sp->numOfBytes) +
-						      sizeof(struct
-							     spaceBitmapDesc) -
-						      1)
-						     >> sb->s_blocksize_bits);
-						brelse(bh);
-						break;
-					}
-				case TAG_IDENT_FSD:
-					{
-						*fileset = newfileset;
-						break;
-					}
-				default:
-					{
-						newfileset.logicalBlockNum++;
-						brelse(bh);
-						bh = NULL;
-						break;
-					}
+				{
+					struct spaceBitmapDesc *sp;
+					sp = (struct spaceBitmapDesc *)bh->b_data;
+					newfileset.logicalBlockNum += 1 +
+						((le32_to_cpu(sp->numOfBytes) +
+						  sizeof(struct spaceBitmapDesc) - 1)
+						 >> sb->s_blocksize_bits);
+					brelse(bh);
+					break;
 				}
-			}
-			while (newfileset.logicalBlockNum < lastblock &&
-			       fileset->logicalBlockNum == 0xFFFFFFFF &&
-			       fileset->partitionReferenceNum == 0xFFFF);
+				case TAG_IDENT_FSD:
+					*fileset = newfileset;
+					break;
+				default:
+					newfileset.logicalBlockNum++;
+					brelse(bh);
+					bh = NULL;
+					break;
+				}
+			} while (newfileset.logicalBlockNum < lastblock &&
+				 fileset->logicalBlockNum == 0xFFFFFFFF &&
+				 fileset->partitionReferenceNum == 0xFFFF);
 		}
 	}
 
@@ -898,10 +838,10 @@
 			      lets_to_cpu(pvoldesc->recordingDateAndTime))) {
 		kernel_timestamp ts;
 		ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
-		udf_debug
-		    ("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
-		     recording, recording_usec, ts.year, ts.month, ts.day,
-		     ts.hour, ts.minute, ts.typeAndTimezone);
+		udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
+			  recording, recording_usec,
+			  ts.year, ts.month, ts.day, ts.hour,
+			  ts.minute, ts.typeAndTimezone);
 		UDF_SB_RECORDTIME(sb).tv_sec = recording;
 		UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000;
 	}
@@ -920,9 +860,8 @@
 	}
 }
 
-static void
-udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
-		 kernel_lb_addr * root)
+static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
+			     kernel_lb_addr *root)
 {
 	struct fileSetDesc *fset;
 
@@ -945,121 +884,72 @@
 
 	for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
 		udf_debug("Searching map: (%d == %d)\n",
-			  UDF_SB_PARTMAPS(sb)[i].s_partition_num,
-			  le16_to_cpu(p->partitionNumber));
-		if (UDF_SB_PARTMAPS(sb)[i].s_partition_num ==
-		    le16_to_cpu(p->partitionNumber)) {
-			UDF_SB_PARTLEN(sb, i) = le32_to_cpu(p->partitionLength);	/* blocks */
-			UDF_SB_PARTROOT(sb, i) =
-			    le32_to_cpu(p->partitionStartingLocation);
-			if (le32_to_cpu(p->accessType) ==
-			    PD_ACCESS_TYPE_READ_ONLY)
-				UDF_SB_PARTFLAGS(sb, i) |=
-				    UDF_PART_FLAG_READ_ONLY;
-			if (le32_to_cpu(p->accessType) ==
-			    PD_ACCESS_TYPE_WRITE_ONCE)
-				UDF_SB_PARTFLAGS(sb, i) |=
-				    UDF_PART_FLAG_WRITE_ONCE;
-			if (le32_to_cpu(p->accessType) ==
-			    PD_ACCESS_TYPE_REWRITABLE)
-				UDF_SB_PARTFLAGS(sb, i) |=
-				    UDF_PART_FLAG_REWRITABLE;
-			if (le32_to_cpu(p->accessType) ==
-			    PD_ACCESS_TYPE_OVERWRITABLE)
-				UDF_SB_PARTFLAGS(sb, i) |=
-				    UDF_PART_FLAG_OVERWRITABLE;
+			  UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
+		if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) {
+			UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
+			UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation);
+			if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY)
+				UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_READ_ONLY;
+			if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_WRITE_ONCE)
+				UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_WRITE_ONCE;
+			if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_REWRITABLE)
+				UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_REWRITABLE;
+			if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_OVERWRITABLE)
+				UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE;
 
-			if (!strcmp
-			    (p->partitionContents.ident,
-			     PD_PARTITION_CONTENTS_NSR02)
-			    || !strcmp(p->partitionContents.ident,
-				       PD_PARTITION_CONTENTS_NSR03)) {
+			if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) ||
+			    !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) {
 				struct partitionHeaderDesc *phd;
 
-				phd =
-				    (struct partitionHeaderDesc *)(p->
-								   partitionContentsUse);
+				phd = (struct partitionHeaderDesc *)(p->partitionContentsUse);
 				if (phd->unallocSpaceTable.extLength) {
-					kernel_lb_addr loc =
-					    { le32_to_cpu(phd->
-							  unallocSpaceTable.
-							  extPosition), i };
+					kernel_lb_addr loc = {
+						.logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition),
+						.partitionReferenceNum = i,
+					};
 
-					UDF_SB_PARTMAPS(sb)[i].s_uspace.
-					    s_table = udf_iget(sb, loc);
-					UDF_SB_PARTFLAGS(sb, i) |=
-					    UDF_PART_FLAG_UNALLOC_TABLE;
-					udf_debug
-					    ("unallocSpaceTable (part %d) @ %ld\n",
-					     i,
-					     UDF_SB_PARTMAPS(sb)[i].s_uspace.
-					     s_table->i_ino);
+					UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table =
+						udf_iget(sb, loc);
+					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE;
+					udf_debug("unallocSpaceTable (part %d) @ %ld\n",
+						  i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
 				}
 				if (phd->unallocSpaceBitmap.extLength) {
 					UDF_SB_ALLOC_BITMAP(sb, i, s_uspace);
-					if (UDF_SB_PARTMAPS(sb)[i].s_uspace.
-					    s_bitmap != NULL) {
-						UDF_SB_PARTMAPS(sb)[i].s_uspace.
-						    s_bitmap->s_extLength =
-						    le32_to_cpu(phd->
-								unallocSpaceBitmap.
-								extLength);
-						UDF_SB_PARTMAPS(sb)[i].s_uspace.
-						    s_bitmap->s_extPosition =
-						    le32_to_cpu(phd->
-								unallocSpaceBitmap.
-								extPosition);
-						UDF_SB_PARTFLAGS(sb, i) |=
-						    UDF_PART_FLAG_UNALLOC_BITMAP;
-						udf_debug
-						    ("unallocSpaceBitmap (part %d) @ %d\n",
-						     i,
-						     UDF_SB_PARTMAPS(sb)[i].
-						     s_uspace.s_bitmap->
-						     s_extPosition);
+					if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL) {
+						UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength =
+							le32_to_cpu(phd->unallocSpaceBitmap.extLength);
+						UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition =
+							le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
+						UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
+						udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
+							  i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
 					}
 				}
 				if (phd->partitionIntegrityTable.extLength)
-					udf_debug
-					    ("partitionIntegrityTable (part %d)\n",
-					     i);
+					udf_debug("partitionIntegrityTable (part %d)\n", i);
 				if (phd->freedSpaceTable.extLength) {
-					kernel_lb_addr loc =
-					    { le32_to_cpu(phd->freedSpaceTable.
-							  extPosition), i };
+					kernel_lb_addr loc = {
+						.logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition),
+						.partitionReferenceNum = i,
+					};
 
-					UDF_SB_PARTMAPS(sb)[i].s_fspace.
-					    s_table = udf_iget(sb, loc);
-					UDF_SB_PARTFLAGS(sb, i) |=
-					    UDF_PART_FLAG_FREED_TABLE;
-					udf_debug
-					    ("freedSpaceTable (part %d) @ %ld\n",
-					     i,
-					     UDF_SB_PARTMAPS(sb)[i].s_fspace.
-					     s_table->i_ino);
+					UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table =
+						udf_iget(sb, loc);
+					UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE;
+					udf_debug("freedSpaceTable (part %d) @ %ld\n",
+						  i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
 				}
 				if (phd->freedSpaceBitmap.extLength) {
 					UDF_SB_ALLOC_BITMAP(sb, i, s_fspace);
-					if (UDF_SB_PARTMAPS(sb)[i].s_fspace.
-					    s_bitmap != NULL) {
-						UDF_SB_PARTMAPS(sb)[i].s_fspace.
-						    s_bitmap->s_extLength =
-						    le32_to_cpu(phd->
-								freedSpaceBitmap.
-								extLength);
-						UDF_SB_PARTMAPS(sb)[i].s_fspace.
-						    s_bitmap->s_extPosition =
-						    le32_to_cpu(phd->
-								freedSpaceBitmap.
-								extPosition);
-						UDF_SB_PARTFLAGS(sb, i) |=
-						    UDF_PART_FLAG_FREED_BITMAP;
-						udf_debug
-						    ("freedSpaceBitmap (part %d) @ %d\n",
-						     i,
-						     UDF_SB_PARTMAPS(sb)[i].
-						     s_fspace.s_bitmap->
-						     s_extPosition);
+					if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL) {
+						UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength =
+							le32_to_cpu(phd->freedSpaceBitmap.extLength);
+						UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition =
+							le32_to_cpu(phd->freedSpaceBitmap.extPosition);
+						UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
+						udf_debug("freedSpaceBitmap (part %d) @ %d\n",
+							  i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
 					}
 				}
 			}
@@ -1070,16 +960,14 @@
 		udf_debug("Partition (%d) not found in partition map\n",
 			  le16_to_cpu(p->partitionNumber));
 	} else {
-		udf_debug
-		    ("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
-		     le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb, i),
-		     UDF_SB_PARTROOT(sb, i), UDF_SB_PARTLEN(sb, i));
+		udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
+			  le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
+			  UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
 	}
 }
 
-static int
-udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
-		    kernel_lb_addr * fileset)
+static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
+			       kernel_lb_addr *fileset)
 {
 	struct logicalVolDesc *lvd;
 	int i, j, offset;
@@ -1090,116 +978,69 @@
 	UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps));
 
 	for (i = 0, offset = 0;
-	     i < UDF_SB_NUMPARTS(sb)
-	     && offset < le32_to_cpu(lvd->mapTableLength);
-	     i++, offset +=
-	     ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->
-	     partitionMapLength) {
-		type =
-		    ((struct genericPartitionMap *)
-		     &(lvd->partitionMaps[offset]))->partitionMapType;
+	     i < UDF_SB_NUMPARTS(sb) && offset < le32_to_cpu(lvd->mapTableLength);
+	     i++, offset += ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) {
+		type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
 		if (type == 1) {
-			struct genericPartitionMap1 *gpm1 =
-			    (struct genericPartitionMap1 *)&(lvd->
-							     partitionMaps
-							     [offset]);
-			UDF_SB_PARTTYPE(sb, i) = UDF_TYPE1_MAP15;
-			UDF_SB_PARTVSN(sb, i) = le16_to_cpu(gpm1->volSeqNum);
-			UDF_SB_PARTNUM(sb, i) = le16_to_cpu(gpm1->partitionNum);
-			UDF_SB_PARTFUNC(sb, i) = NULL;
+			struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]);
+			UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
+			UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
+			UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
+			UDF_SB_PARTFUNC(sb,i) = NULL;
 		} else if (type == 2) {
-			struct udfPartitionMap2 *upm2 =
-			    (struct udfPartitionMap2 *)&(lvd->
-							 partitionMaps[offset]);
-			if (!strncmp
-			    (upm2->partIdent.ident, UDF_ID_VIRTUAL,
-			     strlen(UDF_ID_VIRTUAL))) {
-				if (le16_to_cpu
-				    (((__le16 *) upm2->partIdent.
-				      identSuffix)[0]) == 0x0150) {
-					UDF_SB_PARTTYPE(sb, i) =
-					    UDF_VIRTUAL_MAP15;
-					UDF_SB_PARTFUNC(sb, i) =
-					    udf_get_pblock_virt15;
-				} else
-				    if (le16_to_cpu
-					(((__le16 *) upm2->partIdent.
-					  identSuffix)[0]) == 0x0200) {
-					UDF_SB_PARTTYPE(sb, i) =
-					    UDF_VIRTUAL_MAP20;
-					UDF_SB_PARTFUNC(sb, i) =
-					    udf_get_pblock_virt20;
+			struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]);
+			if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) {
+				if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) {
+					UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
+					UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15;
+				} else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) {
+					UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
+					UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20;
 				}
-			} else
-			    if (!strncmp
-				(upm2->partIdent.ident, UDF_ID_SPARABLE,
-				 strlen(UDF_ID_SPARABLE))) {
+			} else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) {
 				uint32_t loc;
 				uint16_t ident;
 				struct sparingTable *st;
-				struct sparablePartitionMap *spm =
-				    (struct sparablePartitionMap *)&(lvd->
-								     partitionMaps
-								     [offset]);
+				struct sparablePartitionMap *spm = (struct sparablePartitionMap *)&(lvd->partitionMaps[offset]);
 
-				UDF_SB_PARTTYPE(sb, i) = UDF_SPARABLE_MAP15;
-				UDF_SB_TYPESPAR(sb, i).s_packet_len =
-				    le16_to_cpu(spm->packetLength);
+				UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
+				UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength);
 				for (j = 0; j < spm->numSparingTables; j++) {
-					loc =
-					    le32_to_cpu(spm->
-							locSparingTable[j]);
-					UDF_SB_TYPESPAR(sb, i).s_spar_map[j] =
-					    udf_read_tagged(sb, loc, loc,
-							    &ident);
-					if (UDF_SB_TYPESPAR(sb, i).
-					    s_spar_map[j] != NULL) {
-						st = (struct sparingTable *)
-						    UDF_SB_TYPESPAR(sb,
-								    i).
-						    s_spar_map[j]->b_data;
-						if (ident != 0
-						    || strncmp(st->sparingIdent.
-							       ident,
-							       UDF_ID_SPARING,
-							       strlen
-							       (UDF_ID_SPARING)))
-						{
-							brelse(UDF_SB_TYPESPAR
-							       (sb,
-								i).
-							       s_spar_map[j]);
-							UDF_SB_TYPESPAR(sb,
-									i).
-							    s_spar_map[j] =
-							    NULL;
+					loc = le32_to_cpu(spm->locSparingTable[j]);
+					UDF_SB_TYPESPAR(sb,i).s_spar_map[j] =
+						udf_read_tagged(sb, loc, loc, &ident);
+					if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
+						st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data;
+						if (ident != 0 ||
+						    strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) {
+							brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
+							UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
 						}
 					}
 				}
-				UDF_SB_PARTFUNC(sb, i) = udf_get_pblock_spar15;
+				UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
 			} else {
-				udf_debug("Unknown ident: %s\n",
-					  upm2->partIdent.ident);
+				udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
 				continue;
 			}
-			UDF_SB_PARTVSN(sb, i) = le16_to_cpu(upm2->volSeqNum);
-			UDF_SB_PARTNUM(sb, i) = le16_to_cpu(upm2->partitionNum);
+			UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum);
+			UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
 		}
 		udf_debug("Partition (%d:%d) type %d on volume %d\n",
-			  i, UDF_SB_PARTNUM(sb, i), type, UDF_SB_PARTVSN(sb,
-									 i));
+			  i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
 	}
 
 	if (fileset) {
-		long_ad *la = (long_ad *) & (lvd->logicalVolContentsUse[0]);
+		long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
 
 		*fileset = lelb_to_cpu(la->extLocation);
-		udf_debug
-		    ("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
-		     fileset->logicalBlockNum, fileset->partitionReferenceNum);
+		udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
+			  fileset->logicalBlockNum,
+			  fileset->partitionReferenceNum);
 	}
 	if (lvd->integritySeqExt.extLength)
 		udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
+
 	return 0;
 }
 
@@ -1219,9 +1060,7 @@
 		UDF_SB_LVIDBH(sb) = bh;
 
 		if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
-			udf_load_logicalvolint(sb,
-					       leea_to_cpu(UDF_SB_LVID(sb)->
-							   nextIntegrityExt));
+			udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
 
 		if (UDF_SB_LVIDBH(sb) != bh)
 			brelse(bh);
@@ -1247,9 +1086,8 @@
  *	July 1, 1997 - Andrew E. Mileski
  *	Written, tested, and released.
  */
-static int
-udf_process_sequence(struct super_block *sb, long block, long lastblock,
-		     kernel_lb_addr * fileset)
+static int udf_process_sequence(struct super_block *sb, long block, long lastblock,
+				 kernel_lb_addr *fileset)
 {
 	struct buffer_head *bh = NULL;
 	struct udf_vds_record vds[VDS_POS_LENGTH];
@@ -1274,82 +1112,71 @@
 		gd = (struct generic_desc *)bh->b_data;
 		vdsn = le32_to_cpu(gd->volDescSeqNum);
 		switch (ident) {
-		case TAG_IDENT_PVD:	/* ISO 13346 3/10.1 */
+		case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
 			if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) {
-				vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum =
-				    vdsn;
+				vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
 				vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
 			}
 			break;
-		case TAG_IDENT_VDP:	/* ISO 13346 3/10.3 */
+		case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
 			if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) {
 				vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
 				vds[VDS_POS_VOL_DESC_PTR].block = block;
 
 				vdp = (struct volDescPtr *)bh->b_data;
-				next_s =
-				    le32_to_cpu(vdp->nextVolDescSeqExt.
-						extLocation);
-				next_e =
-				    le32_to_cpu(vdp->nextVolDescSeqExt.
-						extLength);
+				next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+				next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
 				next_e = next_e >> sb->s_blocksize_bits;
 				next_e += next_s;
 			}
 			break;
-		case TAG_IDENT_IUVD:	/* ISO 13346 3/10.4 */
+		case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
 			if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) {
-				vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum =
-				    vdsn;
+				vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
 				vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
 			}
 			break;
-		case TAG_IDENT_PD:	/* ISO 13346 3/10.5 */
+		case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
 			if (!vds[VDS_POS_PARTITION_DESC].block)
 				vds[VDS_POS_PARTITION_DESC].block = block;
 			break;
-		case TAG_IDENT_LVD:	/* ISO 13346 3/10.6 */
+		case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
 			if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) {
-				vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum =
-				    vdsn;
+				vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
 				vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
 			}
 			break;
-		case TAG_IDENT_USD:	/* ISO 13346 3/10.8 */
-			if (vdsn >=
-			    vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) {
-				vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum =
-				    vdsn;
+		case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
+			if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) {
+				vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
 				vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
 			}
 			break;
-		case TAG_IDENT_TD:	/* ISO 13346 3/10.9 */
+		case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
 			vds[VDS_POS_TERMINATING_DESC].block = block;
 			if (next_e) {
 				block = next_s;
 				lastblock = next_e;
 				next_s = next_e = 0;
-			} else
+			} else {
 				done = 1;
+			}
 			break;
 		}
 		brelse(bh);
 	}
 	for (i = 0; i < VDS_POS_LENGTH; i++) {
 		if (vds[i].block) {
-			bh = udf_read_tagged(sb, vds[i].block, vds[i].block,
-					     &ident);
+			bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
 
-			if (i == VDS_POS_PRIMARY_VOL_DESC)
+			if (i == VDS_POS_PRIMARY_VOL_DESC) {
 				udf_load_pvoldesc(sb, bh);
-			else if (i == VDS_POS_LOGICAL_VOL_DESC)
+			} else if (i == VDS_POS_LOGICAL_VOL_DESC) {
 				udf_load_logicalvol(sb, bh, fileset);
-			else if (i == VDS_POS_PARTITION_DESC) {
+			} else if (i == VDS_POS_PARTITION_DESC) {
 				struct buffer_head *bh2 = NULL;
 				udf_load_partdesc(sb, bh);
-				for (j = vds[i].block + 1;
-				     j < vds[VDS_POS_TERMINATING_DESC].block;
-				     j++) {
+				for (j = vds[i].block + 1; j <  vds[VDS_POS_TERMINATING_DESC].block; j++) {
 					bh2 = udf_read_tagged(sb, j, j, &ident);
 					gd = (struct generic_desc *)bh2->b_data;
 					if (ident == TAG_IDENT_PD)
@@ -1378,16 +1205,17 @@
 	/* Check that it is NSR02 compliant */
 	/* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
 	else if ((block = udf_vrs(sb, silent)) == -1) {
-		udf_debug
-		    ("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+		udf_debug("Failed to read byte 32768. Assuming open disc. "
+			  "Skipping validity check\n");
 		if (!UDF_SB_LASTBLOCK(sb))
 			UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
 		return 0;
-	} else
+	} else {
 		return !block;
+	}
 }
 
-static int udf_load_partition(struct super_block *sb, kernel_lb_addr * fileset)
+static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
 {
 	struct anchorVolDescPtr *anchor;
 	uint16_t ident;
@@ -1399,28 +1227,20 @@
 		return 1;
 
 	for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
-		if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
-								  UDF_SB_ANCHOR
-								  (sb)[i],
-								  UDF_SB_ANCHOR
-								  (sb)[i],
-								  &ident))) {
+		if (UDF_SB_ANCHOR(sb)[i] &&
+		    (bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+					  UDF_SB_ANCHOR(sb)[i], &ident))) {
 			anchor = (struct anchorVolDescPtr *)bh->b_data;
 
 			/* Locate the main sequence */
-			main_s =
-			    le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
-			main_e =
-			    le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
+			main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
+			main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength );
 			main_e = main_e >> sb->s_blocksize_bits;
 			main_e += main_s;
 
 			/* Locate the reserve sequence */
-			reserve_s =
-			    le32_to_cpu(anchor->reserveVolDescSeqExt.
-					extLocation);
-			reserve_e =
-			    le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
+			reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
+			reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
 			reserve_e = reserve_e >> sb->s_blocksize_bits;
 			reserve_e += reserve_s;
 
@@ -1428,10 +1248,8 @@
 
 			/* Process the main & reserve sequences */
 			/* responsible for finding the PartitionDesc(s) */
-			if (!
-			    (udf_process_sequence(sb, main_s, main_e, fileset)
-			     && udf_process_sequence(sb, reserve_s, reserve_e,
-						     fileset))) {
+			if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
+			      udf_process_sequence(sb, reserve_s, reserve_e, fileset))) {
 				break;
 			}
 		}
@@ -1444,81 +1262,67 @@
 		udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
 
 	for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
+		kernel_lb_addr uninitialized_var(ino);
 		switch (UDF_SB_PARTTYPE(sb, i)) {
 		case UDF_VIRTUAL_MAP15:
 		case UDF_VIRTUAL_MAP20:
-			{
-				kernel_lb_addr uninitialized_var(ino);
-
-				if (!UDF_SB_LASTBLOCK(sb)) {
-					UDF_SB_LASTBLOCK(sb) =
-					    udf_get_last_block(sb);
-					udf_find_anchor(sb);
-				}
-
-				if (!UDF_SB_LASTBLOCK(sb)) {
-					udf_debug
-					    ("Unable to determine Lastblock (For Virtual Partition)\n");
-					return 1;
-				}
-
-				for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) {
-					if (j != i &&
-					    UDF_SB_PARTVSN(sb,
-							   i) ==
-					    UDF_SB_PARTVSN(sb, j)
-					    && UDF_SB_PARTNUM(sb,
-							      i) ==
-					    UDF_SB_PARTNUM(sb, j)) {
-						ino.partitionReferenceNum = j;
-						ino.logicalBlockNum =
-						    UDF_SB_LASTBLOCK(sb) -
-						    UDF_SB_PARTROOT(sb, j);
-						break;
-					}
-				}
-
-				if (j == UDF_SB_NUMPARTS(sb))
-					return 1;
-
-				if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
-					return 1;
-
-				if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) {
-					UDF_SB_TYPEVIRT(sb, i).s_start_offset =
-					    udf_ext0_offset(UDF_SB_VAT(sb));
-					UDF_SB_TYPEVIRT(sb, i).s_num_entries =
-					    (UDF_SB_VAT(sb)->i_size - 36) >> 2;
-				} else if (UDF_SB_PARTTYPE(sb, i) ==
-					   UDF_VIRTUAL_MAP20) {
-					struct buffer_head *bh = NULL;
-					uint32_t pos;
-
-					pos = udf_block_map(UDF_SB_VAT(sb), 0);
-					bh = sb_bread(sb, pos);
-					if (!bh)
-						return 1;
-					UDF_SB_TYPEVIRT(sb, i).s_start_offset =
-					    le16_to_cpu(((struct
-							  virtualAllocationTable20
-							  *)bh->b_data +
-							 udf_ext0_offset
-							 (UDF_SB_VAT(sb)))->
-							lengthHeader) +
-					    udf_ext0_offset(UDF_SB_VAT(sb));
-					UDF_SB_TYPEVIRT(sb, i).s_num_entries =
-					    (UDF_SB_VAT(sb)->i_size -
-					     UDF_SB_TYPEVIRT(sb,
-							     i).
-					     s_start_offset) >> 2;
-					brelse(bh);
-				}
-				UDF_SB_PARTROOT(sb, i) =
-				    udf_get_pblock(sb, 0, i, 0);
-				UDF_SB_PARTLEN(sb, i) =
-				    UDF_SB_PARTLEN(sb,
-						   ino.partitionReferenceNum);
+			if (!UDF_SB_LASTBLOCK(sb)) {
+				UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
+				udf_find_anchor(sb);
 			}
+
+			if (!UDF_SB_LASTBLOCK(sb)) {
+				udf_debug("Unable to determine Lastblock (For "
+						"Virtual Partition)\n");
+				return 1;
+			}
+
+			for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) {
+				if (j != i && UDF_SB_PARTVSN(sb, i) ==
+					UDF_SB_PARTVSN(sb, j) &&
+				    	UDF_SB_PARTNUM(sb, i) ==
+						UDF_SB_PARTNUM(sb, j)) {
+					ino.partitionReferenceNum = j;
+					ino.logicalBlockNum =
+					    UDF_SB_LASTBLOCK(sb) -
+					    UDF_SB_PARTROOT(sb, j);
+					break;
+				}
+			}
+
+			if (j == UDF_SB_NUMPARTS(sb))
+				return 1;
+
+			if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
+				return 1;
+
+			if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) {
+				UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+				    udf_ext0_offset(UDF_SB_VAT(sb));
+				UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+				    (UDF_SB_VAT(sb)->i_size - 36) >> 2;
+			} else if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP20) {
+				struct buffer_head *bh = NULL;
+				uint32_t pos;
+
+				pos = udf_block_map(UDF_SB_VAT(sb), 0);
+				bh = sb_bread(sb, pos);
+				if (!bh)
+					return 1;
+				UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+				    le16_to_cpu(((struct
+					virtualAllocationTable20 *)bh->b_data +
+					  udf_ext0_offset(UDF_SB_VAT(sb)))->
+						lengthHeader) +
+					  udf_ext0_offset(UDF_SB_VAT(sb));
+				UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+				    (UDF_SB_VAT(sb)->i_size -
+				     UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2;
+				brelse(bh);
+			}
+			UDF_SB_PARTROOT(sb, i) = udf_get_pblock(sb, 0, i, 0);
+			UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb,
+						ino.partitionReferenceNum);
 		}
 	}
 	return 0;
@@ -1555,42 +1359,32 @@
 
 static void udf_close_lvid(struct super_block *sb)
 {
+	kernel_timestamp cpu_time;
+	int i;
+
 	if (UDF_SB_LVIDBH(sb) &&
 	    UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN) {
-		int i;
-		kernel_timestamp cpu_time;
-
 		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
 		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
 		if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-			UDF_SB_LVID(sb)->recordingDateAndTime =
-			    cpu_to_lets(cpu_time);
-		if (UDF_MAX_WRITE_VERSION >
-		    le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev))
-			UDF_SB_LVIDIU(sb)->maxUDFWriteRev =
-			    cpu_to_le16(UDF_MAX_WRITE_VERSION);
-		if (UDF_SB_UDFREV(sb) >
-		    le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev))
-			UDF_SB_LVIDIU(sb)->minUDFReadRev =
-			    cpu_to_le16(UDF_SB_UDFREV(sb));
-		if (UDF_SB_UDFREV(sb) >
-		    le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev))
-			UDF_SB_LVIDIU(sb)->minUDFWriteRev =
-			    cpu_to_le16(UDF_SB_UDFREV(sb));
-		UDF_SB_LVID(sb)->integrityType =
-		    cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
+			UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+		if (UDF_MAX_WRITE_VERSION > le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev))
+			UDF_SB_LVIDIU(sb)->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
+		if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev))
+			UDF_SB_LVIDIU(sb)->minUDFReadRev = cpu_to_le16(UDF_SB_UDFREV(sb));
+		if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev))
+			UDF_SB_LVIDIU(sb)->minUDFWriteRev = cpu_to_le16(UDF_SB_UDFREV(sb));
+		UDF_SB_LVID(sb)->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
 
 		UDF_SB_LVID(sb)->descTag.descCRC =
-		    cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
-					le16_to_cpu(UDF_SB_LVID(sb)->descTag.
-						    descCRCLength), 0));
+			cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+					    le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
 
 		UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
 		for (i = 0; i < 16; i++)
 			if (i != 4)
 				UDF_SB_LVID(sb)->descTag.tagChecksum +=
-				    ((uint8_t *) &
-				     (UDF_SB_LVID(sb)->descTag))[i];
+					((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
 
 		mark_buffer_dirty(UDF_SB_LVIDBH(sb));
 	}
@@ -1628,6 +1422,7 @@
 	sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
+
 	sb->s_fs_info = sbi;
 	memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
 
@@ -1679,7 +1474,7 @@
 	UDF_SB_ANCHOR(sb)[2] = uopt.anchor;
 	UDF_SB_ANCHOR(sb)[3] = 256;
 
-	if (udf_check_valid(sb, uopt.novrs, silent)) {	/* read volume recognition sequences */
+	if (udf_check_valid(sb, uopt.novrs, silent)) { /* read volume recognition sequences */
 		printk("UDF-fs: No VRS found\n");
 		goto error_out;
 	}
@@ -1701,10 +1496,8 @@
 	udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
 
 	if (UDF_SB_LVIDBH(sb)) {
-		uint16_t minUDFReadRev =
-		    le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
-		uint16_t minUDFWriteRev =
-		    le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
+		uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
+		uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
 		/* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */
 
 		if (minUDFReadRev > UDF_MAX_READ_VERSION) {
@@ -1729,10 +1522,8 @@
 		goto error_out;
 	}
 
-	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-	    UDF_PART_FLAG_READ_ONLY) {
-		printk
-		    ("UDF-fs: Partition marked readonly; forcing readonly mount\n");
+	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) {
+		printk("UDF-fs: Partition marked readonly; forcing readonly mount\n");
 		sb->s_flags |= MS_RDONLY;
 	}
 
@@ -1744,10 +1535,11 @@
 	if (!silent) {
 		kernel_timestamp ts;
 		udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb));
-		udf_info
-		    ("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
-		     UDFFS_VERSION, UDFFS_DATE, UDF_SB_VOLIDENT(sb), ts.year,
-		     ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone);
+		udf_info("UDF %s (%s) Mounting volume '%s', "
+			 "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+			 UDFFS_VERSION, UDFFS_DATE,
+			 UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
+			 ts.typeAndTimezone);
 	}
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_open_lvid(sb);
@@ -1772,30 +1564,21 @@
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	return 0;
 
-      error_out:
+error_out:
 	if (UDF_SB_VAT(sb))
 		iput(UDF_SB_VAT(sb));
 	if (UDF_SB_NUMPARTS(sb)) {
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_UNALLOC_TABLE)
-			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.
-			     s_table);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_FREED_TABLE)
-			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.
-			     s_table);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_UNALLOC_BITMAP)
-			UDF_SB_FREE_BITMAP(sb, UDF_SB_PARTITION(sb), s_uspace);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_FREED_BITMAP)
-			UDF_SB_FREE_BITMAP(sb, UDF_SB_PARTITION(sb), s_fspace);
-		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) ==
-		    UDF_SPARABLE_MAP15) {
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
 			for (i = 0; i < 4; i++)
-				brelse(UDF_SB_TYPESPAR
-				       (sb,
-					UDF_SB_PARTITION(sb)).s_spar_map[i]);
+				brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
 		}
 	}
 #ifdef CONFIG_UDF_NLS
@@ -1808,6 +1591,7 @@
 	UDF_SB_FREE(sb);
 	kfree(sbi);
 	sb->s_fs_info = NULL;
+
 	return -EINVAL;
 }
 
@@ -1823,8 +1607,8 @@
 	va_start(args, fmt);
 	vsnprintf(error_buf, sizeof(error_buf), fmt, args);
 	va_end(args);
-	printk(KERN_CRIT "UDF-fs error (device %s): %s: %s\n",
-	       sb->s_id, function, error_buf);
+	printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n",
+		sb->s_id, function, error_buf);
 }
 
 void udf_warning(struct super_block *sb, const char *function,
@@ -1859,26 +1643,17 @@
 	if (UDF_SB_VAT(sb))
 		iput(UDF_SB_VAT(sb));
 	if (UDF_SB_NUMPARTS(sb)) {
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_UNALLOC_TABLE)
-			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.
-			     s_table);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_FREED_TABLE)
-			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.
-			     s_table);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_UNALLOC_BITMAP)
-			UDF_SB_FREE_BITMAP(sb, UDF_SB_PARTITION(sb), s_uspace);
-		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-		    UDF_PART_FLAG_FREED_BITMAP)
-			UDF_SB_FREE_BITMAP(sb, UDF_SB_PARTITION(sb), s_fspace);
-		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) ==
-		    UDF_SPARABLE_MAP15) {
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
+			iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
+		if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
+			UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
 			for (i = 0; i < 4; i++)
-				brelse(UDF_SB_TYPESPAR
-				       (sb,
-					UDF_SB_PARTITION(sb)).s_spar_map[i]);
+				brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
 		}
 	}
 #ifdef CONFIG_UDF_NLS
@@ -1917,8 +1692,7 @@
 	buf->f_bavail = buf->f_bfree;
 	buf->f_files = (UDF_SB_LVIDBH(sb) ?
 			(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
-			 le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) +
-	    buf->f_bfree;
+			 le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
 	buf->f_ffree = buf->f_bfree;
 	/* __kernel_fsid_t f_fsid */
 	buf->f_namelen = UDF_NAME_LEN - 2;
@@ -1930,8 +1704,7 @@
 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
 };
 
-static unsigned int
-udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
+static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
 {
 	struct buffer_head *bh = NULL;
 	unsigned int accum = 0;
@@ -1961,8 +1734,8 @@
 
 	bm = (struct spaceBitmapDesc *)bh->b_data;
 	bytes = le32_to_cpu(bm->numOfBytes);
-	index = sizeof(struct spaceBitmapDesc);	/* offset in first block only */
-	ptr = (uint8_t *) bh->b_data;
+	index = sizeof(struct spaceBitmapDesc); /* offset in first block only */
+	ptr = (uint8_t *)bh->b_data;
 
 	while (bytes > 0) {
 		while ((bytes > 0) && (index < sb->s_blocksize)) {
@@ -1981,19 +1754,18 @@
 				goto out;
 			}
 			index = 0;
-			ptr = (uint8_t *) bh->b_data;
+			ptr = (uint8_t *)bh->b_data;
 		}
 	}
 	brelse(bh);
 
-      out:
+out:
 	unlock_kernel();
 
 	return accum;
 }
 
-static unsigned int
-udf_count_free_table(struct super_block *sb, struct inode *table)
+static unsigned int udf_count_free_table(struct super_block *sb, struct inode *table)
 {
 	unsigned int accum = 0;
 	uint32_t elen;
@@ -2007,8 +1779,9 @@
 	epos.offset = sizeof(struct unallocSpaceEntry);
 	epos.bh = NULL;
 
-	while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
+	while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
 		accum += (elen >> table->i_sb->s_blocksize_bits);
+	}
 	brelse(epos.bh);
 
 	unlock_kernel();
@@ -2021,12 +1794,8 @@
 	unsigned int accum = 0;
 
 	if (UDF_SB_LVIDBH(sb)) {
-		if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) >
-		    UDF_SB_PARTITION(sb)) {
-			accum =
-			    le32_to_cpu(UDF_SB_LVID(sb)->
-					freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
+		if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) {
+			accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
 			if (accum == 0xFFFFFFFF)
 				accum = 0;
 		}
@@ -2035,40 +1804,24 @@
 	if (accum)
 		return accum;
 
-	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-	    UDF_PART_FLAG_UNALLOC_BITMAP) {
-		accum +=
-		    udf_count_free_bitmap(sb,
-					  UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION
-							      (sb)].s_uspace.
-					  s_bitmap);
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) {
+		accum += udf_count_free_bitmap(sb,
+					       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
 	}
-	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-	    UDF_PART_FLAG_FREED_BITMAP) {
-		accum +=
-		    udf_count_free_bitmap(sb,
-					  UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION
-							      (sb)].s_fspace.
-					  s_bitmap);
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) {
+		accum += udf_count_free_bitmap(sb,
+					       UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
 	}
 	if (accum)
 		return accum;
 
-	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-	    UDF_PART_FLAG_UNALLOC_TABLE) {
-		accum +=
-		    udf_count_free_table(sb,
-					 UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION
-							     (sb)].s_uspace.
-					 s_table);
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) {
+		accum += udf_count_free_table(sb,
+					      UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
 	}
-	if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) &
-	    UDF_PART_FLAG_FREED_TABLE) {
-		accum +=
-		    udf_count_free_table(sb,
-					 UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION
-							     (sb)].s_fspace.
-					 s_table);
+	if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) {
+		accum += udf_count_free_table(sb,
+					      UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
 	}
 
 	return accum;
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index c4b82a9..e6f933d 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -11,7 +11,7 @@
  *	Each contributing author retains all rights to their own work.
  *
  *  (C) 1998-2001 Ben Fennema
- *  (C) 1999 Stelias Computing Inc 
+ *  (C) 1999 Stelias Computing Inc
  *
  * HISTORY
  *
@@ -33,8 +33,7 @@
 #include <linux/buffer_head.h>
 #include "udf_i.h"
 
-static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen,
-			   char *to)
+static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to)
 {
 	struct pathComponent *pc;
 	int elen = 0;
@@ -81,9 +80,9 @@
 	char *p = kmap(page);
 
 	lock_kernel();
-	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
 		symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
-	else {
+	} else {
 		bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
 
 		if (!bh)
@@ -100,7 +99,8 @@
 	kunmap(page);
 	unlock_page(page);
 	return 0;
-      out:
+
+out:
 	unlock_kernel();
 	SetPageError(page);
 	kunmap(page);
@@ -112,5 +112,5 @@
  * symlinks can't do much...
  */
 const struct address_space_operations udf_symlink_aops = {
-	.readpage = udf_symlink_filler,
+	.readpage		= udf_symlink_filler,
 };
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index b2002da..7fc3912 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -32,13 +32,11 @@
 			 kernel_lb_addr eloc, int8_t etype, uint32_t elen,
 			 uint32_t nelen)
 {
-	kernel_lb_addr neloc = { 0, 0 };
-	int last_block =
-	    (elen + inode->i_sb->s_blocksize -
-	     1) >> inode->i_sb->s_blocksize_bits;
-	int first_block =
-	    (nelen + inode->i_sb->s_blocksize -
-	     1) >> inode->i_sb->s_blocksize_bits;
+	kernel_lb_addr neloc = {};
+	int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
+		inode->i_sb->s_blocksize_bits;
+	int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
+		inode->i_sb->s_blocksize_bits;
 
 	if (nelen) {
 		if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
@@ -70,7 +68,7 @@
  */
 void udf_truncate_tail_extent(struct inode *inode)
 {
-	struct extent_position epos = { NULL, 0, {0, 0} };
+	struct extent_position epos = {};
 	kernel_lb_addr eloc;
 	uint32_t elen, nelen;
 	uint64_t lbcount = 0;
@@ -156,16 +154,16 @@
 		extent_trunc(inode, &epos, eloc, etype, elen, 0);
 		if (!epos.bh) {
 			UDF_I_LENALLOC(inode) =
-			    epos.offset - udf_file_entry_alloc_offset(inode);
+				epos.offset - udf_file_entry_alloc_offset(inode);
 			mark_inode_dirty(inode);
 		} else {
 			struct allocExtDesc *aed =
-			    (struct allocExtDesc *)(epos.bh->b_data);
+				(struct allocExtDesc *)(epos.bh->b_data);
 			aed->lengthAllocDescs =
-			    cpu_to_le32(epos.offset -
-					sizeof(struct allocExtDesc));
-			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)
-			    || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+				cpu_to_le32(epos.offset -
+					    sizeof(struct allocExtDesc));
+			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+			    UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
 				udf_update_tag(epos.bh->b_data, epos.offset);
 			else
 				udf_update_tag(epos.bh->b_data,
@@ -182,7 +180,7 @@
 void udf_truncate_extents(struct inode *inode)
 {
 	struct extent_position epos;
-	kernel_lb_addr eloc, neloc = { 0, 0 };
+	kernel_lb_addr eloc, neloc = {};
 	uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
 	int8_t etype;
 	struct super_block *sb = inode->i_sb;
@@ -198,9 +196,8 @@
 		BUG();
 
 	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
-	byte_offset =
-	    (offset << sb->s_blocksize_bits) +
-	    (inode->i_size & (sb->s_blocksize - 1));
+	byte_offset = (offset << sb->s_blocksize_bits) +
+		(inode->i_size & (sb->s_blocksize - 1));
 	if (etype != -1) {
 		epos.offset -= adsize;
 		extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
@@ -215,9 +212,7 @@
 		else
 			lenalloc -= sizeof(struct allocExtDesc);
 
-		while ((etype =
-			udf_current_aext(inode, &epos, &eloc, &elen,
-					 0)) != -1) {
+		while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
 			if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
 				udf_write_aext(inode, &epos, neloc, nelen, 0);
 				if (indirect_ext_len) {
@@ -229,52 +224,35 @@
 							0, indirect_ext_len);
 				} else {
 					if (!epos.bh) {
-						UDF_I_LENALLOC(inode) =
-						    lenalloc;
+						UDF_I_LENALLOC(inode) = lenalloc;
 						mark_inode_dirty(inode);
 					} else {
 						struct allocExtDesc *aed =
-						    (struct allocExtDesc
-						     *)(epos.bh->b_data);
+							(struct allocExtDesc *)(epos.bh->b_data);
 						aed->lengthAllocDescs =
 						    cpu_to_le32(lenalloc);
-						if (!UDF_QUERY_FLAG
-						    (sb, UDF_FLAG_STRICT)
-						    || UDF_SB_UDFREV(sb) >=
-						    0x0201)
-							udf_update_tag(epos.bh->
-								       b_data,
-								       lenalloc
-								       +
-								       sizeof
-								       (struct
-									allocExtDesc));
+						if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+						    UDF_SB_UDFREV(sb) >= 0x0201)
+							udf_update_tag(epos.bh->b_data,
+								       lenalloc +
+								       sizeof(struct allocExtDesc));
 						else
-							udf_update_tag(epos.bh->
-								       b_data,
-								       sizeof
-								       (struct
-									allocExtDesc));
-						mark_buffer_dirty_inode(epos.bh,
-									inode);
+							udf_update_tag(epos.bh->b_data,
+								       sizeof(struct allocExtDesc));
+						mark_buffer_dirty_inode(epos.bh, inode);
 					}
 				}
 				brelse(epos.bh);
 				epos.offset = sizeof(struct allocExtDesc);
 				epos.block = eloc;
-				epos.bh =
-				    udf_tread(sb,
-					      udf_get_lb_pblock(sb, eloc, 0));
+				epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
 				if (elen)
-					indirect_ext_len = (elen +
-							    sb->s_blocksize -
-							    1) >> sb->
-					    s_blocksize_bits;
+					indirect_ext_len = (elen + sb->s_blocksize -1) >>
+						sb->s_blocksize_bits;
 				else
 					indirect_ext_len = 1;
 			} else {
-				extent_trunc(inode, &epos, eloc, etype, elen,
-					     0);
+				extent_trunc(inode, &epos, eloc, etype, elen, 0);
 				epos.offset += adsize;
 			}
 		}
@@ -292,16 +270,13 @@
 				struct allocExtDesc *aed =
 				    (struct allocExtDesc *)(epos.bh->b_data);
 				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-				if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)
-				    || UDF_SB_UDFREV(sb) >= 0x0201)
+				if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+				    UDF_SB_UDFREV(sb) >= 0x0201)
 					udf_update_tag(epos.bh->b_data,
-						       lenalloc +
-						       sizeof(struct
-							      allocExtDesc));
+						       lenalloc + sizeof(struct allocExtDesc));
 				else
 					udf_update_tag(epos.bh->b_data,
-						       sizeof(struct
-							      allocExtDesc));
+						       sizeof(struct allocExtDesc));
 				mark_buffer_dirty_inode(epos.bh, inode);
 			}
 		}
@@ -314,21 +289,14 @@
 			 *  no extent above inode->i_size => truncate is
 			 *  extending the file by 'offset' blocks.
 			 */
-			if ((!epos.bh
-			     && epos.offset ==
-			     udf_file_entry_alloc_offset(inode)) || (epos.bh
-								     && epos.
-								     offset ==
-								     sizeof
-								     (struct
-								      allocExtDesc)))
-			{
+			if ((!epos.bh &&
+			     epos.offset == udf_file_entry_alloc_offset(inode)) ||
+			    (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
 				/* File has no extents at all or has empty last
 				 * indirect extent! Create a fake extent... */
 				extent.extLocation.logicalBlockNum = 0;
 				extent.extLocation.partitionReferenceNum = 0;
-				extent.extLength =
-				    EXT_NOT_RECORDED_NOT_ALLOCATED;
+				extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
 			} else {
 				epos.offset -= adsize;
 				etype = udf_next_aext(inode, &epos,
@@ -337,10 +305,7 @@
 				extent.extLength |= etype << 30;
 			}
 			udf_extend_file(inode, &epos, &extent,
-					offset +
-					((inode->
-					  i_size & (sb->s_blocksize - 1)) !=
-					 0));
+					offset + ((inode->i_size & (sb->s_blocksize - 1)) != 0));
 		}
 	}
 	UDF_I_LENEXTENTS(inode) = inode->i_size;
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h
index bee4308..d7dbe6f 100644
--- a/fs/udf/udf_i.h
+++ b/fs/udf/udf_i.h
@@ -23,4 +23,4 @@
 #define UDF_I_LAD(X)		( UDF_I(X)->i_ext.i_lad )
 #define UDF_I_DATA(X)		( UDF_I(X)->i_ext.i_data )
 
-#endif				/* !defined(_LINUX_UDF_I_H) */
+#endif /* !defined(_LINUX_UDF_I_H) */
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 60f31d8..3e937d3 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -20,8 +20,8 @@
 #define UDF_FLAG_VARCONV		8
 #define UDF_FLAG_NLS_MAP		9
 #define UDF_FLAG_UTF8			10
-#define UDF_FLAG_UID_FORGET     11	/* save -1 for uid to disk */
-#define UDF_FLAG_UID_IGNORE     12	/* use sb uid instead of on disk uid */
+#define UDF_FLAG_UID_FORGET     11    /* save -1 for uid to disk */
+#define UDF_FLAG_UID_IGNORE     12    /* use sb uid instead of on disk uid */
 #define UDF_FLAG_GID_FORGET     13
 #define UDF_FLAG_GID_IGNORE     14
 
@@ -41,8 +41,7 @@
 
 #define UDF_SB_FREE(X)\
 {\
-	if (UDF_SB(X))\
-	{\
+	if (UDF_SB(X)) {\
 		kfree(UDF_SB_PARTMAPS(X));\
 		UDF_SB_PARTMAPS(X) = NULL;\
 	}\
@@ -51,13 +50,10 @@
 #define UDF_SB_ALLOC_PARTMAPS(X,Y)\
 {\
 	UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
-	if (UDF_SB_PARTMAPS(X) != NULL)\
-	{\
+	if (UDF_SB_PARTMAPS(X) != NULL) {\
 		UDF_SB_NUMPARTS(X) = Y;\
 		memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
-	}\
-	else\
-	{\
+	} else {\
 		UDF_SB_NUMPARTS(X) = 0;\
 		udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
 	}\
@@ -72,15 +68,12 @@
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
 	else\
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
-	if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
-	{\
+	if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL) {\
 		memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
 			(struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
 		UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
-	}\
-	else\
-	{\
+	} else {\
 		udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
 	}\
 }
@@ -90,8 +83,7 @@
 	int i;\
 	int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
 	int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
-	for (i=0; i<nr_groups; i++)\
-	{\
+	for (i = 0; i < nr_groups; i++) {\
 		if (UDF_SB_BITMAP(X,Y,Z,i))\
 			brelse(UDF_SB_BITMAP(X,Y,Z,i));\
 	}\
@@ -139,4 +131,4 @@
 #define UDF_SB_FLAGS(X)				( UDF_SB(X)->s_flags )
 #define UDF_SB_VAT(X)				( UDF_SB(X)->s_vat )
 
-#endif				/* __LINUX_UDF_SB_H */
+#endif /* __LINUX_UDF_SB_H */
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 76f2b82..c8016cc 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -63,8 +63,8 @@
 };
 
 struct generic_desc {
-	tag descTag;
-	__le32 volDescSeqNum;
+	tag		descTag;
+	__le32		volDescSeqNum;
 };
 
 struct ustr {
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h
index 450daab..c4bd120 100644
--- a/fs/udf/udfend.h
+++ b/fs/udf/udfend.h
@@ -7,75 +7,93 @@
 static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
 {
 	kernel_lb_addr out;
+
 	out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
 	out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+
 	return out;
 }
 
 static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
 {
 	lb_addr out;
+
 	out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
 	out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
+
 	return out;
 }
 
 static inline kernel_timestamp lets_to_cpu(timestamp in)
 {
 	kernel_timestamp out;
+
 	memcpy(&out, &in, sizeof(timestamp));
 	out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
 	out.year = le16_to_cpu(in.year);
+
 	return out;
 }
 
 static inline short_ad lesa_to_cpu(short_ad in)
 {
 	short_ad out;
+
 	out.extLength = le32_to_cpu(in.extLength);
 	out.extPosition = le32_to_cpu(in.extPosition);
+
 	return out;
 }
 
 static inline short_ad cpu_to_lesa(short_ad in)
 {
 	short_ad out;
+
 	out.extLength = cpu_to_le32(in.extLength);
 	out.extPosition = cpu_to_le32(in.extPosition);
+
 	return out;
 }
 
 static inline kernel_long_ad lela_to_cpu(long_ad in)
 {
 	kernel_long_ad out;
+
 	out.extLength = le32_to_cpu(in.extLength);
 	out.extLocation = lelb_to_cpu(in.extLocation);
+
 	return out;
 }
 
 static inline long_ad cpu_to_lela(kernel_long_ad in)
 {
 	long_ad out;
+
 	out.extLength = cpu_to_le32(in.extLength);
 	out.extLocation = cpu_to_lelb(in.extLocation);
+
 	return out;
 }
 
 static inline kernel_extent_ad leea_to_cpu(extent_ad in)
 {
 	kernel_extent_ad out;
+
 	out.extLength = le32_to_cpu(in.extLength);
 	out.extLocation = le32_to_cpu(in.extLocation);
+
 	return out;
 }
 
 static inline timestamp cpu_to_lets(kernel_timestamp in)
 {
 	timestamp out;
+
 	memcpy(&out, &in, sizeof(timestamp));
 	out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
 	out.year = cpu_to_le16(in.year);
+
 	return out;
 }
 
-#endif				/* __UDF_ENDIAN_H */
+#endif /* __UDF_ENDIAN_H */
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index b9f3198..3fd80eb 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -18,18 +18,18 @@
    Boston, MA 02111-1307, USA.  */
 
 /*
- * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time 
+ * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
  *     10/04/98: added new table-based lookup after seeing how ugly the gnu code is
  * blf 09/27/99: ripped out all the old code and inserted new table from
- *					John Brockmeyer (without leap second corrections)
- *				 rewrote udf_stamp_to_time and fixed timezone accounting in
-					udf_time_to_stamp.
+ *		 John Brockmeyer (without leap second corrections)
+ *		 rewrote udf_stamp_to_time and fixed timezone accounting in
+ *		 udf_time_to_stamp.
  */
 
 /*
  * We don't take into account leap seconds. This may be correct or incorrect.
  * For more NIST information (especially dealing with leap seconds), see:
- *  http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
+ * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
  */
 
 #include <linux/types.h>
@@ -54,28 +54,28 @@
 };
 
 #define MAX_YEAR_SECONDS	69
-#define SPD 0x15180		/*3600*24 */
-#define SPY(y,l,s) (SPD * (365*y+l)+s)
+#define SPD			0x15180	/*3600*24 */
+#define SPY(y,l,s)		(SPD * (365*y+l)+s)
 
-static time_t year_seconds[MAX_YEAR_SECONDS] = {
-/*1970*/ SPY(0, 0, 0), SPY(1, 0, 0), SPY(2, 0, 0), SPY(3, 1, 0),
-/*1974*/ SPY(4, 1, 0), SPY(5, 1, 0), SPY(6, 1, 0), SPY(7, 2, 0),
-/*1978*/ SPY(8, 2, 0), SPY(9, 2, 0), SPY(10, 2, 0), SPY(11, 3, 0),
-/*1982*/ SPY(12, 3, 0), SPY(13, 3, 0), SPY(14, 3, 0), SPY(15, 4, 0),
-/*1986*/ SPY(16, 4, 0), SPY(17, 4, 0), SPY(18, 4, 0), SPY(19, 5, 0),
-/*1990*/ SPY(20, 5, 0), SPY(21, 5, 0), SPY(22, 5, 0), SPY(23, 6, 0),
-/*1994*/ SPY(24, 6, 0), SPY(25, 6, 0), SPY(26, 6, 0), SPY(27, 7, 0),
-/*1998*/ SPY(28, 7, 0), SPY(29, 7, 0), SPY(30, 7, 0), SPY(31, 8, 0),
-/*2002*/ SPY(32, 8, 0), SPY(33, 8, 0), SPY(34, 8, 0), SPY(35, 9, 0),
-/*2006*/ SPY(36, 9, 0), SPY(37, 9, 0), SPY(38, 9, 0), SPY(39, 10, 0),
-/*2010*/ SPY(40, 10, 0), SPY(41, 10, 0), SPY(42, 10, 0), SPY(43, 11, 0),
-/*2014*/ SPY(44, 11, 0), SPY(45, 11, 0), SPY(46, 11, 0), SPY(47, 12, 0),
-/*2018*/ SPY(48, 12, 0), SPY(49, 12, 0), SPY(50, 12, 0), SPY(51, 13, 0),
-/*2022*/ SPY(52, 13, 0), SPY(53, 13, 0), SPY(54, 13, 0), SPY(55, 14, 0),
-/*2026*/ SPY(56, 14, 0), SPY(57, 14, 0), SPY(58, 14, 0), SPY(59, 15, 0),
-/*2030*/ SPY(60, 15, 0), SPY(61, 15, 0), SPY(62, 15, 0), SPY(63, 16, 0),
-/*2034*/ SPY(64, 16, 0), SPY(65, 16, 0), SPY(66, 16, 0), SPY(67, 17, 0),
-/*2038*/ SPY(68, 17, 0)
+static time_t year_seconds[MAX_YEAR_SECONDS]= {
+/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
+/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
+/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
+/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
+/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
+/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
+/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
+/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
+/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
+/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
+/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
+/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
+/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
+/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
+/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
+/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
+/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
+/*2038*/ SPY(68,17,0)
 };
 
 extern struct timezone sys_tz;
@@ -83,7 +83,7 @@
 #define SECS_PER_HOUR	(60 * 60)
 #define SECS_PER_DAY	(SECS_PER_HOUR * 24)
 
-time_t *udf_stamp_to_time(time_t * dest, long *dest_usec, kernel_timestamp src)
+time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
 {
 	int yday;
 	uint8_t type = src.typeAndTimezone >> 12;
@@ -93,10 +93,11 @@
 		offset = src.typeAndTimezone << 4;
 		/* sign extent offset */
 		offset = (offset >> 4);
-		if (offset == -2047)	/* unspecified offset */
+		if (offset == -2047) /* unspecified offset */
 			offset = 0;
-	} else
+	} else {
 		offset = 0;
+	}
 
 	if ((src.year < EPOCH_YEAR) ||
 	    (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
@@ -107,12 +108,10 @@
 	*dest = year_seconds[src.year - EPOCH_YEAR];
 	*dest -= offset * 60;
 
-	yday = ((__mon_yday[__isleap(src.year)]
+	yday = ((__mon_yday[__isleap (src.year)]
 		 [src.month - 1]) + (src.day - 1));
-	*dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
-	*dest_usec =
-	    src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 +
-	    src.microseconds;
+	*dest += ( ( (yday * 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
+	*dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
 	return dest;
 }
 
@@ -145,8 +144,9 @@
 		long int yg = y + days / 365 - (days % 365 < 0);
 
 		/* Adjust DAYS and Y to match the guessed year.  */
-		days -= ((yg - y) * 365 + LEAPS_THRU_END_OF(yg - 1)
-			 - LEAPS_THRU_END_OF(y - 1));
+		days -= ((yg - y) * 365
+			 + LEAPS_THRU_END_OF (yg - 1)
+			 - LEAPS_THRU_END_OF (y - 1));
 		y = yg;
 	}
 	dest->year = y;
@@ -158,11 +158,9 @@
 	dest->day = days + 1;
 
 	dest->centiseconds = ts.tv_nsec / 10000000;
-	dest->hundredsOfMicroseconds =
-	    (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
-	dest->microseconds =
-	    (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
-	     dest->hundredsOfMicroseconds * 100);
+	dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
+	dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
+			      dest->hundredsOfMicroseconds * 100);
 	return dest;
 }
 
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 4683524..9e6099c 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -29,21 +29,23 @@
 
 static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
 
-static int udf_char_to_ustr(struct ustr *dest, const uint8_t * src, int strlen)
+static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
 {
 	if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
 		return 0;
+
 	memset(dest, 0, sizeof(struct ustr));
 	memcpy(dest->u_name, src, strlen);
 	dest->u_cmpID = 0x08;
 	dest->u_len = strlen;
+
 	return strlen;
 }
 
 /*
  * udf_build_ustr
  */
-int udf_build_ustr(struct ustr *dest, dstring * ptr, int size)
+int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
 {
 	int usesize;
 
@@ -55,13 +57,14 @@
 	dest->u_cmpID = ptr[0];
 	dest->u_len = ptr[size - 1];
 	memcpy(dest->u_name, ptr + 1, usesize - 1);
+
 	return 0;
 }
 
 /*
  * udf_build_ustr_exact
  */
-static int udf_build_ustr_exact(struct ustr *dest, dstring * ptr, int exactsize)
+static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
 {
 	if ((!dest) || (!ptr) || (!exactsize))
 		return -1;
@@ -70,6 +73,7 @@
 	dest->u_cmpID = ptr[0];
 	dest->u_len = exactsize - 1;
 	memcpy(dest->u_name, ptr + 1, exactsize - 1);
+
 	return 0;
 }
 
@@ -129,20 +133,15 @@
 			c = (c << 8) | ocu[i++];
 
 		/* Compress Unicode to UTF-8 */
-		if (c < 0x80U)
-			utf_o->u_name[utf_o->u_len++] = (uint8_t) c;
-		else if (c < 0x800U) {
-			utf_o->u_name[utf_o->u_len++] =
-			    (uint8_t) (0xc0 | (c >> 6));
-			utf_o->u_name[utf_o->u_len++] =
-			    (uint8_t) (0x80 | (c & 0x3f));
+		if (c < 0x80U) {
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
+		} else if (c < 0x800U) {
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
 		} else {
-			utf_o->u_name[utf_o->u_len++] =
-			    (uint8_t) (0xe0 | (c >> 12));
-			utf_o->u_name[utf_o->u_len++] =
-			    (uint8_t) (0x80 | ((c >> 6) & 0x3f));
-			utf_o->u_name[utf_o->u_len++] =
-			    (uint8_t) (0x80 | (c & 0x3f));
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
+			utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
 		}
 	}
 	utf_o->u_cmpID = 8;
@@ -173,7 +172,7 @@
  *	November 12, 1997 - Andrew E. Mileski
  *	Written, tested, and released.
  */
-static int udf_UTF8toCS0(dstring * ocu, struct ustr *utf, int length)
+static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
 {
 	unsigned c, i, max_val, utf_char;
 	int utf_cnt, u_len;
@@ -182,12 +181,12 @@
 	ocu[0] = 8;
 	max_val = 0xffU;
 
-      try_again:
+try_again:
 	u_len = 0U;
 	utf_char = 0U;
 	utf_cnt = 0U;
 	for (i = 0U; i < utf->u_len; i++) {
-		c = (uint8_t) utf->u_name[i];
+		c = (uint8_t)utf->u_name[i];
 
 		/* Complete a multi-byte UTF-8 character */
 		if (utf_cnt) {
@@ -213,37 +212,40 @@
 				} else if ((c & 0xfeU) == 0xfcU) {
 					utf_char = c & 0x01U;
 					utf_cnt = 5;
-				} else
+				} else {
 					goto error_out;
+				}
 				continue;
-			} else
+			} else {
 				/* Single byte UTF-8 character (most common) */
 				utf_char = c;
+			}
 		}
 
 		/* Choose no compression if necessary */
 		if (utf_char > max_val) {
-			if (0xffU == max_val) {
+			if (max_val == 0xffU) {
 				max_val = 0xffffU;
-				ocu[0] = (uint8_t) 0x10U;
+				ocu[0] = (uint8_t)0x10U;
 				goto try_again;
 			}
 			goto error_out;
 		}
 
 		if (max_val == 0xffffU) {
-			ocu[++u_len] = (uint8_t) (utf_char >> 8);
+			ocu[++u_len] = (uint8_t)(utf_char >> 8);
 		}
-		ocu[++u_len] = (uint8_t) (utf_char & 0xffU);
+		ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
 	}
 
 	if (utf_cnt) {
-	      error_out:
+error_out:
 		ocu[++u_len] = '?';
 		printk(KERN_DEBUG "udf: bad UTF-8 character\n");
 	}
 
-	ocu[length - 1] = (uint8_t) u_len + 1;
+	ocu[length - 1] = (uint8_t)u_len + 1;
+
 	return u_len + 1;
 }
 
@@ -288,7 +290,7 @@
 	return utf_o->u_len;
 }
 
-static int udf_NLStoCS0(struct nls_table *nls, dstring * ocu, struct ustr *uni,
+static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
 			int length)
 {
 	unsigned len, i, max_val;
@@ -299,7 +301,7 @@
 	ocu[0] = 8;
 	max_val = 0xffU;
 
-      try_again:
+try_again:
 	u_len = 0U;
 	for (i = 0U; i < uni->u_len; i++) {
 		len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
@@ -308,21 +310,21 @@
 
 		if (uni_char > max_val) {
 			max_val = 0xffffU;
-			ocu[0] = (uint8_t) 0x10U;
+			ocu[0] = (uint8_t)0x10U;
 			goto try_again;
 		}
 
 		if (max_val == 0xffffU)
-			ocu[++u_len] = (uint8_t) (uni_char >> 8);
-		ocu[++u_len] = (uint8_t) (uni_char & 0xffU);
+			ocu[++u_len] = (uint8_t)(uni_char >> 8);
+		ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
 		i += len - 1;
 	}
 
-	ocu[length - 1] = (uint8_t) u_len + 1;
+	ocu[length - 1] = (uint8_t)u_len + 1;
 	return u_len + 1;
 }
 
-int udf_get_filename(struct super_block *sb, uint8_t * sname, uint8_t * dname,
+int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
 		     int flen)
 {
 	struct ustr filename, unifilename;
@@ -334,30 +336,29 @@
 
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
 		if (!udf_CS0toUTF8(&filename, &unifilename)) {
-			udf_debug("Failed in udf_get_filename: sname = %s\n",
-				  sname);
+			udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
 			return 0;
 		}
 	} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
-		if (!udf_CS0toNLS
-		    (UDF_SB(sb)->s_nls_map, &filename, &unifilename)) {
-			udf_debug("Failed in udf_get_filename: sname = %s\n",
-				  sname);
+		if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename)) {
+			udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
 			return 0;
 		}
-	} else
+	} else {
 		return 0;
+	}
 
-	if ((len =
-	     udf_translate_to_linux(dname, filename.u_name, filename.u_len,
-				    unifilename.u_name, unifilename.u_len))) {
+	len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
+				     unifilename.u_name, unifilename.u_len);
+	if (len) {
 		return len;
 	}
+
 	return 0;
 }
 
-int udf_put_filename(struct super_block *sb, const uint8_t * sname,
-		     uint8_t * dname, int flen)
+int udf_put_filename(struct super_block *sb, const uint8_t *sname,
+		     uint8_t *dname, int flen)
 {
 	struct ustr unifilename;
 	int namelen;
@@ -367,31 +368,29 @@
 	}
 
 	if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
-		if (!
-		    (namelen =
-		     udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN))) {
+		namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
+		if (!namelen) {
 			return 0;
 		}
 	} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
-		if (!
-		    (namelen =
-		     udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename,
-				  UDF_NAME_LEN))) {
+		namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN);
+		if (!namelen) {
 			return 0;
 		}
-	} else
+	} else {
 		return 0;
+	}
 
 	return namelen;
 }
 
 #define ILLEGAL_CHAR_MARK	'_'
-#define EXT_MARK			'.'
-#define CRC_MARK			'#'
-#define EXT_SIZE			5
+#define EXT_MARK		'.'
+#define CRC_MARK		'#'
+#define EXT_SIZE 		5
 
-static int udf_translate_to_linux(uint8_t * newName, uint8_t * udfName,
-				  int udfLen, uint8_t * fidName, int fidNameLen)
+static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen,
+				  uint8_t *fidName, int fidNameLen)
 {
 	int index, newIndex = 0, needsCRC = 0;
 	int extIndex = 0, newExtIndex = 0, hasExt = 0;
@@ -399,8 +398,8 @@
 	uint8_t curr;
 	const uint8_t hexChar[] = "0123456789ABCDEF";
 
-	if (udfName[0] == '.' && (udfLen == 1 ||
-				  (udfLen == 2 && udfName[1] == '.'))) {
+	if (udfName[0] == '.' &&
+	    (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
 		needsCRC = 1;
 		newIndex = udfLen;
 		memcpy(newName, udfName, udfLen);
@@ -410,16 +409,13 @@
 			if (curr == '/' || curr == 0) {
 				needsCRC = 1;
 				curr = ILLEGAL_CHAR_MARK;
-				while (index + 1 < udfLen
-				       && (udfName[index + 1] == '/'
-					   || udfName[index + 1] == 0))
+				while (index + 1 < udfLen && (udfName[index + 1] == '/' ||
+							      udfName[index + 1] == 0))
 					index++;
-			}
-			if (curr == EXT_MARK
-			    && (udfLen - index - 1) <= EXT_SIZE) {
-				if (udfLen == index + 1)
+			} if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) {
+				if (udfLen == index + 1) {
 					hasExt = 0;
-				else {
+				} else {
 					hasExt = 1;
 					extIndex = index;
 					newExtIndex = newIndex;
@@ -437,23 +433,16 @@
 
 		if (hasExt) {
 			int maxFilenameLen;
-			for (index = 0;
-			     index < EXT_SIZE && extIndex + index + 1 < udfLen;
-			     index++) {
+			for(index = 0; index < EXT_SIZE && extIndex + index + 1 < udfLen; index++) {
 				curr = udfName[extIndex + index + 1];
 
 				if (curr == '/' || curr == 0) {
 					needsCRC = 1;
 					curr = ILLEGAL_CHAR_MARK;
-					while (extIndex + index + 2 < udfLen
-					       && (index + 1 < EXT_SIZE
-						   &&
-						   (udfName
-						    [extIndex + index + 2] ==
-						    '/'
-						    || udfName[extIndex +
-							       index + 2] ==
-						    0)))
+					while(extIndex + index + 2 < udfLen &&
+					      (index + 1 < EXT_SIZE
+					       && (udfName[extIndex + index + 2] == '/' ||
+						   udfName[extIndex + index + 2] == 0)))
 						index++;
 				}
 				ext[localExtIndex++] = curr;
@@ -463,8 +452,9 @@
 				newIndex = maxFilenameLen;
 			else
 				newIndex = newExtIndex;
-		} else if (newIndex > 250)
+		} else if (newIndex > 250) {
 			newIndex = 250;
+		}
 		newName[newIndex++] = CRC_MARK;
 		valueCRC = udf_crc(fidName, fidNameLen, 0);
 		newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
@@ -478,5 +468,6 @@
 				newName[newIndex++] = ext[index];
 		}
 	}
+
 	return newIndex;
 }
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 8948a64..45662f6 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -486,6 +486,8 @@
 #define ACPI_FUNCTION_NAME(name)
 #endif
 
+#ifdef DEBUG_FUNC_TRACE
+
 #define ACPI_FUNCTION_TRACE(a)          ACPI_FUNCTION_NAME(a) \
 			  acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
 #define ACPI_FUNCTION_TRACE_PTR(a,b)    ACPI_FUNCTION_NAME(a) \
@@ -563,6 +565,27 @@
 
 #endif				/* ACPI_SIMPLE_RETURN_MACROS */
 
+#else /* !DEBUG_FUNC_TRACE */
+
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)
+#define ACPI_FUNCTION_TRACE_U32(a,b)
+#define ACPI_FUNCTION_TRACE_STR(a,b)
+#define ACPI_FUNCTION_EXIT
+#define ACPI_FUNCTION_STATUS_EXIT(s)
+#define ACPI_FUNCTION_VALUE_EXIT(s)
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_ENTRY()
+
+#define return_VOID                     return
+#define return_ACPI_STATUS(s)           return(s)
+#define return_VALUE(s)                 return(s)
+#define return_UINT8(s)                 return(s)
+#define return_UINT32(s)                return(s)
+#define return_PTR(s)                   return(s)
+
+#endif /* DEBUG_FUNC_TRACE */
+
 /* Conditional execution */
 
 #define ACPI_DEBUG_EXEC(a)              a
@@ -599,26 +622,26 @@
 #define ACPI_DEBUG_EXEC(a)
 #define ACPI_NORMAL_EXEC(a)             a;
 
-#define ACPI_DEBUG_DEFINE(a)
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#define ACPI_FUNCTION_NAME(a)
-#define ACPI_FUNCTION_TRACE(a)
-#define ACPI_FUNCTION_TRACE_PTR(a,b)
-#define ACPI_FUNCTION_TRACE_U32(a,b)
-#define ACPI_FUNCTION_TRACE_STR(a,b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
-#define ACPI_FUNCTION_ENTRY()
-#define ACPI_DUMP_STACK_ENTRY(a)
-#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
-#define ACPI_DUMP_ENTRY(a,b)
-#define ACPI_DUMP_TABLES(a,b)
-#define ACPI_DUMP_PATHNAME(a,b,c,d)
-#define ACPI_DUMP_RESOURCE_LIST(a)
-#define ACPI_DUMP_BUFFER(a,b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
+#define ACPI_DEBUG_DEFINE(a)		do { } while(0)
+#define ACPI_DEBUG_ONLY_MEMBERS(a)	do { } while(0)
+#define ACPI_FUNCTION_NAME(a)		do { } while(0)
+#define ACPI_FUNCTION_TRACE(a)		do { } while(0)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)	do { } while(0)
+#define ACPI_FUNCTION_TRACE_U32(a,b)	do { } while(0)
+#define ACPI_FUNCTION_TRACE_STR(a,b)	do { } while(0)
+#define ACPI_FUNCTION_EXIT		do { } while(0)
+#define ACPI_FUNCTION_STATUS_EXIT(s)	do { } while(0)
+#define ACPI_FUNCTION_VALUE_EXIT(s)	do { } while(0)
+#define ACPI_FUNCTION_ENTRY()		do { } while(0)
+#define ACPI_DUMP_STACK_ENTRY(a)	do { } while(0)
+#define ACPI_DUMP_OPERANDS(a,b,c,d,e)	do { } while(0)
+#define ACPI_DUMP_ENTRY(a,b)		do { } while(0)
+#define ACPI_DUMP_TABLES(a,b)		do { } while(0)
+#define ACPI_DUMP_PATHNAME(a,b,c,d)	do { } while(0)
+#define ACPI_DUMP_RESOURCE_LIST(a)	do { } while(0)
+#define ACPI_DUMP_BUFFER(a,b)		do { } while(0)
+#define ACPI_DEBUG_PRINT(pl)		do { } while(0)
+#define ACPI_DEBUG_PRINT_RAW(pl)	do { } while(0)
 
 #define return_VOID                     return
 #define return_ACPI_STATUS(s)           return(s)
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 7812267..c090a8b 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -178,8 +178,8 @@
 
 /* Defaults for debug_level, debug and normal */
 
-#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
-#define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
+#define ACPI_DEBUG_DEFAULT          (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
+#define ACPI_NORMAL_DEFAULT         (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
 #define ACPI_DEBUG_ALL              (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
 
 #endif				/* __ACOUTPUT_H__ */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c6fa5e0..5e3dcf3 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -321,7 +321,8 @@
 };
 
 extern struct kset acpi_subsys;
-
+extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+						u8 type, int data);
 /*
  * External Functions
  */
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
index e2fcee2..62c5ee4 100644
--- a/include/acpi/acpi_numa.h
+++ b/include/acpi/acpi_numa.h
@@ -13,6 +13,7 @@
 
 extern int pxm_to_node(int);
 extern int node_to_pxm(int);
+extern void __acpi_map_pxm_to_node(int, int);
 extern int acpi_map_pxm_to_node(int);
 extern void __cpuinit acpi_unmap_pxm_to_node(int);
 
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index dab2ec5..c785485 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -136,7 +136,7 @@
 
 /*! [Begin] no source code translation */
 
-#if defined(__linux__)
+#if defined(_LINUX) || defined(__linux__)
 #include "aclinux.h"
 
 #elif defined(_AED_EFI)
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index a568717..6ed15a0 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -91,7 +91,10 @@
 #define ACPI_USE_NATIVE_DIVIDE
 #endif
 
+#ifndef __cdecl
 #define __cdecl
+#endif
+
 #define ACPI_FLUSH_CPU_CACHE()
 #endif				/* __KERNEL__ */
 
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index b4b0ffd..f9f987f 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -21,6 +21,8 @@
 #define ACPI_PSD_REV0_REVISION		0	/* Support for _PSD as in ACPI 3.0 */
 #define ACPI_PSD_REV0_ENTRIES		5
 
+#define ACPI_TSD_REV0_REVISION		0	/* Support for _PSD as in ACPI 3.0 */
+#define ACPI_TSD_REV0_ENTRIES		5
 /*
  * Types of coordination defined in ACPI 3.0. Same macros can be used across
  * P, C and T states
@@ -125,17 +127,53 @@
 
 /* Throttling Control */
 
+struct acpi_tsd_package {
+	acpi_integer num_entries;
+	acpi_integer revision;
+	acpi_integer domain;
+	acpi_integer coord_type;
+	acpi_integer num_processors;
+} __attribute__ ((packed));
+
+struct acpi_ptc_register {
+	u8 descriptor;
+	u16 length;
+	u8 space_id;
+	u8 bit_width;
+	u8 bit_offset;
+	u8 reserved;
+	u64 address;
+} __attribute__ ((packed));
+
+struct acpi_processor_tx_tss {
+	acpi_integer freqpercentage;	/* */
+	acpi_integer power;	/* milliWatts */
+	acpi_integer transition_latency;	/* microseconds */
+	acpi_integer control;	/* control value */
+	acpi_integer status;	/* success indicator */
+};
 struct acpi_processor_tx {
 	u16 power;
 	u16 performance;
 };
 
+struct acpi_processor;
 struct acpi_processor_throttling {
-	int state;
+	unsigned int state;
+	unsigned int platform_limit;
+	struct acpi_pct_register control_register;
+	struct acpi_pct_register status_register;
+	unsigned int state_count;
+	struct acpi_processor_tx_tss *states_tss;
+	struct acpi_tsd_package domain_info;
+	cpumask_t shared_cpu_map;
+	int (*acpi_processor_get_throttling) (struct acpi_processor * pr);
+	int (*acpi_processor_set_throttling) (struct acpi_processor * pr,
+					      int state);
+
 	u32 address;
 	u8 duty_offset;
 	u8 duty_width;
-	int state_count;
 	struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
 };
 
@@ -169,6 +207,9 @@
 	u32 id;
 	u32 pblk;
 	int performance_platform_limit;
+	int throttling_platform_limit;
+	/* 0 - states 0..n-th state available */
+
 	struct acpi_processor_flags flags;
 	struct acpi_processor_power power;
 	struct acpi_processor_performance *performance;
@@ -270,7 +311,7 @@
 
 /* in processor_throttling.c */
 int acpi_processor_get_throttling_info(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
 extern struct file_operations acpi_processor_throttling_fops;
 
 /* in processor_idle.c */
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index eb7da54..bda6c81 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -149,4 +149,6 @@
 #define __parainstructions_end	NULL
 #endif
 
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
 #endif /* _I386_ALTERNATIVE_H */
diff --git a/include/asm-i386/cmpxchg.h b/include/asm-i386/cmpxchg.h
index 64dcdf4..f86ede2 100644
--- a/include/asm-i386/cmpxchg.h
+++ b/include/asm-i386/cmpxchg.h
@@ -34,7 +34,7 @@
 		"\n1:\t"
 		"movl (%0), %%eax\n\t"
 		"movl 4(%0), %%edx\n\t"
-		"lock cmpxchg8b (%0)\n\t"
+		LOCK_PREFIX "cmpxchg8b (%0)\n\t"
 		"jnz 1b"
 		: /* no outputs */
 		:	"D"(ptr),
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
index c03290c..43114c8 100644
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -47,6 +47,14 @@
 extern void limit_regions(unsigned long long size);
 extern void print_memory_map(char *who);
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+extern void e820_mark_nosave_regions(void);
+#else
+static inline void e820_mark_nosave_regions(void)
+{
+}
+#endif
+
 #endif/*!__ASSEMBLY__*/
 
 #endif/*__E820_HEADER*/
diff --git a/include/asm-i386/geode.h b/include/asm-i386/geode.h
new file mode 100644
index 0000000..6da4bbb
--- /dev/null
+++ b/include/asm-i386/geode.h
@@ -0,0 +1,159 @@
+/*
+ * AMD Geode definitions
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_GEODE_H_
+#define _ASM_GEODE_H_
+
+#include <asm/processor.h>
+#include <linux/io.h>
+
+/* Generic southbridge functions */
+
+#define GEODE_DEV_PMS 0
+#define GEODE_DEV_ACPI 1
+#define GEODE_DEV_GPIO 2
+#define GEODE_DEV_MFGPT 3
+
+extern int geode_get_dev_base(unsigned int dev);
+
+/* Useful macros */
+#define geode_pms_base()	geode_get_dev_base(GEODE_DEV_PMS)
+#define geode_acpi_base()	geode_get_dev_base(GEODE_DEV_ACPI)
+#define geode_gpio_base()	geode_get_dev_base(GEODE_DEV_GPIO)
+#define geode_mfgpt_base()	geode_get_dev_base(GEODE_DEV_MFGPT)
+
+/* MSRS */
+
+#define GX_GLCP_SYS_RSTPLL	0x4C000014
+
+#define MSR_LBAR_SMB		0x5140000B
+#define MSR_LBAR_GPIO		0x5140000C
+#define MSR_LBAR_MFGPT		0x5140000D
+#define MSR_LBAR_ACPI		0x5140000E
+#define MSR_LBAR_PMS		0x5140000F
+
+#define MSR_PIC_YSEL_LOW	0x51400020
+#define MSR_PIC_YSEL_HIGH	0x51400021
+#define MSR_PIC_ZSEL_LOW	0x51400022
+#define MSR_PIC_ZSEL_HIGH	0x51400023
+
+#define MFGPT_IRQ_MSR		0x51400028
+#define MFGPT_NR_MSR		0x51400029
+
+/* Resource Sizes */
+
+#define LBAR_GPIO_SIZE		0xFF
+#define LBAR_MFGPT_SIZE		0x40
+#define LBAR_ACPI_SIZE		0x40
+#define LBAR_PMS_SIZE		0x80
+
+/* ACPI registers (PMS block) */
+
+/*
+ * PM1_EN is only valid when VSA is enabled for 16 bit reads.
+ * When VSA is not enabled, *always* read both PM1_STS and PM1_EN
+ * with a 32 bit read at offset 0x0
+ */
+
+#define PM1_STS			0x00
+#define PM1_EN			0x02
+#define PM1_CNT			0x08
+#define PM2_CNT			0x0C
+#define PM_TMR			0x10
+#define PM_GPE0_STS		0x18
+#define PM_GPE0_EN		0x1C
+
+/* PMC registers (PMS block) */
+
+#define PM_SSD			0x00
+#define PM_SCXA			0x04
+#define PM_SCYA			0x08
+#define PM_OUT_SLPCTL		0x0C
+#define PM_SCLK			0x10
+#define PM_SED			0x1
+#define PM_SCXD			0x18
+#define PM_SCYD			0x1C
+#define PM_IN_SLPCTL		0x20
+#define PM_WKD			0x30
+#define PM_WKXD			0x34
+#define PM_RD			0x38
+#define PM_WKXA			0x3C
+#define PM_FSD			0x40
+#define PM_TSD			0x44
+#define PM_PSD			0x48
+#define PM_NWKD			0x4C
+#define PM_AWKD			0x50
+#define PM_SSC			0x54
+
+/* GPIO */
+
+#define GPIO_OUTPUT_VAL		0x00
+#define GPIO_OUTPUT_ENABLE	0x04
+#define GPIO_OUTPUT_OPEN_DRAIN	0x08
+#define GPIO_OUTPUT_INVERT	0x0C
+#define GPIO_OUTPUT_AUX1	0x10
+#define GPIO_OUTPUT_AUX2	0x14
+#define GPIO_PULL_UP		0x18
+#define GPIO_PULL_DOWN		0x1C
+#define GPIO_INPUT_ENABLE	0x20
+#define GPIO_INPUT_INVERT	0x24
+#define GPIO_INPUT_FILTER	0x28
+#define GPIO_INPUT_EVENT_COUNT	0x2C
+#define GPIO_READ_BACK		0x30
+#define GPIO_INPUT_AUX1		0x34
+#define GPIO_EVENTS_ENABLE	0x38
+#define GPIO_LOCK_ENABLE	0x3C
+#define GPIO_POSITIVE_EDGE_EN	0x40
+#define GPIO_NEGATIVE_EDGE_EN	0x44
+#define GPIO_POSITIVE_EDGE_STS	0x48
+#define GPIO_NEGATIVE_EDGE_STS	0x4C
+
+#define GPIO_MAP_X		0xE0
+#define GPIO_MAP_Y		0xE4
+#define GPIO_MAP_Z		0xE8
+#define GPIO_MAP_W		0xEC
+
+extern void geode_gpio_set(unsigned int, unsigned int);
+extern void geode_gpio_clear(unsigned int, unsigned int);
+extern int geode_gpio_isset(unsigned int, unsigned int);
+extern void geode_gpio_setup_event(unsigned int, int, int);
+extern void geode_gpio_set_irq(unsigned int, unsigned int);
+
+static inline void geode_gpio_event_irq(unsigned int gpio, int pair)
+{
+	geode_gpio_setup_event(gpio, pair, 0);
+}
+
+static inline void geode_gpio_event_pme(unsigned int gpio, int pair)
+{
+	geode_gpio_setup_event(gpio, pair, 1);
+}
+
+/* Specific geode tests */
+
+static inline int is_geode_gx(void)
+{
+	return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) &&
+		(boot_cpu_data.x86 == 5) &&
+		(boot_cpu_data.x86_model == 5));
+}
+
+static inline int is_geode_lx(void)
+{
+	return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+		(boot_cpu_data.x86 == 5) &&
+		(boot_cpu_data.x86_model == 10));
+}
+
+static inline int is_geode(void)
+{
+	return (is_geode_gx() || is_geode_lx());
+}
+
+#endif
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
index dddeedf..c82dc7e 100644
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -4,112 +4,82 @@
 
 #ifdef CONFIG_HPET_TIMER
 
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/msr.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-
 /*
  * Documentation on HPET can be found at:
  *      http://www.intel.com/ial/home/sp/pcmmspec.htm
  *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
  */
 
-#define HPET_MMAP_SIZE	1024
+#define HPET_MMAP_SIZE		1024
 
-#define HPET_ID		0x000
-#define HPET_PERIOD	0x004
-#define HPET_CFG	0x010
-#define HPET_STATUS	0x020
-#define HPET_COUNTER	0x0f0
-#define HPET_T0_CFG	0x100
-#define HPET_T0_CMP	0x108
-#define HPET_T0_ROUTE	0x110
-#define HPET_T1_CFG	0x120
-#define HPET_T1_CMP	0x128
-#define HPET_T1_ROUTE	0x130
-#define HPET_T2_CFG	0x140
-#define HPET_T2_CMP	0x148
-#define HPET_T2_ROUTE	0x150
+#define HPET_ID			0x000
+#define HPET_PERIOD		0x004
+#define HPET_CFG		0x010
+#define HPET_STATUS		0x020
+#define HPET_COUNTER		0x0f0
+#define HPET_T0_CFG		0x100
+#define HPET_T0_CMP		0x108
+#define HPET_T0_ROUTE		0x110
+#define HPET_T1_CFG		0x120
+#define HPET_T1_CMP		0x128
+#define HPET_T1_ROUTE		0x130
+#define HPET_T2_CFG		0x140
+#define HPET_T2_CMP		0x148
+#define HPET_T2_ROUTE		0x150
 
-#define HPET_ID_LEGSUP	0x00008000
-#define HPET_ID_NUMBER	0x00001f00
-#define HPET_ID_REV	0x000000ff
+#define HPET_ID_REV		0x000000ff
+#define HPET_ID_NUMBER		0x00001f00
+#define HPET_ID_64BIT		0x00002000
+#define HPET_ID_LEGSUP		0x00008000
+#define HPET_ID_VENDOR		0xffff0000
 #define	HPET_ID_NUMBER_SHIFT	8
+#define HPET_ID_VENDOR_SHIFT	16
 
-#define HPET_CFG_ENABLE	0x001
-#define HPET_CFG_LEGACY	0x002
+#define HPET_ID_VENDOR_8086	0x8086
+
+#define HPET_CFG_ENABLE		0x001
+#define HPET_CFG_LEGACY		0x002
 #define	HPET_LEGACY_8254	2
 #define	HPET_LEGACY_RTC		8
 
-#define HPET_TN_ENABLE		0x004
-#define HPET_TN_PERIODIC	0x008
-#define HPET_TN_PERIODIC_CAP	0x010
-#define HPET_TN_SETVAL		0x040
-#define HPET_TN_32BIT		0x100
+#define HPET_TN_LEVEL		0x0002
+#define HPET_TN_ENABLE		0x0004
+#define HPET_TN_PERIODIC	0x0008
+#define HPET_TN_PERIODIC_CAP	0x0010
+#define HPET_TN_64BIT_CAP	0x0020
+#define HPET_TN_SETVAL		0x0040
+#define HPET_TN_32BIT		0x0100
+#define HPET_TN_ROUTE		0x3e00
+#define HPET_TN_FSB		0x4000
+#define HPET_TN_FSB_CAP		0x8000
+#define HPET_TN_ROUTE_SHIFT	9
 
-/* Use our own asm for 64 bit multiply/divide */
-#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) 			\
-		__asm__ __volatile__("mull %2" 				\
-				:"=a" (eax_out), "=d" (edx_out) 	\
-				:"r" (reg_in), "0" (eax_in))
-
-#define ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) 		\
-		__asm__ __volatile__("divl %2" 				\
-				:"=a" (eax_out), "=d" (edx_out) 	\
-				:"r" (reg_in), "0" (eax_in), "1" (edx_in))
-
-#define KERNEL_TICK_USEC 	(1000000UL/HZ)	/* tick value in microsec */
 /* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD (100000000UL)
+#define HPET_MAX_PERIOD		100000000UL
 /*
  * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
  * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
  */
-#define HPET_MIN_PERIOD (100000UL)
-#define HPET_TICK_RATE  (HZ * 100000UL)
+#define HPET_MIN_PERIOD		100000UL
 
-extern unsigned long hpet_address;	/* hpet memory map physical address */
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
 extern int is_hpet_enabled(void);
-
-#ifdef CONFIG_X86_64
-extern unsigned long hpet_tick;	/* hpet clks count per tick */
-extern int hpet_use_timer;
-extern int hpet_rtc_timer_init(void);
 extern int hpet_enable(void);
-extern int is_hpet_capable(void);
-extern int hpet_readl(unsigned long a);
-#else
-extern int hpet_enable(void);
-#endif
 
 #ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
 extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
 extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+			       unsigned char sec);
 extern int hpet_set_periodic_freq(unsigned long freq);
 extern int hpet_rtc_dropped_irq(void);
 extern int hpet_rtc_timer_init(void);
 extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
 #endif /* CONFIG_HPET_EMULATE_RTC */
 
 #else
diff --git a/include/asm-i386/i8253.h b/include/asm-i386/i8253.h
index 6cb0dd4..7577d05 100644
--- a/include/asm-i386/i8253.h
+++ b/include/asm-i386/i8253.h
@@ -3,19 +3,15 @@
 
 #include <linux/clockchips.h>
 
+/* i8253A PIT registers */
+#define PIT_MODE		0x43
+#define PIT_CH0			0x40
+#define PIT_CH2			0x42
+
 extern spinlock_t i8253_lock;
 
 extern struct clock_event_device *global_clock_event;
 
-/**
- * pit_interrupt_hook - hook into timer tick
- * @regs:	standard registers from interrupt
- *
- * Call the global clock event handler.
- **/
-static inline void pit_interrupt_hook(void)
-{
-	global_clock_event->event_handler(global_clock_event);
-}
+extern void setup_pit_timer(void);
 
 #endif	/* __ASM_I8253_H__ */
diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h
index 56e5689..23ecda0 100644
--- a/include/asm-i386/mach-default/do_timer.h
+++ b/include/asm-i386/mach-default/do_timer.h
@@ -12,5 +12,5 @@
 
 static inline void do_timer_interrupt_hook(void)
 {
-	pit_interrupt_hook();
+	global_clock_event->event_handler(global_clock_event);
 }
diff --git a/include/asm-i386/mach-default/io_ports.h b/include/asm-i386/mach-default/io_ports.h
index a96d9f6..48540ba9 100644
--- a/include/asm-i386/mach-default/io_ports.h
+++ b/include/asm-i386/mach-default/io_ports.h
@@ -7,11 +7,6 @@
 #ifndef _MACH_IO_PORTS_H
 #define _MACH_IO_PORTS_H
 
-/* i8253A PIT registers */
-#define PIT_MODE		0x43
-#define PIT_CH0			0x40
-#define PIT_CH2			0x42
-
 /* i8259A PIC registers */
 #define PIC_MASTER_CMD		0x20
 #define PIC_MASTER_IMR		0x21
diff --git a/include/asm-i386/mach-default/mach_reboot.h b/include/asm-i386/mach-default/mach_reboot.h
index a955e57..e23fd9f 100644
--- a/include/asm-i386/mach-default/mach_reboot.h
+++ b/include/asm-i386/mach-default/mach_reboot.h
@@ -19,14 +19,37 @@
 static inline void mach_reboot(void)
 {
 	int i;
+
+	/* old method, works on most machines */
 	for (i = 0; i < 10; i++) {
 		kb_wait();
 		udelay(50);
+		outb(0xfe, 0x64);	/* pulse reset low */
+		udelay(50);
+	}
+
+	/* New method: sets the "System flag" which, when set, indicates
+	 * successful completion of the keyboard controller self-test (Basic
+	 * Assurance Test, BAT).  This is needed for some machines with no
+	 * keyboard plugged in.  This read-modify-write sequence sets only the
+	 * system flag
+	 */
+	for (i = 0; i < 10; i++) {
+		int cmd;
+
+		outb(0x20, 0x64);	/* read Controller Command Byte */
+		udelay(50);
+		kb_wait();
+		udelay(50);
+		cmd = inb(0x60);
+		udelay(50);
+		kb_wait();
+		udelay(50);
 		outb(0x60, 0x64);	/* write Controller Command Byte */
 		udelay(50);
 		kb_wait();
 		udelay(50);
-		outb(0x14, 0x60);	/* set "System flag" */
+		outb(cmd | 0x04, 0x60);	/* set "System flag" */
 		udelay(50);
 		kb_wait();
 		udelay(50);
diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h
index 60f9dcc..bc2b589 100644
--- a/include/asm-i386/mach-voyager/do_timer.h
+++ b/include/asm-i386/mach-voyager/do_timer.h
@@ -12,7 +12,7 @@
  **/
 static inline void do_timer_interrupt_hook(void)
 {
-	pit_interrupt_hook();
+	global_clock_event->event_handler(global_clock_event);
 	voyager_timer_interrupt();
 }
 
diff --git a/include/asm-i386/mc146818rtc.h b/include/asm-i386/mc146818rtc.h
index 99a8900..1613b42 100644
--- a/include/asm-i386/mc146818rtc.h
+++ b/include/asm-i386/mc146818rtc.h
@@ -6,6 +6,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/processor.h>
 #include <linux/mc146818rtc.h>
 
 #ifndef RTC_PORT
@@ -43,8 +44,10 @@
 	unsigned long new;
 	new = ((smp_processor_id()+1) << 8) | reg;
 	for (;;) {
-		if (cmos_lock)
+		if (cmos_lock) {
+			cpu_relax();
 			continue;
+		}
 		if (__cmpxchg(&cmos_lock, 0, new, sizeof(cmos_lock)) == 0)
 			return;
 	}
diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h
index b0a02ee..d56d897 100644
--- a/include/asm-i386/mce.h
+++ b/include/asm-i386/mce.h
@@ -5,3 +5,7 @@
 #endif
 
 extern int mce_disabled;
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index fb1e133..ff30c98 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -57,5 +57,7 @@
 int lapic_watchdog_ok(void);
 void disable_lapic_nmi_watchdog(void);
 void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
 
 #endif /* ASM_NMI_H */
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 99cf5d3..80ecc66 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -44,7 +44,6 @@
 extern int nx_enabled;
 
 #ifdef CONFIG_X86_PAE
-extern unsigned long long __supported_pte_mask;
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
 typedef struct { unsigned long long pmd; } pmd_t;
 typedef struct { unsigned long long pgd; } pgd_t;
diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h
index 392d3fe..d790343 100644
--- a/include/asm-i386/pci.h
+++ b/include/asm-i386/pci.h
@@ -3,6 +3,11 @@
 
 
 #ifdef __KERNEL__
+
+struct pci_sysdata {
+	int		node;		/* NUMA node */
+};
+
 #include <linux/mm.h>		/* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
diff --git a/include/asm-i386/processor-cyrix.h b/include/asm-i386/processor-cyrix.h
new file mode 100644
index 0000000..97568ad
--- /dev/null
+++ b/include/asm-i386/processor-cyrix.h
@@ -0,0 +1,30 @@
+/*
+ * NSC/Cyrix CPU indexed register access. Must be inlined instead of
+ * macros to ensure correct access ordering
+ * Access order is always 0x22 (=offset), 0x23 (=value)
+ *
+ * When using the old macros a line like
+ *   setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
+ * gets expanded to:
+ *  do {
+ *    outb((CX86_CCR2), 0x22);
+ *    outb((({
+ *        outb((CX86_CCR2), 0x22);
+ *        inb(0x23);
+ *    }) | 0x88), 0x23);
+ *  } while (0);
+ *
+ * which in fact violates the access order (= 0x22, 0x22, 0x23, 0x23).
+ */
+
+static inline u8 getCx86(u8 reg)
+{
+	outb(reg, 0x22);
+	return inb(0x23);
+}
+
+static inline void setCx86(u8 reg, u8 data)
+{
+	outb(reg, 0x22);
+	outb(data, 0x23);
+}
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 422cffe..3845fe7 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -88,7 +88,6 @@
 #define X86_VENDOR_UMC 3
 #define X86_VENDOR_NEXGEN 4
 #define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
 #define X86_VENDOR_NSC 8
 #define X86_VENDOR_NUM 9
@@ -169,17 +168,6 @@
 	write_cr4(cr4);
 }
 
-/*
- *      NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
-	outb((reg), 0x22); \
-	outb((data), 0x23); \
-} while (0)
-
 /* Stop speculative execution */
 static inline void sync_core(void)
 {
diff --git a/include/asm-i386/resume-trace.h b/include/asm-i386/resume-trace.h
new file mode 100644
index 0000000..ec9cfd65
--- /dev/null
+++ b/include/asm-i386/resume-trace.h
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do {					\
+	if (pm_trace_enabled) {					\
+		void *tracedata;				\
+		asm volatile("movl $1f,%0\n"			\
+			".section .tracedata,\"a\"\n"		\
+			"1:\t.word %c1\n"			\
+			"\t.long %c2\n"				\
+			".previous"				\
+			:"=r" (tracedata)			\
+			: "i" (__LINE__), "i" (__FILE__));	\
+		generate_resume_trace(tracedata, user);		\
+	}							\
+} while (0)
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index b927736..a9b6445 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -2,203 +2,35 @@
 #define _I386_STRING_H_
 
 #ifdef __KERNEL__
-/*
- * On a 486 or Pentium, we are better off not using the
- * byte string operations. But on a 386 or a PPro the
- * byte string ops are faster than doing it by hand
- * (MUCH faster on a Pentium).
- */
 
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strsep,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- *		NO Copyright (C) 1991, 1992 Linus Torvalds,
- *		consider these trivial functions to be PD.
- */
-
-/* AK: in fact I bet it would be better to move this stuff all out of line.
- */
+/* Let gcc decide wether to inline or use the out of line functions */
 
 #define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
-	"1:\tlodsb\n\t"
-	"stosb\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b"
-	: "=&S" (d0), "=&D" (d1), "=&a" (d2)
-	:"0" (src),"1" (dest) : "memory");
-return dest;
-}
+extern char *strcpy(char *dest, const char *src);
 
 #define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char * dest,const char *src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-	"1:\tdecl %2\n\t"
-	"js 2f\n\t"
-	"lodsb\n\t"
-	"stosb\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n\t"
-	"rep\n\t"
-	"stosb\n"
-	"2:"
-	: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
-	:"0" (src),"1" (dest),"2" (count) : "memory");
-return dest;
-}
+extern char *strncpy(char *dest, const char *src, size_t count);
 
 #define __HAVE_ARCH_STRCAT
-static inline char * strcat(char * dest,const char * src)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-	"repne\n\t"
-	"scasb\n\t"
-	"decl %1\n"
-	"1:\tlodsb\n\t"
-	"stosb\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b"
-	: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
-	: "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
-return dest;
-}
+extern char *strcat(char *dest, const char *src);
 
 #define __HAVE_ARCH_STRNCAT
-static inline char * strncat(char * dest,const char * src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
-	"repne\n\t"
-	"scasb\n\t"
-	"decl %1\n\t"
-	"movl %8,%3\n"
-	"1:\tdecl %3\n\t"
-	"js 2f\n\t"
-	"lodsb\n\t"
-	"stosb\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n"
-	"2:\txorl %2,%2\n\t"
-	"stosb"
-	: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
-	: "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
-	: "memory");
-return dest;
-}
+extern char *strncat(char *dest, const char *src, size_t count);
 
 #define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
-{
-int d0, d1;
-register int __res;
-__asm__ __volatile__(
-	"1:\tlodsb\n\t"
-	"scasb\n\t"
-	"jne 2f\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n\t"
-	"xorl %%eax,%%eax\n\t"
-	"jmp 3f\n"
-	"2:\tsbbl %%eax,%%eax\n\t"
-	"orb $1,%%al\n"
-	"3:"
-	:"=a" (__res), "=&S" (d0), "=&D" (d1)
-	:"1" (cs),"2" (ct)
-	:"memory");
-return __res;
-}
+extern int strcmp(const char *cs, const char *ct);
 
 #define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res;
-int d0, d1, d2;
-__asm__ __volatile__(
-	"1:\tdecl %3\n\t"
-	"js 2f\n\t"
-	"lodsb\n\t"
-	"scasb\n\t"
-	"jne 3f\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n"
-	"2:\txorl %%eax,%%eax\n\t"
-	"jmp 4f\n"
-	"3:\tsbbl %%eax,%%eax\n\t"
-	"orb $1,%%al\n"
-	"4:"
-	:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
-	:"1" (cs),"2" (ct),"3" (count)
-	:"memory");
-return __res;
-}
+extern int strncmp(const char *cs, const char *ct, size_t count);
 
 #define __HAVE_ARCH_STRCHR
-static inline char * strchr(const char * s, int c)
-{
-int d0;
-register char * __res;
-__asm__ __volatile__(
-	"movb %%al,%%ah\n"
-	"1:\tlodsb\n\t"
-	"cmpb %%ah,%%al\n\t"
-	"je 2f\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n\t"
-	"movl $1,%1\n"
-	"2:\tmovl %1,%0\n\t"
-	"decl %0"
-	:"=a" (__res), "=&S" (d0)
-	:"1" (s),"0" (c)
-	:"memory");
-return __res;
-}
+extern char *strchr(const char *s, int c);
 
 #define __HAVE_ARCH_STRRCHR
-static inline char * strrchr(const char * s, int c)
-{
-int d0, d1;
-register char * __res;
-__asm__ __volatile__(
-	"movb %%al,%%ah\n"
-	"1:\tlodsb\n\t"
-	"cmpb %%ah,%%al\n\t"
-	"jne 2f\n\t"
-	"leal -1(%%esi),%0\n"
-	"2:\ttestb %%al,%%al\n\t"
-	"jne 1b"
-	:"=g" (__res), "=&S" (d0), "=&a" (d1)
-	:"0" (0),"1" (s),"2" (c)
-	:"memory");
-return __res;
-}
+extern char *strrchr(const char *s, int c);
 
 #define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
-	"repne\n\t"
-	"scasb\n\t"
-	"notl %0\n\t"
-	"decl %0"
-	:"=c" (__res), "=&D" (d0)
-	:"1" (s),"a" (0), "0" (0xffffffffu)
-	:"memory");
-return __res;
-}
+extern size_t strlen(const char *s);
 
 static __always_inline void * __memcpy(void * to, const void * from, size_t n)
 {
@@ -207,9 +39,7 @@
 	"rep ; movsl\n\t"
 	"movl %4,%%ecx\n\t"
 	"andl $3,%%ecx\n\t"
-#if 1	/* want to pay 2 byte penalty for a chance to skip microcoded rep? */
 	"jz 1f\n\t"
-#endif
 	"rep ; movsb\n\t"
 	"1:"
 	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
@@ -328,23 +158,7 @@
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-static inline void * memchr(const void * cs,int c,size_t count)
-{
-int d0;
-register void * __res;
-if (!count)
-	return NULL;
-__asm__ __volatile__(
-	"repne\n\t"
-	"scasb\n\t"
-	"je 1f\n\t"
-	"movl $1,%0\n"
-	"1:\tdecl %0"
-	:"=D" (__res), "=&c" (d0)
-	:"a" (c),"0" (cs),"1" (count)
-	:"memory");
-return __res;
-}
+extern void *memchr(const void * cs,int c,size_t count);
 
 static inline void * __memset_generic(void * s, char c,size_t count)
 {
@@ -386,29 +200,10 @@
 
 /* Added by Gertjan van Wingerde to make minix and sysv module work */
 #define __HAVE_ARCH_STRNLEN
-static inline size_t strnlen(const char * s, size_t count)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
-	"movl %2,%0\n\t"
-	"jmp 2f\n"
-	"1:\tcmpb $0,(%0)\n\t"
-	"je 3f\n\t"
-	"incl %0\n"
-	"2:\tdecl %1\n\t"
-	"cmpl $-1,%1\n\t"
-	"jne 1b\n"
-	"3:\tsubl %2,%0"
-	:"=a" (__res), "=&d" (d0)
-	:"c" (s),"1" (count)
-	:"memory");
-return __res;
-}
+extern size_t strnlen(const char * s, size_t count);
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
-
 extern char *strstr(const char *cs, const char *ct);
 
 /*
@@ -474,19 +269,7 @@
  * find the first occurrence of byte 'c', or 1 past the area if none
  */
 #define __HAVE_ARCH_MEMSCAN
-static inline void * memscan(void * addr, int c, size_t size)
-{
-	if (!size)
-		return addr;
-	__asm__("repnz; scasb\n\t"
-		"jnz 1f\n\t"
-		"dec %%edi\n"
-		"1:"
-		: "=D" (addr), "=c" (size)
-		: "0" (addr), "1" (size), "a" (c)
-		: "memory");
-	return addr;
-}
+extern void *memscan(void * addr, int c, size_t size);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index 51a713e..0db7e99 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -5,13 +5,11 @@
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-void setup_pit_timer(void);
 unsigned long long native_sched_clock(void);
 unsigned long native_calculate_cpu_khz(void);
 
 extern int timer_ack;
 extern int no_timer_check;
-extern int no_sync_cmos_clock;
 extern int recalibrate_cpu_khz(void);
 
 #ifndef CONFIG_PARAVIRT
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index fc525c5..a50fa67 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -160,7 +160,11 @@
 	native_flush_tlb_others(&mask, mm, va)
 #endif
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+					unsigned long end)
+{
+	flush_tlb_all();
+}
 
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 7fc512d..19b2daf 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -67,7 +67,7 @@
 	return first_cpu(mask);
 }
 
-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))
 
 /* sched_domains SD_NODE_INIT for NUMAQ machines */
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index e2aa5e0..d2a4f7b 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -581,7 +581,7 @@
  * If there is a limit on the length of a valid string, you may wish to
  * consider using strnlen_user() instead.
  */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+#define strlen_user(str) strnlen_user(str, LONG_MAX)
 
 long strnlen_user(const char __user *str, long n);
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index c054d7a..efa1b8f 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -90,13 +90,27 @@
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)	isa_irq_to_vector_map[(x)]
 
+struct irq_cfg {
+	ia64_vector vector;
+	cpumask_t domain;
+};
+extern spinlock_t vector_lock;
+extern struct irq_cfg irq_cfg[NR_IRQS];
+#define irq_to_domain(x)	irq_cfg[(x)].domain
+DECLARE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq);
+
 extern struct hw_interrupt_type irq_type_ia64_lsapic;	/* CPU-internal interrupt controller */
 
+extern int bind_irq_vector(int irq, int vector, cpumask_t domain);
 extern int assign_irq_vector (int irq);	/* allocate a free vector */
 extern void free_irq_vector (int vector);
 extern int reserve_irq_vector (int vector);
+extern void __setup_vector_irq(int cpu);
+extern int reassign_irq_vector(int irq, int cpu);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
+extern int check_irq_used (int irq);
+extern void destroy_and_reserve_irq (unsigned int irq);
 
 static inline void ia64_resend_irq(unsigned int vector)
 {
@@ -113,7 +127,7 @@
 static inline unsigned int
 __ia64_local_vector_to_irq (ia64_vector vec)
 {
-	return (unsigned int) vec;
+	return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
@@ -131,7 +145,7 @@
 static inline ia64_vector
 irq_to_vector (int irq)
 {
-	return (ia64_vector) irq;
+	return irq_cfg[irq].vector;
 }
 
 /*
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 421cb6b..b8f7128 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -47,19 +47,21 @@
 #define	IOSAPIC_MASK_SHIFT		16
 #define	IOSAPIC_MASK			(1<<IOSAPIC_MASK_SHIFT)
 
+#define IOSAPIC_VECTOR_MASK		0xffffff00
+
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_IOSAPIC
 
 #define NR_IOSAPICS			256
 
-static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg)
 {
 	writel(reg, iosapic + IOSAPIC_REG_SELECT);
 	return readl(iosapic + IOSAPIC_WINDOW);
 }
 
-static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
 {
 	writel(reg, iosapic + IOSAPIC_REG_SELECT);
 	writel(val, iosapic + IOSAPIC_WINDOW);
diff --git a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h
index 6722161..35b360b 100644
--- a/include/asm-ia64/irq.h
+++ b/include/asm-ia64/irq.h
@@ -14,8 +14,13 @@
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
-#define NR_IRQS		256
-#define NR_IRQ_VECTORS	NR_IRQS
+#define NR_VECTORS	256
+
+#if (NR_VECTORS + 32 * NR_CPUS) < 1024
+#define NR_IRQS (NR_VECTORS + 32 * NR_CPUS)
+#else
+#define NR_IRQS 1024
+#endif
 
 static __inline__ int
 irq_canonicalize (int irq)
diff --git a/include/asm-ia64/rwsem.h b/include/asm-ia64/rwsem.h
index 2d1640c..8aba06a 100644
--- a/include/asm-ia64/rwsem.h
+++ b/include/asm-ia64/rwsem.h
@@ -21,6 +21,10 @@
 #ifndef _ASM_IA64_RWSEM_H
 #define _ASM_IA64_RWSEM_H
 
+#ifndef _LINUX_RWSEM_H
+#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
+#endif
+
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 441c9e0..315f8de 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -292,7 +292,7 @@
 #define __NR_sync_file_range		1300
 #define __NR_tee			1301
 #define __NR_vmsplice			1302
-/* 1303 reserved for move_pages */
+#define __NR_fallocate			1303
 #define __NR_getcpu			1304
 #define __NR_epoll_pwait		1305
 #define __NR_utimensat			1306
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
index 5e0fcf4..47bb9cf 100644
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -27,6 +27,7 @@
 #include <asm/raw_io.h>
 #include <asm/virtconvert.h>
 
+#include <asm-generic/iomap.h>
 
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
@@ -152,6 +153,16 @@
     default: return NULL; /* avoid warnings, just in case */
     }
 }
+static inline u32 __iomem *isa_itl(unsigned long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
 static inline u8 __iomem *isa_mtb(unsigned long addr)
 {
   switch(ISA_TYPE)
@@ -188,8 +199,10 @@
 
 #define isa_inb(port)      in_8(isa_itb(port))
 #define isa_inw(port)      (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
+#define isa_inl(port)      (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port)))
 #define isa_outb(val,port) out_8(isa_itb(port),(val))
 #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
+#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val)))
 
 #define isa_readb(p)       in_8(isa_mtb((unsigned long)(p)))
 #define isa_readw(p)       \
@@ -234,6 +247,15 @@
 #define isa_outsw(port, buf, nr)    \
        (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) :  \
                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
+#define isa_insl(port, buf, nr)     \
+       (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) :    \
+                  raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
+#define isa_outsl(port, buf, nr)    \
+       (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) :  \
+                  raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
 #endif  /* CONFIG_ISA */
 
 
@@ -246,14 +268,16 @@
 #define inw_p   isa_inw_p
 #define outw    isa_outw
 #define outw_p  isa_outw_p
-#define inl     isa_inw
-#define inl_p   isa_inw_p
-#define outl    isa_outw
-#define outl_p  isa_outw_p
+#define inl     isa_inl
+#define inl_p   isa_inl_p
+#define outl    isa_outl
+#define outl_p  isa_outl_p
 #define insb    isa_insb
 #define insw    isa_insw
+#define insl    isa_insl
 #define outsb   isa_outsb
 #define outsw   isa_outsw
+#define outsl   isa_outsl
 #define readb   isa_readb
 #define readw   isa_readw
 #define writeb  isa_writeb
@@ -262,8 +286,6 @@
 
 #if defined(CONFIG_PCI)
 
-#define inl(port)        in_le32(port)
-#define outl(val,port)   out_le32((port),(val))
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 
@@ -282,6 +304,8 @@
 #define outb(val,port) out_8((port),(val))
 #define inw(port)      in_le16(port)
 #define outw(val,port) out_le16((port),(val))
+#define inl(port)      in_le32(port)
+#define outl(val,port) out_le32((port),(val))
 
 #else
 /*
@@ -306,20 +330,35 @@
 #endif
 #endif /* CONFIG_PCI */
 
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
+#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 /*
- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+ * We need to define dummy functions for GENERIC_IOMAP support.
  */
-#define inb(port)        0xff
-#define inb_p(port)      0xff
-#define outb(val,port)   do { } while (0)
-#define outb_p(val,port) do { } while (0)
+#define inb(port)          0xff
+#define inb_p(port)        0xff
+#define outb(val,port)     ((void)0)
+#define outb_p(val,port)   ((void)0)
+#define inw(port)          0xffff
+#define outw(val,port)     ((void)0)
+#define inl(port)          0xffffffffUL
+#define outl(val,port)     ((void)0)
+
+#define insb(port,buf,nr)  ((void)0)
+#define outsb(port,buf,nr) ((void)0)
+#define insw(port,buf,nr)  ((void)0)
+#define outsw(port,buf,nr) ((void)0)
+#define insl(port,buf,nr)  ((void)0)
+#define outsl(port,buf,nr) ((void)0)
 
 /*
  * These should be valid on any ioremap()ed region
  */
 #define readb(addr)      in_8(addr)
 #define writeb(val,addr) out_8((addr),(val))
+#define readw(addr)      in_le16(addr)
+#define writew(val,addr) out_le16((addr),(val))
+#endif
+#if !defined(CONFIG_PCI)
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 #endif
@@ -351,6 +390,18 @@
 extern void dma_cache_wback(unsigned long start, unsigned long size);
 extern void dma_cache_inv(unsigned long start, unsigned long size);
 
+static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+	__builtin_memset((void __force *) addr, val, count);
+}
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
+{
+	__builtin_memcpy(dst, (void __force *) src, count);
+}
+static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+	__builtin_memcpy((void __force *) dst, src, count);
+}
 
 #ifndef CONFIG_SUN3
 #define IO_SPACE_LIMIT 0xffff
diff --git a/include/asm-m68k/raw_io.h b/include/asm-m68k/raw_io.h
index 811ccd2..91c623f 100644
--- a/include/asm-m68k/raw_io.h
+++ b/include/asm-m68k/raw_io.h
@@ -49,10 +49,16 @@
 #define raw_inb in_8
 #define raw_inw in_be16
 #define raw_inl in_be32
+#define __raw_readb in_8
+#define __raw_readw in_be16
+#define __raw_readl in_be32
 
 #define raw_outb(val,port) out_8((port),(val))
 #define raw_outw(val,port) out_be16((port),(val))
 #define raw_outl(val,port) out_be32((port),(val))
+#define __raw_writeb(val,addr) out_8((addr),(val))
+#define __raw_writew(val,addr) out_be16((addr),(val))
+#define __raw_writel(val,addr) out_be32((addr),(val))
 
 static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
 {
@@ -336,8 +342,6 @@
 		: "d0", "a0", "a1", "d6");
 }
 
-#define __raw_writel raw_outl
-
 #endif /* __KERNEL__ */
 
 #endif /* _RAW_IO_H */
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 1b60624..7d80037 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -138,7 +138,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -181,7 +181,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -190,7 +190,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -233,7 +233,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -250,7 +250,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -302,7 +302,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -519,7 +519,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -562,7 +562,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -571,7 +571,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -614,7 +614,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -631,7 +631,7 @@
 {
 	unsigned long result;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (cpu_has_llsc && R10000_LLSC_WAR) {
 		unsigned long temp;
@@ -683,7 +683,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return result;
 }
@@ -791,10 +791,11 @@
  * atomic*_return operations are serializing but not the non-*_return
  * versions.
  */
-#define smp_mb__before_atomic_dec()	smp_mb()
-#define smp_mb__after_atomic_dec()	smp_mb()
-#define smp_mb__before_atomic_inc()	smp_mb()
-#define smp_mb__after_atomic_inc()	smp_mb()
+#define smp_mb__before_atomic_dec()	smp_llsc_mb()
+#define smp_mb__after_atomic_dec()	smp_llsc_mb()
+#define smp_mb__before_atomic_inc()	smp_llsc_mb()
+#define smp_mb__after_atomic_inc()	smp_llsc_mb()
 
 #include <asm-generic/atomic.h>
+
 #endif /* _ASM_ATOMIC_H */
diff --git a/include/asm-mips/barrier.h b/include/asm-mips/barrier.h
index ed82631..9d8cfbb 100644
--- a/include/asm-mips/barrier.h
+++ b/include/asm-mips/barrier.h
@@ -121,6 +121,11 @@
 #else
 #define __WEAK_ORDERING_MB	"		\n"
 #endif
+#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
+#define __WEAK_LLSC_MB		"       sync	\n"
+#else
+#define __WEAK_LLSC_MB		"		\n"
+#endif
 
 #define smp_mb()	__asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
 #define smp_rmb()	__asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
@@ -129,4 +134,8 @@
 #define set_mb(var, value) \
 	do { var = value; smp_mb(); } while (0)
 
+#define smp_llsc_mb()	__asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_rmb()	__asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_wmb()	__asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+
 #endif /* __ASM_BARRIER_H */
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index d9e81af..148bc79 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -38,8 +38,8 @@
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
-#define smp_mb__before_clear_bit()	smp_mb()
-#define smp_mb__after_clear_bit()	smp_mb()
+#define smp_mb__before_clear_bit()	smp_llsc_mb()
+#define smp_mb__after_clear_bit()	smp_llsc_mb()
 
 /*
  * set_bit - Atomically set a bit in memory
@@ -289,7 +289,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return res != 0;
 }
@@ -377,7 +377,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return res != 0;
 }
@@ -445,7 +445,7 @@
 		raw_local_irq_restore(flags);
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return res != 0;
 }
diff --git a/include/asm-mips/ds1216.h b/include/asm-mips/ds1216.h
deleted file mode 100644
index 1ff8b73..0000000
--- a/include/asm-mips/ds1216.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _DS1216_H
-#define _DS1216_H
-
-extern volatile unsigned char *ds1216_base;
-unsigned long ds1216_get_cmos_time(void);
-int ds1216_set_rtc_mmss(unsigned long nowtime);
-
-#define DS1216_SEC_BYTE		1
-#define DS1216_MIN_BYTE		2
-#define DS1216_HOUR_BYTE	3
-#define DS1216_HOUR_MASK	(0x1f)
-#define DS1216_AMPM_MASK	(1<<5)
-#define DS1216_1224_MASK	(1<<7)
-#define DS1216_DAY_BYTE		4
-#define DS1216_DAY_MASK		(0x7)
-#define DS1216_DATE_BYTE	5
-#define DS1216_DATE_MASK	(0x3f)
-#define DS1216_MONTH_BYTE	6
-#define DS1216_MONTH_MASK	(0x1f)
-#define DS1216_YEAR_BYTE	7
-
-#define DS1216_SEC(buf)		(buf[DS1216_SEC_BYTE])
-#define DS1216_MIN(buf)		(buf[DS1216_MIN_BYTE])
-#define DS1216_HOUR(buf)	(buf[DS1216_HOUR_BYTE] & DS1216_HOUR_MASK)
-#define DS1216_AMPM(buf)	(buf[DS1216_HOUR_BYTE] & DS1216_AMPM_MASK)
-#define DS1216_1224(buf)	(buf[DS1216_HOUR_BYTE] & DS1216_1224_MASK)
-#define DS1216_DATE(buf)	(buf[DS1216_DATE_BYTE] & DS1216_DATE_MASK)
-#define DS1216_MONTH(buf)	(buf[DS1216_MONTH_BYTE] & DS1216_MONTH_MASK)
-#define DS1216_YEAR(buf)	(buf[DS1216_YEAR_BYTE])
-
-#endif
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
index 47e5679..b623882 100644
--- a/include/asm-mips/futex.h
+++ b/include/asm-mips/futex.h
@@ -29,7 +29,7 @@
 		"	.set	mips3				\n"	\
 		"2:	sc	$1, %2				\n"	\
 		"	beqzl	$1, 1b				\n"	\
-		__WEAK_ORDERING_MB					\
+		__WEAK_LLSC_MB						\
 		"3:						\n"	\
 		"	.set	pop				\n"	\
 		"	.set	mips0				\n"	\
@@ -55,7 +55,7 @@
 		"	.set	mips3				\n"	\
 		"2:	sc	$1, %2				\n"	\
 		"	beqz	$1, 1b				\n"	\
-		__WEAK_ORDERING_MB					\
+		__WEAK_LLSC_MB						\
 		"3:						\n"	\
 		"	.set	pop				\n"	\
 		"	.set	mips0				\n"	\
@@ -152,7 +152,7 @@
 		"	.set	mips3					\n"
 		"2:	sc	$1, %1					\n"
 		"	beqzl	$1, 1b					\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"3:							\n"
 		"	.set	pop					\n"
 		"	.section .fixup,\"ax\"				\n"
@@ -179,7 +179,7 @@
 		"	.set	mips3					\n"
 		"2:	sc	$1, %1					\n"
 		"	beqz	$1, 1b					\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"3:							\n"
 		"	.set	pop					\n"
 		"	.section .fixup,\"ax\"				\n"
diff --git a/include/asm-mips/gfx.h b/include/asm-mips/gfx.h
deleted file mode 100644
index 37235e4..0000000
--- a/include/asm-mips/gfx.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * This is the user-visible SGI GFX interface.
- *
- * This must be used verbatim into the GNU libc.  It does not include
- * any kernel-only bits on it.
- *
- * miguel@nuclecu.unam.mx
- */
-#ifndef _ASM_GFX_H
-#define _ASM_GFX_H
-
-/* The iocls, yes, they do not make sense, but such is life */
-#define GFX_BASE             100
-#define GFX_GETNUM_BOARDS    (GFX_BASE + 1)
-#define GFX_GETBOARD_INFO    (GFX_BASE + 2)
-#define GFX_ATTACH_BOARD     (GFX_BASE + 3)
-#define GFX_DETACH_BOARD     (GFX_BASE + 4)
-#define GFX_IS_MANAGED       (GFX_BASE + 5)
-
-#define GFX_MAPALL           (GFX_BASE + 10)
-#define GFX_LABEL            (GFX_BASE + 11)
-
-#define GFX_INFO_NAME_SIZE  16
-#define GFX_INFO_LABEL_SIZE 16
-
-struct gfx_info {
-	char name  [GFX_INFO_NAME_SIZE];  /* board name */
-	char label [GFX_INFO_LABEL_SIZE]; /* label name */
-	unsigned short int xpmax, ypmax;  /* screen resolution */
-	unsigned int lenght;	          /* size of a complete gfx_info for this board */
-};
-
-struct gfx_getboardinfo_args {
-	unsigned int board;     /* board number.  starting from zero */
-	void *buf;              /* pointer to gfx_info */
-	unsigned int len;       /* buffer size of buf */
-};
-
-struct gfx_attach_board_args {
-	unsigned int board;	/* board number, starting from zero */
-	void        *vaddr;	/* address where the board registers should be mapped */
-};
-
-#ifdef __KERNEL__
-/* umap.c */
-extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
-extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
-#endif
-
-#endif /* _ASM_GFX_H */
diff --git a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
index c6dfa59d..d38f069 100644
--- a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
 #define __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
@@ -46,6 +46,8 @@
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_icache_snoops_remote_store	0
 #define cpu_has_dsp		0
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 #define cpu_has_mips32r1	0
 #define cpu_has_mips32r2	0
diff --git a/include/asm-mips/mach-excite/cpu-feature-overrides.h b/include/asm-mips/mach-excite/cpu-feature-overrides.h
index 0d31854..07f4322 100644
--- a/include/asm-mips/mach-excite/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-excite/cpu-feature-overrides.h
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2004 Thomas Koeller <thomas.koeller@baslerweb.com>
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +28,8 @@
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_has_dsp		0
 #define cpu_icache_snoops_remote_store	0
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 #define cpu_has_nofpuex		0
 #define cpu_has_64bits		1
diff --git a/include/asm-mips/mach-ip22/cpu-feature-overrides.h b/include/asm-mips/mach-ip22/cpu-feature-overrides.h
index f7c5dc8..9c87351 100644
--- a/include/asm-mips/mach-ip22/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip22/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
@@ -30,6 +30,8 @@
 #define cpu_has_ic_fills_f_dc	0
 
 #define cpu_has_dsp		0
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 #define cpu_has_nofpuex		0
 #define cpu_has_64bits		1
diff --git a/include/asm-mips/mach-ip27/cpu-feature-overrides.h b/include/asm-mips/mach-ip27/cpu-feature-overrides.h
index a071974..fe07638 100644
--- a/include/asm-mips/mach-ip27/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip27/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +27,8 @@
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_has_dsp		0
 #define cpu_icache_snoops_remote_store	1
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 #define cpu_has_nofpuex		0
 #define cpu_has_64bits		1
diff --git a/include/asm-mips/mach-ip32/cpu-feature-overrides.h b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
index 2a3de09..6782fcc 100644
--- a/include/asm-mips/mach-ip32/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2005 Ilya A. Volynets-Evenbakh
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2005, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
@@ -38,6 +38,8 @@
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_has_dsp		0
 #define cpu_has_4k_cache	1
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 
 #define cpu_has_mips32r1	0
diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
index 529445d..d2daaed 100644
--- a/include/asm-mips/mach-qemu/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
@@ -24,6 +24,7 @@
 #define cpu_has_ic_fills_f_dc	0
 
 #define cpu_has_dsp		0
+#define cpu_has_mipsmt		0
 
 #define cpu_has_nofpuex		0
 #define cpu_has_64bits		0
diff --git a/include/asm-mips/mach-rm/cpu-feature-overrides.h b/include/asm-mips/mach-rm/cpu-feature-overrides.h
index 7e07283..ccf5433 100644
--- a/include/asm-mips/mach-rm/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-rm/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  *
  * SNI RM200 C apparently was only shipped with R4600 V2.0 and R5000 processors.
  */
@@ -32,6 +32,8 @@
 #define cpu_has_dsp		0
 #define cpu_has_nofpuex		0
 #define cpu_has_64bits		1
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 
 #define cpu_has_mips32r1	0
 #define cpu_has_mips32r2	0
diff --git a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
index a25968f..63d5bf6 100644
--- a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases	0
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_has_dsp		0
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 #define cpu_icache_snoops_remote_store	0
 
 #define cpu_has_nofpuex		0
diff --git a/include/asm-mips/mach-yosemite/cpu-feature-overrides.h b/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
index 42cebb7..470e5e9 100644
--- a/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases	0
 #define cpu_has_ic_fills_f_dc	0
 #define cpu_has_dsp		0
+#define cpu_has_mipsmt		0
+#define cpu_has_userlocal	0
 #define cpu_icache_snoops_remote_store	0
 
 #define cpu_has_nofpuex		0
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
index 35e431c..bb89701 100644
--- a/include/asm-mips/spinlock.h
+++ b/include/asm-mips/spinlock.h
@@ -67,7 +67,7 @@
 		: "memory");
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
@@ -118,7 +118,7 @@
 		: "memory");
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return res == 0;
 }
@@ -183,7 +183,7 @@
 		: "memory");
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 }
 
 /* Note the use of sub, not subu which will make the kernel die with an
@@ -193,7 +193,7 @@
 {
 	unsigned int tmp;
 
-	smp_mb();
+	smp_llsc_mb();
 
 	if (R10000_LLSC_WAR) {
 		__asm__ __volatile__(
@@ -262,7 +262,7 @@
 		: "memory");
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
@@ -293,7 +293,7 @@
 		"	.set	reorder					\n"
 		"	beqzl	%1, 1b					\n"
 		"	 nop						\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"	li	%2, 1					\n"
 		"2:							\n"
 		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -310,7 +310,7 @@
 		"	beqz	%1, 1b					\n"
 		"	 nop						\n"
 		"	.set	reorder					\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"	li	%2, 1					\n"
 		"2:							\n"
 		: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -336,7 +336,7 @@
 		"	sc	%1, %0					\n"
 		"	beqzl	%1, 1b					\n"
 		"	 nop						\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"	li	%2, 1					\n"
 		"	.set	reorder					\n"
 		"2:							\n"
@@ -354,7 +354,7 @@
 		"	beqz	%1, 3f					\n"
 		"	 li	%2, 1					\n"
 		"2:							\n"
-		__WEAK_ORDERING_MB
+		__WEAK_LLSC_MB
 		"	.subsection 2					\n"
 		"3:	b	1b					\n"
 		"	 li	%2, 0					\n"
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 7633916..8d0b1cd 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -117,7 +117,7 @@
 		raw_local_irq_restore(flags);	/* implies memory barrier  */
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return retval;
 }
@@ -165,7 +165,7 @@
 		raw_local_irq_restore(flags);	/* implies memory barrier  */
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return retval;
 }
@@ -246,7 +246,7 @@
 		raw_local_irq_restore(flags);	/* implies memory barrier  */
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return retval;
 }
@@ -352,7 +352,7 @@
 		raw_local_irq_restore(flags);	/* implies memory barrier  */
 	}
 
-	smp_mb();
+	smp_llsc_mb();
 
 	return retval;
 }
@@ -470,6 +470,6 @@
  */
 #define __ARCH_WANT_UNLOCKED_CTXSW
 
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
 
 #endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 2ffb06a..262db6b 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -296,6 +296,9 @@
 	unsigned int		dcr_base;
 #endif
 
+	/* Protected sources */
+	unsigned long		*protected;
+
 #ifdef CONFIG_MPIC_WEIRD
 	/* Pointer to HW info array */
 	u32			*hw_set;
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index e9af49e..ec2a8a2 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -3,14 +3,12 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
-#include <linux/mod_devicetable.h>
-#include <asm/prom.h>
-
+#include <linux/of.h>
 
 /*
  * The of_device is a kind of "base class" that is a superset of
  * struct device for use by devices attached to an OF node and
- * probed using OF properties
+ * probed using OF properties.
  */
 struct of_device
 {
@@ -18,24 +16,14 @@
 	u64			dma_mask;	/* DMA mask */
 	struct device		dev;		/* Generic device interface */
 };
-#define	to_of_device(d) container_of(d, struct of_device, dev)
-
-extern const struct of_device_id *of_match_node(
-	const struct of_device_id *matches, const struct device_node *node);
-extern const struct of_device_id *of_match_device(
-	const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern void of_release_dev(struct device *dev);
 
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
 					char *str, ssize_t len);
 extern int of_device_uevent(struct device *dev,
 	char **envp, int num_envp, char *buffer, int buffer_size);
 
+/* This is just here during the transition */
+#include <linux/of_device.h>
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/of_platform.h b/include/asm-powerpc/of_platform.h
index 217eafb..80e6fad 100644
--- a/include/asm-powerpc/of_platform.h
+++ b/include/asm-powerpc/of_platform.h
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_OF_PLATFORM_H
+#define _ASM_POWERPC_OF_PLATFORM_H
 /*
  *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
  *			 <benh@kernel.crashing.org>
@@ -9,37 +11,8 @@
  *
  */
 
-#include <asm/of_device.h>
-
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
-	char			*name;
-	struct of_device_id	*match_table;
-	struct module		*owner;
-
-	int	(*probe)(struct of_device* dev,
-			 const struct of_device_id *match);
-	int	(*remove)(struct of_device* dev);
-
-	int	(*suspend)(struct of_device* dev, pm_message_t state);
-	int	(*resume)(struct of_device* dev);
-	int	(*shutdown)(struct of_device* dev);
-
-	struct device_driver	driver;
-};
-#define	to_of_platform_driver(drv) \
-	container_of(drv,struct of_platform_driver, driver)
+/* This is just here during the transition */
+#include <linux/of_platform.h>
 
 /* Platform drivers register/unregister */
 extern int of_register_platform_driver(struct of_platform_driver *drv);
@@ -56,5 +29,6 @@
 				 struct of_device_id *matches,
 				 struct device *parent);
 
-extern struct of_device *of_find_device_by_node(struct device_node *np);
 extern struct of_device *of_find_device_by_phandle(phandle ph);
+
+#endif	/* _ASM_POWERPC_OF_PLATFORM_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 8d6b47f..938fefb 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -39,14 +39,16 @@
 
 /* Per-arch configuration */
 struct op_powerpc_model {
-	void (*reg_setup) (struct op_counter_config *,
+	int (*reg_setup) (struct op_counter_config *,
 			   struct op_system_config *,
 			   int num_counters);
-	void (*cpu_setup) (struct op_counter_config *);
-	void (*start) (struct op_counter_config *);
-        void (*global_start) (struct op_counter_config *);
+	int  (*cpu_setup) (struct op_counter_config *);
+	int  (*start) (struct op_counter_config *);
+	int  (*global_start) (struct op_counter_config *);
 	void (*stop) (void);
 	void (*global_stop) (void);
+	int (*sync_start)(void);
+	int (*sync_stop)(void);
 	void (*handle_interrupt) (struct pt_regs *,
 				  struct op_counter_config *);
 	int num_counters;
diff --git a/include/asm-powerpc/pmi.h b/include/asm-powerpc/pmi.h
index cb0f8aa..2259d4c 100644
--- a/include/asm-powerpc/pmi.h
+++ b/include/asm-powerpc/pmi.h
@@ -55,13 +55,13 @@
 struct pmi_handler {
 	struct list_head node;
 	u8 type;
-	void (*handle_pmi_message) (struct of_device *, pmi_message_t);
+	void (*handle_pmi_message) (pmi_message_t);
 };
 
-void pmi_register_handler(struct of_device *, struct pmi_handler *);
-void pmi_unregister_handler(struct of_device *, struct pmi_handler *);
+int pmi_register_handler(struct pmi_handler *);
+void pmi_unregister_handler(struct pmi_handler *);
 
-void pmi_send_message(struct of_device *, pmi_message_t);
+int pmi_send_message(pmi_message_t);
 
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PMI_H */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 1632baa..6720837 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -21,6 +21,13 @@
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT	1
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT	1
+
+#define of_compat_cmp(s1, s2, l)	strncasecmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)		strcmp((s1), (s2))
+#define of_node_cmp(s1, s2)		strcasecmp((s1), (s2))
+
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER		0xd00dfeed	/* marker */
 #define OF_DT_BEGIN_NODE	0x1		/* Start of node, full name */
@@ -97,10 +104,6 @@
 
 extern struct device_node *of_chosen;
 
-/* flag descriptions */
-#define OF_DYNAMIC	1 /* node and properties were allocated via kmalloc */
-#define OF_DETACHED	2 /* node has been detached from the device tree */
-
 static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
 {
 	return test_bit(flag, &n->_flags);
@@ -120,31 +123,7 @@
 }
 
 
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name);
-#define for_each_node_by_name(dn, name) \
-	for (dn = of_find_node_by_name(NULL, name); dn; \
-	     dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type);
-#define for_each_node_by_type(dn, type) \
-	for (dn = of_find_node_by_type(NULL, type); dn; \
-	     dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compat);
-#define for_each_compatible_node(dn, type, compatible) \
-	for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
-	     dn = of_find_compatible_node(dn, type, compatible))
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-					     struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-					 const char *name,
-					 int *lenp);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 
@@ -160,23 +139,15 @@
 
 /* For updating the device tree at runtime */
 extern void of_attach_node(struct device_node *);
-extern void of_detach_node(const struct device_node *);
+extern void of_detach_node(struct device_node *);
 
 /* Other Prototypes */
 extern void finish_device_tree(void);
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
-extern int of_device_is_compatible(const struct device_node *device,
-				const char *);
 #define device_is_compatible(d, c)	of_device_is_compatible((d), (c))
 extern int machine_is_compatible(const char *compat);
-extern const void *of_get_property(const struct device_node *node,
-				const char *name,
-				int *lenp);
-#define get_property(a, b, c)	of_get_property((a), (b), (c))
 extern void print_properties(struct device_node *node);
-extern int of_n_addr_cells(struct device_node* np);
-extern int of_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -230,7 +201,6 @@
 
 /* Translate an OF address block into a CPU physical address
  */
-#define OF_BAD_ADDR	((u64)-1)
 extern u64 of_translate_address(struct device_node *np, const u32 *addr);
 
 /* Extract an address from a device, returns the region size and
@@ -357,5 +327,11 @@
  */
 extern void __iomem *of_iomap(struct device_node *device, int index);
 
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index eedc828..8836c0f 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -107,10 +107,10 @@
 struct device_node;
 
 enum spu_utilization_state {
-	SPU_UTIL_SYSTEM,
 	SPU_UTIL_USER,
+	SPU_UTIL_SYSTEM,
 	SPU_UTIL_IOWAIT,
-	SPU_UTIL_IDLE,
+	SPU_UTIL_IDLE_LOADED,
 	SPU_UTIL_MAX
 };
 
@@ -121,9 +121,9 @@
 	unsigned long problem_phys;
 	struct spu_problem __iomem *problem;
 	struct spu_priv2 __iomem *priv2;
-	struct list_head list;
-	struct list_head sched_list;
+	struct list_head cbe_list;
 	struct list_head full_list;
+	enum { SPU_FREE, SPU_USED } alloc_state;
 	int number;
 	unsigned int irqs[3];
 	u32 node;
@@ -137,6 +137,7 @@
 	struct spu_runqueue *rq;
 	unsigned long long timestamp;
 	pid_t pid;
+	pid_t tgid;
 	int class_0_pending;
 	spinlock_t register_lock;
 
@@ -165,11 +166,14 @@
 
 	struct sys_device sysdev;
 
+	int has_mem_affinity;
+	struct list_head aff_list;
+
 	struct {
 		/* protected by interrupt reentrancy */
-		enum spu_utilization_state utilization_state;
-		unsigned long tstamp;		/* time of last ctx switch */
-		unsigned long times[SPU_UTIL_MAX];
+		enum spu_utilization_state util_state;
+		unsigned long long tstamp;
+		unsigned long long times[SPU_UTIL_MAX];
 		unsigned long long vol_ctx_switch;
 		unsigned long long invol_ctx_switch;
 		unsigned long long min_flt;
@@ -181,13 +185,29 @@
 	} stats;
 };
 
-struct spu *spu_alloc(void);
-struct spu *spu_alloc_node(int node);
-void spu_free(struct spu *spu);
+struct cbe_spu_info {
+	struct mutex list_mutex;
+	struct list_head spus;
+	int n_spus;
+	int nr_active;
+	atomic_t reserved_spus;
+};
+
+extern struct cbe_spu_info cbe_spu_info[];
+
+void spu_init_channels(struct spu *spu);
 int spu_irq_class_0_bottom(struct spu *spu);
 int spu_irq_class_1_bottom(struct spu *spu);
 void spu_irq_setaffinity(struct spu *spu, int cpu);
 
+#ifdef CONFIG_KEXEC
+void crash_register_spus(struct list_head *list);
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
 extern void spu_invalidate_slbs(struct spu *spu);
 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 
@@ -195,6 +215,20 @@
 struct mm_struct;
 extern void spu_flush_all_slbs(struct mm_struct *mm);
 
+/* This interface allows a profiler (e.g., OProfile) to store a ref
+ * to spu context information that it creates.	This caching technique
+ * avoids the need to recreate this information after a save/restore operation.
+ *
+ * Assumes the caller has already incremented the ref count to
+ * profile_info; then spu_context_destroy must call kref_put
+ * on prof_info_kref.
+ */
+void spu_set_profile_private_kref(struct spu_context *ctx,
+				  struct kref *prof_info_kref,
+				  void ( * prof_info_release) (struct kref *kref));
+
+void *spu_get_profile_private_kref(struct spu_context *ctx);
+
 /* system callbacks from the SPU */
 struct spu_syscall_block {
 	u64 nr_ret;
@@ -206,7 +240,8 @@
 struct file;
 extern struct spufs_calls {
 	asmlinkage long (*create_thread)(const char __user *name,
-					unsigned int flags, mode_t mode);
+					unsigned int flags, mode_t mode,
+					struct file *neighbor);
 	asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
 						__u32 __user *ustatus);
 	struct module *owner;
@@ -233,8 +268,10 @@
 #define SPU_CREATE_GANG			0x0002
 #define SPU_CREATE_NOSCHED		0x0004
 #define SPU_CREATE_ISOLATE		0x0008
+#define SPU_CREATE_AFFINITY_SPU		0x0010
+#define SPU_CREATE_AFFINITY_MEM		0x0020
 
-#define SPU_CREATE_FLAG_ALL		0x000f /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL		0x003f /* mask of all valid flags */
 
 
 #ifdef CONFIG_SPU_FS_MODULE
@@ -403,6 +440,7 @@
 #define MFC_CNTL_RESUME_DMA_QUEUE		(0ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE		(1ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK		(1ull << 0)
+#define MFC_CNTL_SUSPEND_MASK			(1ull << 4)
 #define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION	(0ull << 8)
 #define MFC_CNTL_SUSPEND_IN_PROGRESS		(1ull << 8)
 #define MFC_CNTL_SUSPEND_COMPLETE		(3ull << 8)
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index c48ae18..e87794d 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -50,6 +50,12 @@
 #define SPU_STOPPED_STATUS_P_I  8
 #define SPU_STOPPED_STATUS_R    9
 
+/*
+ * Definitions for software decrementer status flag.
+ */
+#define SPU_DECR_STATUS_RUNNING 0x1
+#define SPU_DECR_STATUS_WRAPPED 0x2
+
 #ifndef  __ASSEMBLY__
 /**
  * spu_reg128 - generic 128-bit register definition.
@@ -63,7 +69,7 @@
  * @gprs: Array of saved registers.
  * @fpcr: Saved floating point status control register.
  * @decr: Saved decrementer value.
- * @decr_status: Indicates decrementer run status.
+ * @decr_status: Indicates software decrementer status flags.
  * @ppu_mb: Saved PPU mailbox data.
  * @ppuint_mb: Saved PPU interrupting mailbox data.
  * @tag_mask: Saved tag group mask.
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index f1311a8..cc45780 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -54,6 +54,7 @@
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
+extern int set_dabr(unsigned long dabr);
 #ifdef CONFIG_6xx
 extern long _get_L2CR(void);
 extern long _get_L3CR(void);
diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h
index 386d797..b550a27 100644
--- a/include/asm-sh/clock.h
+++ b/include/asm-sh/clock.h
@@ -14,6 +14,7 @@
 	void (*disable)(struct clk *clk);
 	void (*recalc)(struct clk *clk);
 	int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+	long (*round_rate)(struct clk *clk, unsigned long rate);
 };
 
 struct clk {
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
index 4ca3f76..20d4295 100644
--- a/include/asm-sh/hw_irq.h
+++ b/include/asm-sh/hw_irq.h
@@ -1,6 +1,7 @@
 #ifndef __ASM_SH_HW_IRQ_H
 #define __ASM_SH_HW_IRQ_H
 
+#include <linux/init.h>
 #include <asm/atomic.h>
 
 extern atomic_t irq_err_count;
@@ -22,7 +23,6 @@
 };
 
 void register_intc2_controller(struct intc2_desc *);
-void init_IRQ_intc2(void);
 
 struct ipr_data {
 	unsigned char irq;
@@ -40,11 +40,82 @@
 };
 
 void register_ipr_controller(struct ipr_desc *);
-void init_IRQ_ipr(void);
 
 /*
  * Enable individual interrupt mode for external IPR IRQs.
  */
-void ipr_irq_enable_irlm(void);
+void __init ipr_irq_enable_irlm(void);
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+	intc_enum enum_id;
+	unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_prio {
+	intc_enum enum_id;
+	unsigned char priority;
+};
+
+#define INTC_PRIO(enum_id, prio) { enum_id, prio }
+
+struct intc_group {
+	intc_enum enum_id;
+	intc_enum *enum_ids;
+};
+
+#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+
+struct intc_mask_reg {
+	unsigned long set_reg, clr_reg, reg_width;
+	intc_enum enum_ids[32];
+};
+
+struct intc_prio_reg {
+	unsigned long reg, reg_width, field_width;
+	intc_enum enum_ids[16];
+};
+
+struct intc_sense_reg {
+	unsigned long reg, reg_width, field_width;
+	intc_enum enum_ids[16];
+};
+
+struct intc_desc {
+	struct intc_vect *vectors;
+	unsigned int nr_vectors;
+	struct intc_group *groups;
+	unsigned int nr_groups;
+	struct intc_prio *priorities;
+	unsigned int nr_priorities;
+	struct intc_mask_reg *mask_regs;
+	unsigned int nr_mask_regs;
+	struct intc_prio_reg *prio_regs;
+	unsigned int nr_prio_regs;
+	struct intc_sense_reg *sense_regs;
+	unsigned int nr_sense_regs;
+	struct irq_chip chip;
+};
+
+#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups,		\
+	priorities, mask_regs, prio_regs, sense_regs)			\
+struct intc_desc symbol = {						\
+	_INTC_ARRAY(vectors), _INTC_ARRAY(groups),			\
+	_INTC_ARRAY(priorities),					\
+	_INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs),			\
+	_INTC_ARRAY(sense_regs),					\
+	.chip.name = chipname,						\
+}
+
+void __init register_intc_controller(struct intc_desc *desc);
+
+void __init plat_irq_setup(void);
+
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+void __init plat_irq_setup_pins(int mode);
 
 #endif /* __ASM_SH_HW_IRQ_H */
diff --git a/include/asm-sh/se7722.h b/include/asm-sh/se7722.h
index b3b31e4..e0e89fc 100644
--- a/include/asm-sh/se7722.h
+++ b/include/asm-sh/se7722.h
@@ -81,36 +81,32 @@
 /* IRQ */
 #define IRQ0_IRQ        32
 #define IRQ1_IRQ        33
-#define INTC_ICR0       0xA4140000UL
-#define INTC_ICR1       0xA414001CUL
-
-#define INTMSK0         0xa4140044
-#define INTMSKCLR0      0xa4140064
-#define INTC_INTPRI0    0xa4140010
 
 #define IRQ01_MODE      0xb1800000
 #define IRQ01_STS       0xb1800004
 #define IRQ01_MASK      0xb1800008
-#define EXT_BIT		(0x3fc0)        /* SH IRQ1 */
-#define MRSHPC_BIT0	(0x0004)        /* SH IRQ1 */
-#define MRSHPC_BIT1	(0x0008)        /* SH IRQ1 */
-#define MRSHPC_BIT2	(0x0010)        /* SH IRQ1 */
-#define MRSHPC_BIT3	(0x0020)        /* SH IRQ1 */
-#define SMC_BIT		(0x0002)        /* SH IRQ0 */
-#define USB_BIT		(0x0001)        /* SH IRQ0 */
 
-#define MRSHPC_IRQ3    	11
-#define MRSHPC_IRQ2    	12
-#define MRSHPC_IRQ1    	13
-#define MRSHPC_IRQ0    	14
-#define SMC_IRQ		10
-#define EXT_IRQ		5
-#define USB_IRQ		6
+/* Bits in IRQ01_* registers */
 
+#define SE7722_FPGA_IRQ_USB	0 /* IRQ0 */
+#define SE7722_FPGA_IRQ_SMC	1 /* IRQ0 */
+#define SE7722_FPGA_IRQ_MRSHPC0	2 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC1	3 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC2	4 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC3	5 /* IRQ1 */
+
+#define SE7722_FPGA_IRQ_NR	6
+#define SE7722_FPGA_IRQ_BASE	110
+
+#define MRSHPC_IRQ3    	(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
+#define MRSHPC_IRQ2    	(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
+#define MRSHPC_IRQ1    	(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
+#define MRSHPC_IRQ0    	(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
+#define SMC_IRQ		(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
+#define USB_IRQ		(SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
 
 /* arch/sh/boards/se/7722/irq.c */
 void init_se7722_IRQ(void);
-int se7722_irq_demux(int);
 
 #define __IO_PREFIX		se7722
 #include <asm/io_generic.h>
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 77bcb09..b182b1c 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -332,8 +332,9 @@
 #define __NR_signalfd		321
 #define __NR_timerfd		322
 #define __NR_eventfd		323
+#define __NR_fallocate		324
 
-#define NR_syscalls 324
+#define NR_syscalls 325
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
index ea3adc6..1a5197f 100644
--- a/include/asm-sh64/unistd.h
+++ b/include/asm-sh64/unistd.h
@@ -374,10 +374,11 @@
 #define __NR_signalfd		349
 #define __NR_timerfd		350
 #define __NR_eventfd		351
+#define __NR_fallocate		352
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 352
+#define NR_syscalls 353
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h
index d8f9872..4a56d84 100644
--- a/include/asm-sparc/device.h
+++ b/include/asm-sparc/device.h
@@ -3,5 +3,17 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC_DEVICE_H
+#define _ASM_SPARC_DEVICE_H
+
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+	struct device_node	*prom_node;
+	struct of_device	*op;
+};
+
+#endif /* _ASM_SPARC_DEVICE_H */
+
 
diff --git a/include/asm-sparc/fb.h b/include/asm-sparc/fb.h
index c7df380..c73ca08 100644
--- a/include/asm-sparc/fb.h
+++ b/include/asm-sparc/fb.h
@@ -1,11 +1,20 @@
 #ifndef _ASM_FB_H_
 #define _ASM_FB_H_
 #include <linux/fb.h>
+#include <asm/prom.h>
 
 #define fb_pgprotect(...) do {} while (0)
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+	struct device *dev = info->device;
+	struct device_node *node;
+
+	node = dev->archdata.prom_node;
+	if (node &&
+	    node == of_console_device)
+		return 1;
+
 	return 0;
 }
 
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index ff520ea..afb88a5 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -7,178 +7,16 @@
 #ifndef _SPARC_IRQ_H
 #define _SPARC_IRQ_H
 
-#include <linux/linkage.h>
-#include <linux/threads.h>     /* For NR_CPUS */
 #include <linux/interrupt.h>
 
-#include <asm/system.h>     /* For SUN4M_NCPUS */
-#include <asm/btfixup.h>
-
-#define __irq_ino(irq) irq
-#define __irq_pil(irq) irq
-
 #define NR_IRQS    16
 
 #define irq_canonicalize(irq)	(irq)
 
-/* Dave Redman (djhr@tadpole.co.uk)
- * changed these to function pointers.. it saves cycles and will allow
- * the irq dependencies to be split into different files at a later date
- * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
- * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Changed these to btfixup entities... It saves cycles :)
- */
-BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
-BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-
-static inline void disable_irq_nosync(unsigned int irq)
-{
-	BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void disable_irq(unsigned int irq)
-{
-	BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void enable_irq(unsigned int irq)
-{
-	BTFIXUP_CALL(enable_irq)(irq);
-}
-
-static inline void disable_pil_irq(unsigned int irq)
-{
-	BTFIXUP_CALL(disable_pil_irq)(irq);
-}
-
-static inline void enable_pil_irq(unsigned int irq)
-{
-	BTFIXUP_CALL(enable_pil_irq)(irq);
-}
-
-static inline void clear_clock_irq(void)
-{
-	BTFIXUP_CALL(clear_clock_irq)();
-}
-
-static inline void clear_profile_irq(int irq)
-{
-	BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
-static inline void load_profile_irq(int cpu, int limit)
-{
-	BTFIXUP_CALL(load_profile_irq)(cpu, limit);
-}
-
-extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
-extern void claim_ticker14(irq_handler_t irq_handler,
-			   int irq,
-			   unsigned int timeout);
-
-#ifdef CONFIG_SMP
-BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, set_irq_udt, int)
-
-#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
-#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
-#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
-#endif
+extern void disable_irq_nosync(unsigned int irq);
+extern void disable_irq(unsigned int irq);
+extern void enable_irq(unsigned int irq);
 
 extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname);
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-	unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-	/* These next two registers are WRITE-ONLY and are only
-	 * "on bit" sensitive, "off bits" written have NO affect.
-	 */
-	unsigned int clear;  /* Clear this cpus irqs here. */
-	unsigned int set;    /* Set this cpus irqs here. */
-	unsigned char space[PAGE_SIZE - 12];
-};
-
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-	struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-	unsigned int tbt;                /* IRQ's that are still pending. */
-	unsigned int irqs;               /* Master IRQ bits. */
-
-	/* Again, like the above, two these registers are WRITE-ONLY. */
-	unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-	unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-	/* This register is both READ and WRITE. */
-	unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
-};
-
-extern struct sun4m_intregs *sun4m_interrupts;
-
-/* 
- * Bit field defines for the interrupt registers on various
- * Sparc machines.
- */
-
-/* The sun4c interrupt register. */
-#define SUN4C_INT_ENABLE  0x01     /* Allow interrupts. */
-#define SUN4C_INT_E14     0x80     /* Enable level 14 IRQ. */
-#define SUN4C_INT_E10     0x20     /* Enable level 10 IRQ. */
-#define SUN4C_INT_E8      0x10     /* Enable level 8 IRQ. */
-#define SUN4C_INT_E6      0x08     /* Enable level 6 IRQ. */
-#define SUN4C_INT_E4      0x04     /* Enable level 4 IRQ. */
-#define SUN4C_INT_E1      0x02     /* Enable level 1 IRQ. */
-
-/* Dave Redman (djhr@tadpole.co.uk)
- * The sun4m interrupt registers.
- */
-#define SUN4M_INT_ENABLE  	0x80000000
-#define SUN4M_INT_E14     	0x00000080
-#define SUN4M_INT_E10     	0x00080000
-
-#define SUN4M_HARD_INT(x)	(0x000000001 << (x))
-#define SUN4M_SOFT_INT(x)	(0x000010000 << (x))
-
-#define	SUN4M_INT_MASKALL	0x80000000	  /* mask all interrupts */
-#define	SUN4M_INT_MODULE_ERR	0x40000000	  /* module error */
-#define	SUN4M_INT_M2S_WRITE	0x20000000	  /* write buffer error */
-#define	SUN4M_INT_ECC		0x10000000	  /* ecc memory error */
-#define	SUN4M_INT_FLOPPY	0x00400000	  /* floppy disk */
-#define	SUN4M_INT_MODULE	0x00200000	  /* module interrupt */
-#define	SUN4M_INT_VIDEO		0x00100000	  /* onboard video */
-#define	SUN4M_INT_REALTIME	0x00080000	  /* system timer */
-#define	SUN4M_INT_SCSI		0x00040000	  /* onboard scsi */
-#define	SUN4M_INT_AUDIO		0x00020000	  /* audio/isdn */
-#define	SUN4M_INT_ETHERNET	0x00010000	  /* onboard ethernet */
-#define	SUN4M_INT_SERIAL	0x00008000	  /* serial ports */
-#define	SUN4M_INT_KBDMS		0x00004000	  /* keyboard/mouse */
-#define	SUN4M_INT_SBUSBITS	0x00003F80	  /* sbus int bits */
-
-#define SUN4M_INT_SBUS(x)	(1 << (x+7))
-#define SUN4M_INT_VME(x)	(1 << (x))
-
 #endif
diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h
index 7cb00c1..e5f5aed 100644
--- a/include/asm-sparc/of_device.h
+++ b/include/asm-sparc/of_device.h
@@ -3,13 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -30,50 +26,13 @@
 	int				portid;
 	int				clock_freq;
 };
-#define	to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-	const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-	char			*name;
-	struct of_device_id	*match_table;
-	struct module		*owner;
-
-	int	(*probe)(struct of_device* dev, const struct of_device_id *match);
-	int	(*remove)(struct of_device* dev);
-
-	int	(*suspend)(struct of_device* dev, pm_message_t state);
-	int	(*resume)(struct of_device* dev);
-	int	(*shutdown)(struct of_device* dev);
-
-	struct device_driver	driver;
-};
-#define	to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-			      struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-						   const char *bus_id,
-						   struct device *parent,
-						   struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/include/asm-sparc/of_platform.h b/include/asm-sparc/of_platform.h
new file mode 100644
index 0000000..64a2300
--- /dev/null
+++ b/include/asm-sparc/of_platform.h
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_OF_PLATFORM_H
+#define _ASM_SPARC_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *		by Stephen Rothwell
+ *
+ *  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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type	of_platform_bus_type	/* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+			      struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+						   const char *bus_id,
+						   struct device *parent,
+						   struct bus_type *bus);
+
+#endif	/* _ASM_SPARC_OF_PLATFORM_H */
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
index 91691e5..17ba82ee 100644
--- a/include/asm-sparc/oplib.h
+++ b/include/asm-sparc/oplib.h
@@ -158,32 +158,6 @@
 extern void prom_printf(char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-	PROMDEV_IKBD,			/* input from keyboard */
-	PROMDEV_ITTYA,			/* input from ttya */
-	PROMDEV_ITTYB,			/* input from ttyb */
-	PROMDEV_IRSC,			/* input from rsc */
-	PROMDEV_IVCONS,			/* input from virtual-console */
-	PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-	PROMDEV_OSCREEN,		/* to screen */
-	PROMDEV_OTTYA,			/* to ttya */
-	PROMDEV_OTTYB,			/* to ttyb */
-	PROMDEV_ORSC,			/* to rsc */
-	PROMDEV_OVCONS,			/* to virtual-console */
-	PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 
 /* Start the CPU with the given device tree node, context table, and context
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index a55f4c3..2cc235b 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -46,7 +46,6 @@
 #define pgd_ERROR(e)   __builtin_trap()
 
 BTFIXUPDEF_INT(page_none)
-BTFIXUPDEF_INT(page_shared)
 BTFIXUPDEF_INT(page_copy)
 BTFIXUPDEF_INT(page_readonly)
 BTFIXUPDEF_INT(page_kernel)
@@ -66,7 +65,7 @@
 #define PTE_SIZE		(PTRS_PER_PTE*4)
 
 #define PAGE_NONE      __pgprot(BTFIXUP_INT(page_none))
-#define PAGE_SHARED    __pgprot(BTFIXUP_INT(page_shared))
+extern pgprot_t PAGE_SHARED;
 #define PAGE_COPY      __pgprot(BTFIXUP_INT(page_copy))
 #define PAGE_READONLY  __pgprot(BTFIXUP_INT(page_readonly))
 
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index 9ea105e..350676c 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -2,7 +2,6 @@
 #define _SPARC_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -17,11 +16,17 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT	2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT	1
+
+#define of_compat_cmp(s1, s2, l)	strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)		strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)		strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -55,53 +60,34 @@
 	unsigned int unique_id;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR	((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-	dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name);
-#define for_each_node_by_name(dn, name) \
-	for (dn = of_find_node_by_name(NULL, name); dn; \
-	     dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type);
-#define for_each_node_by_type(dn, type) \
-	for (dn = of_find_node_by_type(NULL, type); dn; \
-	     dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-					     struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-					 const char *name,
-					 int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-				   const char *);
-extern const void *of_get_property(const struct device_node *node,
-				   const char *name,
-				   int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+	return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 64471bc..029b3e0 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.74 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
@@ -330,8 +329,9 @@
 #define __NR_signalfd		311
 #define __NR_timerfd		312
 #define __NR_eventfd		313
+#define __NR_fallocate		314
 
-#define NR_SYSCALLS		314
+#define NR_SYSCALLS		315
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-sparc64/fb.h b/include/asm-sparc64/fb.h
index d6cd3a1..389012e 100644
--- a/include/asm-sparc64/fb.h
+++ b/include/asm-sparc64/fb.h
@@ -3,6 +3,7 @@
 #include <linux/fb.h>
 #include <linux/fs.h>
 #include <asm/page.h>
+#include <asm/prom.h>
 
 static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
 				unsigned long off)
@@ -12,6 +13,14 @@
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+	struct device *dev = info->device;
+	struct device_node *node;
+
+	node = dev->archdata.prom_node;
+	if (node &&
+	    node == of_console_device)
+		return 1;
+
 	return 0;
 }
 
diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h
index 60e9173..46d69b3 100644
--- a/include/asm-sparc64/of_device.h
+++ b/include/asm-sparc64/of_device.h
@@ -3,14 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type isa_bus_type;
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -31,50 +26,13 @@
 	int				portid;
 	int				clock_freq;
 };
-#define	to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-	const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-	char			*name;
-	struct of_device_id	*match_table;
-	struct module		*owner;
-
-	int	(*probe)(struct of_device* dev, const struct of_device_id *match);
-	int	(*remove)(struct of_device* dev);
-
-	int	(*suspend)(struct of_device* dev, pm_message_t state);
-	int	(*resume)(struct of_device* dev);
-	int	(*shutdown)(struct of_device* dev);
-
-	struct device_driver	driver;
-};
-#define	to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-			      struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-						   const char *bus_id,
-						   struct device *parent,
-						   struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC64_OF_DEVICE_H */
diff --git a/include/asm-sparc64/of_platform.h b/include/asm-sparc64/of_platform.h
new file mode 100644
index 0000000..f7c1f17
--- /dev/null
+++ b/include/asm-sparc64/of_platform.h
@@ -0,0 +1,33 @@
+#ifndef _ASM_SPARC64_OF_PLATFORM_H
+#define _ASM_SPARC64_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *		by Stephen Rothwell
+ *
+ *  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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type isa_bus_type;
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type	of_platform_bus_type	/* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+			      struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+						   const char *bus_id,
+						   struct device *parent,
+						   struct bus_type *bus);
+
+#endif	/* _ASM_SPARC64_OF_PLATFORM_H */
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index 992f9f7..3f23c5d 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -140,32 +140,6 @@
 extern void prom_printf(const char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-	PROMDEV_IKBD,			/* input from keyboard */
-	PROMDEV_ITTYA,			/* input from ttya */
-	PROMDEV_ITTYB,			/* input from ttyb */
-	PROMDEV_IRSC,			/* input from rsc */
-	PROMDEV_IVCONS,			/* input from virtual-console */
-	PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-	PROMDEV_OSCREEN,		/* to screen */
-	PROMDEV_OTTYA,			/* to ttya */
-	PROMDEV_OTTYB,			/* to ttyb */
-	PROMDEV_ORSC,			/* to rsc */
-	PROMDEV_OVCONS,			/* to virtual-console */
-	PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 #ifdef CONFIG_SMP
 /* Start the CPU with the given device tree node at the passed program
@@ -319,6 +293,8 @@
 extern int prom_service_exists(const char *service_name);
 extern void prom_sun4v_guest_soft_state(void);
 
+extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
+
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
 extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 23cc63f..600afe5 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -8,8 +8,9 @@
 #define _ASM_SPARC64_PARPORT_H 1
 
 #include <asm/ebus.h>
-#include <asm/isa.h>
 #include <asm/ns87303.h>
+#include <asm/of_device.h>
+#include <asm/prom.h>
 
 #define PARPORT_PC_MAX_PORTS	PARPORT_MAX
 
@@ -35,8 +36,12 @@
 	unsigned int addr;
 	unsigned int count;
 	int lock;
+
+	struct parport *port;
 } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
+static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
+
 static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
 {
 	if (dmanr >= PARPORT_PC_MAX_PORTS)
@@ -98,117 +103,145 @@
 	return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
-static int ebus_ecpp_p(struct linux_ebus_device *edev)
+static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-	if (!strcmp(edev->prom_node->name, "ecpp"))
-		return 1;
-	if (!strcmp(edev->prom_node->name, "parallel")) {
-		const char *compat;
+	unsigned long base = op->resource[0].start;
+	unsigned long config = op->resource[1].start;
+	unsigned long d_base = op->resource[2].start;
+	unsigned long d_len;
+	struct device_node *parent;
+	struct parport *p;
+	int slot, err;
 
-		compat = of_get_property(edev->prom_node,
-					 "compatible", NULL);
-		if (compat &&
-		    (!strcmp(compat, "ecpp") ||
-		     !strcmp(compat, "ns87317-ecpp") ||
-		     !strcmp(compat + 13, "ecpp")))
-			return 1;
+	parent = op->node->parent;
+	if (!strcmp(parent->name, "dma")) {
+		p = parport_pc_probe_port(base, base + 0x400,
+					  op->irqs[0], PARPORT_DMA_NOFIFO,
+					  op->dev.parent);
+		if (!p)
+			return -ENOMEM;
+		dev_set_drvdata(&op->dev, p);
+		return 0;
 	}
+
+	for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
+		if (!test_and_set_bit(slot, dma_slot_map))
+			break;
+	}
+	err = -ENODEV;
+	if (slot >= PARPORT_PC_MAX_PORTS)
+		goto out_err;
+
+	spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
+
+	d_len = (op->resource[2].end - d_base) + 1UL;
+	sparc_ebus_dmas[slot].info.regs =
+		of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
+
+	if (!sparc_ebus_dmas[slot].info.regs)
+		goto out_clear_map;
+
+	sparc_ebus_dmas[slot].info.flags = 0;
+	sparc_ebus_dmas[slot].info.callback = NULL;
+	sparc_ebus_dmas[slot].info.client_cookie = NULL;
+	sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
+	strcpy(sparc_ebus_dmas[slot].info.name, "parport");
+	if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
+		goto out_unmap_regs;
+
+	ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
+
+	/* Configure IRQ to Push Pull, Level Low */
+	/* Enable ECP, set bit 2 of the CTR first */
+	outb(0x04, base + 0x02);
+	ns87303_modify(config, PCR,
+		       PCR_EPP_ENABLE |
+		       PCR_IRQ_ODRAIN,
+		       PCR_ECP_ENABLE |
+		       PCR_ECP_CLK_ENA |
+		       PCR_IRQ_POLAR);
+
+	/* CTR bit 5 controls direction of port */
+	ns87303_modify(config, PTR,
+		       0, PTR_LPT_REG_DIR);
+
+	p = parport_pc_probe_port(base, base + 0x400,
+				  op->irqs[0],
+				  slot,
+				  op->dev.parent);
+	err = -ENOMEM;
+	if (!p)
+		goto out_disable_irq;
+
+	dev_set_drvdata(&op->dev, p);
+
+	return 0;
+
+out_disable_irq:
+	ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+	ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+
+out_unmap_regs:
+	of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
+
+out_clear_map:
+	clear_bit(slot, dma_slot_map);
+
+out_err:
+	return err;
+}
+
+static int __devexit ecpp_remove(struct of_device *op)
+{
+	struct parport *p = dev_get_drvdata(&op->dev);
+	int slot = p->dma;
+
+	parport_pc_unregister_port(p);
+
+	if (slot != PARPORT_DMA_NOFIFO) {
+		unsigned long d_base = op->resource[2].start;
+		unsigned long d_len;
+
+		d_len = (op->resource[2].end - d_base) + 1UL;
+
+		ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+		ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+		of_iounmap(&op->resource[2],
+			   sparc_ebus_dmas[slot].info.regs,
+			   d_len);
+		clear_bit(slot, dma_slot_map);
+	}
+
 	return 0;
 }
 
-static int parport_isa_probe(int count)
+static struct of_device_id ecpp_match[] = {
+	{
+		.name = "ecpp",
+	},
+	{
+		.name = "parallel",
+		.compatible = "ecpp",
+	},
+	{
+		.name = "parallel",
+		.compatible = "ns87317-ecpp",
+	},
+	{},
+};
+
+static struct of_platform_driver ecpp_driver = {
+	.name			= "ecpp",
+	.match_table		= ecpp_match,
+	.probe			= ecpp_probe,
+	.remove			= __devexit_p(ecpp_remove),
+};
+
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
-	struct sparc_isa_bridge *isa_br;
-	struct sparc_isa_device *isa_dev;
+	of_register_driver(&ecpp_driver, &of_bus_type);
 
-	for_each_isa(isa_br) {
-		for_each_isadev(isa_dev, isa_br) {
-			struct sparc_isa_device *child;
-			unsigned long base;
-
-			if (strcmp(isa_dev->prom_node->name, "dma"))
-				continue;
-
-			child = isa_dev->child;
-			while (child) {
-				if (!strcmp(child->prom_node->name, "parallel"))
-					break;
-				child = child->next;
-			}
-			if (!child)
-				continue;
-
-			base = child->resource.start;
-
-			/* No DMA, see commentary in
-			 * asm-sparc64/floppy.h:isa_floppy_init()
-			 */
-			if (parport_pc_probe_port(base, base + 0x400,
-						  child->irq, PARPORT_DMA_NOFIFO,
-						  &child->bus->self->dev))
-				count++;
-		}
-	}
-
-	return count;
-}
-
-static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
-{
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev;
-	int count = 0;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (ebus_ecpp_p(edev)) {
-				unsigned long base = edev->resource[0].start;
-				unsigned long config = edev->resource[1].start;
-				unsigned long d_base = edev->resource[2].start;
-				unsigned long d_len;
-
-				spin_lock_init(&sparc_ebus_dmas[count].info.lock);
-				d_len = (edev->resource[2].end -
-					 d_base) + 1;
-				sparc_ebus_dmas[count].info.regs =
-					ioremap(d_base, d_len);
-				if (!sparc_ebus_dmas[count].info.regs)
-					continue;
-				sparc_ebus_dmas[count].info.flags = 0;
-				sparc_ebus_dmas[count].info.callback = NULL;
-				sparc_ebus_dmas[count].info.client_cookie = NULL;
-				sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
-				strcpy(sparc_ebus_dmas[count].info.name, "parport");
-				if (ebus_dma_register(&sparc_ebus_dmas[count].info))
-					continue;
-				ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
-
-				/* Configure IRQ to Push Pull, Level Low */
-				/* Enable ECP, set bit 2 of the CTR first */
-				outb(0x04, base + 0x02);
-				ns87303_modify(config, PCR,
-					       PCR_EPP_ENABLE |
-					       PCR_IRQ_ODRAIN,
-					       PCR_ECP_ENABLE |
-					       PCR_ECP_CLK_ENA |
-					       PCR_IRQ_POLAR);
-
-				/* CTR bit 5 controls direction of port */
-				ns87303_modify(config, PTR,
-					       0, PTR_LPT_REG_DIR);
-
-				if (parport_pc_probe_port(base, base + 0x400,
-							  edev->irqs[0],
-							  count,
-							  &ebus->self->dev))
-					count++;
-			}
-		}
-	}
-
-	count = parport_isa_probe(count);
-
-	return count;
+	return 0;
 }
 
 #endif /* !(_ASM_SPARC64_PARPORT_H */
diff --git a/include/asm-sparc64/power.h b/include/asm-sparc64/power.h
deleted file mode 100644
index 94495c1..0000000
--- a/include/asm-sparc64/power.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _SPARC64_POWER_H
-#define _SPARC64_POWER_H
-
-extern void wake_up_powerd(void);
-extern int start_powerd(void);
-
-#endif /* !(_SPARC64_POWER_H) */
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index b4df304..31dcb92 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -2,7 +2,6 @@
 #define _SPARC64_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -17,11 +16,17 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT	2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT	1
+
+#define of_compat_cmp(s1, s2, l)	strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)		strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)		strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -63,54 +68,35 @@
 	void		*data;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR	((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-	dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-	const char *name);
-#define for_each_node_by_name(dn, name) \
-	for (dn = of_find_node_by_name(NULL, name); dn; \
-	     dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-	const char *type);
-#define for_each_node_by_type(dn, type) \
-	for (dn = of_find_node_by_type(NULL, type); dn; \
-	     dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-	const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-					     struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-					 const char *name,
-					 int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-				   const char *);
-extern const void *of_get_property(const struct device_node *node,
-			     const char *name,
-			     int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
 				 const char *name,
 				 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+	return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC64_PROM_H */
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 4090674..64891cb 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -115,14 +115,8 @@
 #ifndef __ASSEMBLY__
 
 extern void sun_do_break(void);
-extern int serial_console;
 extern int stop_a_enabled;
 
-static __inline__ int con_is_present(void)
-{
-	return serial_console ? 0 : 1;
-}
-
 extern void synchronize_user_stack(void);
 
 extern void __flushw_user(void);
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index 53e96ed..cb751b4 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.50 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
@@ -332,8 +331,9 @@
 #define __NR_signalfd		311
 #define __NR_timerfd		312
 #define __NR_eventfd		313
+#define __NR_fallocate		314
 
-#define NR_SYSCALLS		314
+#define NR_SYSCALLS		315
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
index c0a8d4e..f7417e9 100644
--- a/include/asm-sparc64/vio.h
+++ b/include/asm-sparc64/vio.h
@@ -275,6 +275,8 @@
 	char			compat[VIO_MAX_COMPAT_LEN];
 	int			compat_len;
 
+	u64			dev_no;
+
 	unsigned long		channel_id;
 
 	unsigned int		tx_irq;
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index a29f050..1da8f49 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -29,6 +29,7 @@
 #ifdef __KERNEL__
 
 #include <acpi/pdc_intel.h>
+#include <asm/numa.h>
 
 #define COMPILER_DEPENDENT_INT64   long long
 #define COMPILER_DEPENDENT_UINT64  unsigned long long
@@ -141,6 +142,16 @@
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
 
+#ifdef CONFIG_ACPI_NUMA
+extern void __init acpi_fake_nodes(const struct bootnode *fake_nodes,
+				   int num_nodes);
+#else
+static inline void acpi_fake_nodes(const struct bootnode *fake_nodes,
+				   int num_nodes)
+{
+}
+#endif
+
 #endif /*__KERNEL__*/
 
 #endif /*_ASM_ACPI_H*/
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index eea7aec..ab161e8 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -154,4 +154,6 @@
 #define __parainstructions_end NULL
 #endif
 
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
 #endif /* _X86_64_ALTERNATIVE_H */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 45e9fca..85125ef 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -83,8 +83,10 @@
 extern void enable_APIC_timer(void);
 extern void setup_apic_routing(void);
 
-extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-				   unsigned char msg_type, unsigned char mask);
+extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+				    unsigned char msg_type, unsigned char mask);
+
+extern int apic_is_clustered_box(void);
 
 #define K8_APIC_EXT_LVT_BASE    0x500
 #define K8_APIC_EXT_INT_MSG_FIX 0x0
diff --git a/include/asm-x86_64/auxvec.h b/include/asm-x86_64/auxvec.h
index 2403c4c..1d5ab0d 100644
--- a/include/asm-x86_64/auxvec.h
+++ b/include/asm-x86_64/auxvec.h
@@ -1,4 +1,6 @@
 #ifndef __ASM_X86_64_AUXVEC_H
 #define __ASM_X86_64_AUXVEC_H
 
+#define AT_SYSINFO_EHDR		33
+
 #endif
diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
index 4d5747a..67f6040 100644
--- a/include/asm-x86_64/calgary.h
+++ b/include/asm-x86_64/calgary.h
@@ -1,7 +1,7 @@
 /*
  * Derived from include/asm-powerpc/iommu.h
  *
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
  *
  * Author: Jon Mason <jdmason@us.ibm.com>
  * Author: Muli Ben-Yehuda <muli@il.ibm.com>
@@ -31,6 +31,7 @@
 #include <asm/types.h>
 
 struct iommu_table {
+	struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
 	unsigned long  it_base;      /* mapped address of tce table */
 	unsigned long  it_hint;      /* Hint for next alloc */
 	unsigned long *it_map;       /* A simple allocation bitmap for now */
@@ -42,6 +43,12 @@
 	unsigned char  it_busno;     /* Bus number this table belongs to */
 };
 
+struct cal_chipset_ops {
+	void (*handle_quirks)(struct iommu_table *tbl, struct pci_dev *dev);
+	void (*tce_cache_blast)(struct iommu_table *tbl);
+	void (*dump_error_regs)(struct iommu_table *tbl);
+};
+
 #define TCE_TABLE_SIZE_UNSPECIFIED	~0
 #define TCE_TABLE_SIZE_64K		0
 #define TCE_TABLE_SIZE_128K		1
diff --git a/include/asm-x86_64/cmpxchg.h b/include/asm-x86_64/cmpxchg.h
index 09a6b6b..5e18206 100644
--- a/include/asm-x86_64/cmpxchg.h
+++ b/include/asm-x86_64/cmpxchg.h
@@ -128,7 +128,7 @@
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
 #define cmpxchg_local(ptr,o,n)\
-	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
 
 #endif
diff --git a/include/asm-x86_64/dmi.h b/include/asm-x86_64/dmi.h
index 93b2b15..d02e32e 100644
--- a/include/asm-x86_64/dmi.h
+++ b/include/asm-x86_64/dmi.h
@@ -3,15 +3,12 @@
 
 #include <asm/io.h>
 
-extern void *dmi_ioremap(unsigned long addr, unsigned long size);
-extern void dmi_iounmap(void *addr, unsigned long size);
-
 #define DMI_MAX_DATA 2048
 
 extern int dmi_alloc_index;
 extern char dmi_alloc_data[DMI_MAX_DATA];
 
-/* This is so early that there is no good way to allocate dynamic memory. 
+/* This is so early that there is no good way to allocate dynamic memory.
    Allocate data in an BSS array. */
 static inline void *dmi_alloc(unsigned len)
 {
diff --git a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h
index 6d24ea7..b4fbe47 100644
--- a/include/asm-x86_64/elf.h
+++ b/include/asm-x86_64/elf.h
@@ -162,6 +162,19 @@
 /* 1GB for 64bit, 8MB for 32bit */
 #define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff)
 
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+                                       int executable_stack);
+
+extern int vdso_enabled;
+
+#define ARCH_DLINFO						\
+do if (vdso_enabled) {						\
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,(unsigned long)current->mm->context.vdso);\
+} while (0)
+
 #endif
 
 #endif
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index 2acb9b7..cdfbe4a 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -22,9 +22,9 @@
  * compile time, but to set the physical address only
  * in the boot process.
  *
- * these 'compile-time allocated' memory buffers are
- * fixed-size 4k pages. (or larger if used with an increment
- * highger than 1) use fixmap_set(idx,phys) to associate
+ * These 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages (or larger if used with an increment
+ * higher than 1). Use set_fixmap(idx,phys) to associate
  * physical memory with fixmap indices.
  *
  * TLB entries of such buffers will not be flushed across
diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
index 59a66f0..79bb950 100644
--- a/include/asm-x86_64/hpet.h
+++ b/include/asm-x86_64/hpet.h
@@ -1,78 +1,18 @@
 #ifndef _ASM_X8664_HPET_H
 #define _ASM_X8664_HPET_H 1
 
-/*
- * Documentation on HPET can be found at:
- *      http://www.intel.com/ial/home/sp/pcmmspec.htm
- *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE	1024
-
-#define HPET_ID		0x000
-#define HPET_PERIOD	0x004
-#define HPET_CFG	0x010
-#define HPET_STATUS	0x020
-#define HPET_COUNTER	0x0f0
-#define HPET_Tn_OFFSET	0x20
-#define HPET_Tn_CFG(n)	 (0x100 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_ROUTE(n) (0x104 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_CMP(n)	 (0x108 + (n) * HPET_Tn_OFFSET)
-#define HPET_T0_CFG	HPET_Tn_CFG(0)
-#define HPET_T0_CMP	HPET_Tn_CMP(0)
-#define HPET_T1_CFG	HPET_Tn_CFG(1)
-#define HPET_T1_CMP	HPET_Tn_CMP(1)
-
-#define HPET_ID_VENDOR	0xffff0000
-#define HPET_ID_LEGSUP	0x00008000
-#define HPET_ID_64BIT	0x00002000
-#define HPET_ID_NUMBER	0x00001f00
-#define HPET_ID_REV	0x000000ff
-#define	HPET_ID_NUMBER_SHIFT	8
-
-#define HPET_ID_VENDOR_SHIFT	16
-#define HPET_ID_VENDOR_8086	0x8086
-
-#define HPET_CFG_ENABLE	0x001
-#define HPET_CFG_LEGACY	0x002
-#define	HPET_LEGACY_8254	2
-#define	HPET_LEGACY_RTC		8
-
-#define HPET_TN_LEVEL		0x0002
-#define HPET_TN_ENABLE		0x0004
-#define HPET_TN_PERIODIC	0x0008
-#define HPET_TN_PERIODIC_CAP	0x0010
-#define HPET_TN_64BIT_CAP	0x0020
-#define HPET_TN_SETVAL		0x0040
-#define HPET_TN_32BIT		0x0100
-#define HPET_TN_ROUTE		0x3e00
-#define HPET_TN_FSB		0x4000
-#define HPET_TN_FSB_CAP		0x8000
-
-#define HPET_TN_ROUTE_SHIFT	9
+#include <asm-i386/hpet.h>
 
 #define HPET_TICK_RATE (HZ * 100000UL)
 
-extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
-extern int apic_is_clustered_box(void);
 extern int hpet_arch_init(void);
 extern int hpet_timer_stop_set_go(unsigned long tick);
 extern int hpet_reenable(void);
 extern unsigned int hpet_calibrate_tsc(void);
 
 extern int hpet_use_timer;
-extern unsigned long hpet_address;
 extern unsigned long hpet_period;
 extern unsigned long hpet_tick;
 
-#ifdef CONFIG_HPET_EMULATE_RTC
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
 #endif
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 6153ae5..09dfc18 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -95,6 +95,26 @@
 
 
 #ifndef __ASSEMBLY__
+
+/* Interrupt handlers registered during init_IRQ */
+void apic_timer_interrupt(void);
+void spurious_interrupt(void);
+void error_interrupt(void);
+void reschedule_interrupt(void);
+void call_function_interrupt(void);
+void irq_move_cleanup_interrupt(void);
+void invalidate_interrupt0(void);
+void invalidate_interrupt1(void);
+void invalidate_interrupt2(void);
+void invalidate_interrupt3(void);
+void invalidate_interrupt4(void);
+void invalidate_interrupt5(void);
+void invalidate_interrupt6(void);
+void invalidate_interrupt7(void);
+void thermal_interrupt(void);
+void threshold_interrupt(void);
+void i8254_timer_resume(void);
+
 typedef int vector_irq_t[NR_VECTORS];
 DECLARE_PER_CPU(vector_irq_t, vector_irq);
 extern void __setup_vector_irq(int cpu);
diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
index c16c6ff..5cbf9fa 100644
--- a/include/asm-x86_64/hypertransport.h
+++ b/include/asm-x86_64/hypertransport.h
@@ -1,42 +1 @@
-#ifndef ASM_HYPERTRANSPORT_H
-#define ASM_HYPERTRANSPORT_H
-
-/*
- * Constants for x86 Hypertransport Interrupts.
- */
-
-#define HT_IRQ_LOW_BASE			0xf8000000
-
-#define HT_IRQ_LOW_VECTOR_SHIFT		16
-#define  HT_IRQ_LOW_VECTOR_MASK		0x00ff0000
-#define  HT_IRQ_LOW_VECTOR(v)		(((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
-
-#define HT_IRQ_LOW_DEST_ID_SHIFT	8
-#define  HT_IRQ_LOW_DEST_ID_MASK	0x0000ff00
-#define  HT_IRQ_LOW_DEST_ID(v)		(((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
-
-#define HT_IRQ_LOW_DM_PHYSICAL		0x0000000
-#define HT_IRQ_LOW_DM_LOGICAL		0x0000040
-
-#define HT_IRQ_LOW_RQEOI_EDGE		0x0000000
-#define HT_IRQ_LOW_RQEOI_LEVEL		0x0000020
-
-
-#define HT_IRQ_LOW_MT_FIXED		0x0000000
-#define HT_IRQ_LOW_MT_ARBITRATED	0x0000004
-#define HT_IRQ_LOW_MT_SMI		0x0000008
-#define HT_IRQ_LOW_MT_NMI		0x000000c
-#define HT_IRQ_LOW_MT_INIT		0x0000010
-#define HT_IRQ_LOW_MT_STARTUP		0x0000014
-#define HT_IRQ_LOW_MT_EXTINT		0x0000018
-#define HT_IRQ_LOW_MT_LINT1		0x000008c
-#define HT_IRQ_LOW_MT_LINT0		0x0000098
-
-#define HT_IRQ_LOW_IRQ_MASKED		0x0000001
-
-
-#define HT_IRQ_HIGH_DEST_ID_SHIFT	0
-#define  HT_IRQ_HIGH_DEST_ID_MASK	0x00ffffff
-#define  HT_IRQ_HIGH_DEST_ID(v)		((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
-
-#endif /* ASM_HYPERTRANSPORT_H */
+#include <asm-i386/hypertransport.h>
diff --git a/include/asm-x86_64/i8253.h b/include/asm-x86_64/i8253.h
new file mode 100644
index 0000000..015d8df
--- /dev/null
+++ b/include/asm-x86_64/i8253.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif	/* __ASM_I8253_H__ */
diff --git a/include/asm-x86_64/iommu.h b/include/asm-x86_64/iommu.h
new file mode 100644
index 0000000..5af471f
--- /dev/null
+++ b/include/asm-x86_64/iommu.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_X8664_IOMMU_H
+#define _ASM_X8664_IOMMU_H 1
+
+extern void pci_iommu_shutdown(void);
+extern void no_iommu_init(void);
+extern int force_iommu, no_iommu;
+extern int iommu_detected;
+#ifdef CONFIG_IOMMU
+extern void gart_iommu_init(void);
+extern void gart_iommu_shutdown(void);
+extern void __init gart_parse_options(char *);
+extern void iommu_hole_init(void);
+extern int fallback_aper_order;
+extern int fallback_aper_force;
+extern int iommu_aperture;
+extern int iommu_aperture_allowed;
+extern int iommu_aperture_disabled;
+extern int fix_aperture;
+#else
+#define iommu_aperture 0
+#define iommu_aperture_allowed 0
+
+static inline void gart_iommu_shutdown(void)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h
index 177e92b..7bc030a 100644
--- a/include/asm-x86_64/mce.h
+++ b/include/asm-x86_64/mce.h
@@ -105,6 +105,11 @@
 
 extern void do_machine_check(struct pt_regs *, long);
 
+extern int mce_notify_user(void);
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
 #endif
 
 #endif
diff --git a/include/asm-x86_64/mmu.h b/include/asm-x86_64/mmu.h
index 5dc6ed7..d2cd4a9 100644
--- a/include/asm-x86_64/mmu.h
+++ b/include/asm-x86_64/mmu.h
@@ -15,6 +15,7 @@
 	rwlock_t ldtlock; 
 	int size;
 	struct semaphore sem; 
+	void *vdso;
 } mm_context_t;
 
 #endif
diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
index 5b8acdd..083ad58 100644
--- a/include/asm-x86_64/msidef.h
+++ b/include/asm-x86_64/msidef.h
@@ -1,47 +1 @@
-#ifndef ASM_MSIDEF_H
-#define ASM_MSIDEF_H
-
-/*
- * Constants for Intel APIC based MSI messages.
- */
-
-/*
- * Shifts for MSI data
- */
-
-#define MSI_DATA_VECTOR_SHIFT		0
-#define  MSI_DATA_VECTOR_MASK		0x000000ff
-#define	 MSI_DATA_VECTOR(v)		(((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
-
-#define MSI_DATA_DELIVERY_MODE_SHIFT	8
-#define  MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_MODE_SHIFT)
-#define  MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_MODE_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT		14
-#define	 MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
-#define	 MSI_DATA_LEVEL_ASSERT		(1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT		15
-#define  MSI_DATA_TRIGGER_EDGE		(0 << MSI_DATA_TRIGGER_SHIFT)
-#define  MSI_DATA_TRIGGER_LEVEL		(1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for msi address
- */
-
-#define MSI_ADDR_BASE_HI		0
-#define MSI_ADDR_BASE_LO		0xfee00000
-
-#define MSI_ADDR_DEST_MODE_SHIFT	2
-#define  MSI_ADDR_DEST_MODE_PHYSICAL	(0 << MSI_ADDR_DEST_MODE_SHIFT)
-#define	 MSI_ADDR_DEST_MODE_LOGICAL	(1 << MSI_ADDR_DEST_MODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT	3
-#define  MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
-#define  MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
-
-#define MSI_ADDR_DEST_ID_SHIFT		12
-#define	 MSI_ADDR_DEST_ID_MASK		0x00ffff0
-#define  MSI_ADDR_DEST_ID(dest)		(((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
-
-#endif /* ASM_MSIDEF_H */
+#include <asm-i386/msidef.h>
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index d0a7f53..5fb3c0d 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -88,5 +88,7 @@
 int lapic_watchdog_ok(void);
 void disable_lapic_nmi_watchdog(void);
 void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
 
 #endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index bda94fd..88926eb 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -5,6 +5,25 @@
 
 #ifdef __KERNEL__
 
+struct pci_sysdata {
+	int		node;		/* NUMA node */
+	void*		iommu;		/* IOMMU private data */
+};
+
+#ifdef CONFIG_CALGARY_IOMMU
+static inline void* pci_iommu(struct pci_bus *bus)
+{
+	struct pci_sysdata *sd = bus->sysdata;
+	return sd->iommu;
+}
+
+static inline void set_pci_iommu(struct pci_bus *bus, void *val)
+{
+	struct pci_sysdata *sd = bus->sysdata;
+	sd->iommu = val;
+}
+#endif /* CONFIG_CALGARY_IOMMU */
+
 #include <linux/mm.h> /* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
index 8bb5646..b467be6 100644
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -4,6 +4,10 @@
 #include <asm/pda.h>
 #include <linux/threads.h>
 #include <linux/mm.h>
+#include <linux/quicklist.h>
+
+#define QUICK_PGD 0	/* We preserve special mappings over free */
+#define QUICK_PT 1	/* Other page table pages that are zero on free */
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 		set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
@@ -20,23 +24,23 @@
 static inline void pmd_free(pmd_t *pmd)
 {
 	BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
-	free_page((unsigned long)pmd);
+	quicklist_free(QUICK_PT, NULL, pmd);
 }
 
 static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
 {
-	return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+	return (pmd_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+	return (pud_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline void pud_free (pud_t *pud)
 {
 	BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
-	free_page((unsigned long)pud);
+	quicklist_free(QUICK_PT, NULL, pud);
 }
 
 static inline void pgd_list_add(pgd_t *pgd)
@@ -57,41 +61,57 @@
 	spin_unlock(&pgd_lock);
 }
 
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline void pgd_ctor(void *x)
 {
 	unsigned boundary;
-	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
-	if (!pgd)
-		return NULL;
-	pgd_list_add(pgd);
+	pgd_t *pgd = x;
+	struct page *page = virt_to_page(pgd);
+
 	/*
 	 * Copy kernel pointers in from init.
-	 * Could keep a freelist or slab cache of those because the kernel
-	 * part never changes.
 	 */
 	boundary = pgd_index(__PAGE_OFFSET);
-	memset(pgd, 0, boundary * sizeof(pgd_t));
 	memcpy(pgd + boundary,
-	       init_level4_pgt + boundary,
-	       (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
+		init_level4_pgt + boundary,
+		(PTRS_PER_PGD - boundary) * sizeof(pgd_t));
+
+	spin_lock(&pgd_lock);
+	list_add(&page->lru, &pgd_list);
+	spin_unlock(&pgd_lock);
+}
+
+static inline void pgd_dtor(void *x)
+{
+	pgd_t *pgd = x;
+	struct page *page = virt_to_page(pgd);
+
+        spin_lock(&pgd_lock);
+	list_del(&page->lru);
+	spin_unlock(&pgd_lock);
+}
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	pgd_t *pgd = (pgd_t *)quicklist_alloc(QUICK_PGD,
+		GFP_KERNEL|__GFP_REPEAT, pgd_ctor);
 	return pgd;
 }
 
 static inline void pgd_free(pgd_t *pgd)
 {
 	BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
-	pgd_list_del(pgd);
-	free_page((unsigned long)pgd);
+	quicklist_free(QUICK_PGD, pgd_dtor, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-	return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+	return (pte_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+	void *p = (void *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
+
 	if (!p)
 		return NULL;
 	return virt_to_page(p);
@@ -103,17 +123,22 @@
 static inline void pte_free_kernel(pte_t *pte)
 {
 	BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
-	free_page((unsigned long)pte); 
+	quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-	__free_page(pte);
-} 
+	quicklist_free_page(QUICK_PT, NULL, pte);
+}
 
-#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+#define __pte_free_tlb(tlb,pte) quicklist_free_page(QUICK_PT, NULL,(pte))
 
-#define __pmd_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
-#define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
+#define __pmd_free_tlb(tlb,x)   quicklist_free(QUICK_PT, NULL, (x))
+#define __pud_free_tlb(tlb,x)   quicklist_free(QUICK_PT, NULL, (x))
 
+static inline void check_pgt_cache(void)
+{
+	quicklist_trim(QUICK_PGD, pgd_dtor, 25, 16);
+	quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 #endif /* _X86_64_PGALLOC_H */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 3ba5309..c9d8764 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -403,13 +403,14 @@
 
 extern int kern_addr_valid(unsigned long addr); 
 
+pte_t *lookup_address(unsigned long addr);
+
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
 #define HAVE_ARCH_UNMAPPED_AREA
 
 #define pgtable_cache_init()   do { } while (0)
-#define check_pgt_cache()      do { } while (0)
 
 #define PAGE_AGP    PAGE_KERNEL_NOCACHE
 #define HAVE_PAGE_AGP 1
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index efc87a5..1952517 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -83,7 +83,6 @@
 #define X86_VENDOR_UMC 3
 #define X86_VENDOR_NEXGEN 4
 #define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
 #define X86_VENDOR_NUM 8
 #define X86_VENDOR_UNKNOWN 0xff
@@ -390,17 +389,6 @@
 
 #define cpu_relax()   rep_nop()
 
-/*
- *      NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
-	outb((reg), 0x22); \
-	outb((data), 0x23); \
-} while (0)
-
 static inline void serialize_cpu(void)
 {
 	__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 85255db..31f20ad 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -75,8 +75,6 @@
 extern void early_quirks(void);
 extern void check_efer(void);
 
-extern int unhandled_signal(struct task_struct *tsk, int sig);
-
 extern void select_idle_routine(const struct cpuinfo_x86 *c);
 
 extern unsigned long table_start, table_end;
@@ -85,24 +83,6 @@
 extern unsigned cpu_khz;
 extern unsigned tsc_khz;
 
-extern void no_iommu_init(void);
-extern int force_iommu, no_iommu;
-extern int iommu_detected;
-#ifdef CONFIG_IOMMU
-extern void gart_iommu_init(void);
-extern void __init gart_parse_options(char *);
-extern void iommu_hole_init(void);
-extern int fallback_aper_order;
-extern int fallback_aper_force;
-extern int iommu_aperture;
-extern int iommu_aperture_allowed;
-extern int iommu_aperture_disabled;
-extern int fix_aperture;
-#else
-#define iommu_aperture 0
-#define iommu_aperture_allowed 0
-#endif
-
 extern int reboot_force;
 extern int notsc_setup(char *);
 
diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
index 5ea84db..7f166cc 100644
--- a/include/asm-x86_64/ptrace.h
+++ b/include/asm-x86_64/ptrace.h
@@ -1,6 +1,7 @@
 #ifndef _X86_64_PTRACE_H
 #define _X86_64_PTRACE_H
 
+#include <linux/compiler.h>	/* For __user */
 #include <asm/ptrace-abi.h>
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-x86_64/resume-trace.h b/include/asm-x86_64/resume-trace.h
new file mode 100644
index 0000000..34bf998
--- /dev/null
+++ b/include/asm-x86_64/resume-trace.h
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do {					\
+	if (pm_trace_enabled) {					\
+		void *tracedata;				\
+		asm volatile("movq $1f,%0\n"			\
+			".section .tracedata,\"a\"\n"		\
+			"1:\t.word %c1\n"			\
+			"\t.quad %c2\n"				\
+			".previous"				\
+			:"=r" (tracedata)			\
+			: "i" (__LINE__), "i" (__FILE__));	\
+		generate_resume_trace(tracedata, user);		\
+	}							\
+} while (0)
diff --git a/include/asm-x86_64/string.h b/include/asm-x86_64/string.h
index 9505d9f..e583da7 100644
--- a/include/asm-x86_64/string.h
+++ b/include/asm-x86_64/string.h
@@ -29,6 +29,9 @@
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
+extern void *memcpy(void *to, const void *from, size_t len);
+#else
 extern void *__memcpy(void *to, const void *from, size_t len); 
 #define memcpy(dst,src,len) \
 	({ size_t __len = (len);				\
@@ -38,7 +41,7 @@
 	   else							\
 		 __ret = __builtin_memcpy((dst),(src),__len);	\
 	   __ret; }) 
-
+#endif
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index e4f246d..02175aa 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -75,19 +75,31 @@
 	unsigned long cr0;
 	asm volatile("movq %%cr0,%0" : "=r" (cr0));
 	return cr0;
-} 
+}
 
 static inline void write_cr0(unsigned long val) 
 { 
 	asm volatile("movq %0,%%cr0" :: "r" (val));
-} 
+}
+
+static inline unsigned long read_cr2(void)
+{
+	unsigned long cr2;
+	asm("movq %%cr2,%0" : "=r" (cr2));
+	return cr2;
+}
+
+static inline void write_cr2(unsigned long val)
+{
+	asm volatile("movq %0,%%cr2" :: "r" (val));
+}
 
 static inline unsigned long read_cr3(void)
 { 
 	unsigned long cr3;
 	asm("movq %%cr3,%0" : "=r" (cr3));
 	return cr3;
-} 
+}
 
 static inline void write_cr3(unsigned long val)
 {
@@ -99,17 +111,29 @@
 	unsigned long cr4;
 	asm("movq %%cr4,%0" : "=r" (cr4));
 	return cr4;
-} 
+}
 
 static inline void write_cr4(unsigned long val)
 { 
 	asm volatile("movq %0,%%cr4" :: "r" (val) : "memory");
-} 
+}
+
+static inline unsigned long read_cr8(void)
+{
+	unsigned long cr8;
+	asm("movq %%cr8,%0" : "=r" (cr8));
+	return cr8;
+}
+
+static inline void write_cr8(unsigned long val)
+{
+	asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
+}
 
 #define stts() write_cr0(8 | read_cr0())
 
 #define wbinvd() \
-	__asm__ __volatile__ ("wbinvd": : :"memory");
+	__asm__ __volatile__ ("wbinvd": : :"memory")
 
 #endif	/* __KERNEL__ */
 
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 10bb5a8..33c72ef 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -115,6 +115,7 @@
 #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
 #define TIF_SECCOMP		8	/* secure computing */
 #define TIF_RESTORE_SIGMASK	9	/* restore signal mask in do_signal */
+#define TIF_MCE_NOTIFY		10	/* notify userspace of an MCE */
 /* 16 free */
 #define TIF_IA32		17	/* 32bit process */ 
 #define TIF_FORK		18	/* ret_from_fork */
@@ -133,6 +134,7 @@
 #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+#define _TIF_MCE_NOTIFY		(1<<TIF_MCE_NOTIFY)
 #define _TIF_IA32		(1<<TIF_IA32)
 #define _TIF_FORK		(1<<TIF_FORK)
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
index f6527e1..6ed21f4 100644
--- a/include/asm-x86_64/timex.h
+++ b/include/asm-x86_64/timex.h
@@ -9,7 +9,6 @@
 #include <asm/8253pit.h>
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
-#include <asm/hpet.h>
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/tsc.h>
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 8516225..888eb4a 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -92,7 +92,11 @@
 
 #endif
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+					unsigned long end)
+{
+	flush_tlb_all();
+}
 
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 4fd6fb2..36e52fb 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -22,7 +22,7 @@
 #define parent_node(node)		(node)
 #define node_to_first_cpu(node) 	(first_cpu(node_to_cpumask[node]))
 #define node_to_cpumask(node)		(node_to_cpumask[node])
-#define pcibus_to_node(bus)		((long)(bus->sysdata))	
+#define pcibus_to_node(bus)	((struct pci_sysdata *)((bus)->sysdata))->node
 #define pcibus_to_cpumask(bus)		node_to_cpumask(pcibus_to_node(bus));
 
 #define numa_node_id()			read_pda(nodenumber)
diff --git a/include/asm-x86_64/vgtod.h b/include/asm-x86_64/vgtod.h
new file mode 100644
index 0000000..3301f09
--- /dev/null
+++ b/include/asm-x86_64/vgtod.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_VGTOD_H
+#define _ASM_VGTOD_H 1
+
+#include <asm/vsyscall.h>
+#include <linux/clocksource.h>
+
+struct vsyscall_gtod_data {
+	seqlock_t	lock;
+
+	/* open coded 'struct timespec' */
+	time_t		wall_time_sec;
+	u32		wall_time_nsec;
+
+	int		sysctl_enabled;
+	struct timezone sys_tz;
+	struct { /* extract of a clocksource struct */
+		cycle_t (*vread)(void);
+		cycle_t	cycle_last;
+		cycle_t	mask;
+		u32	mult;
+		u32	shift;
+	} clock;
+	struct timespec wall_to_monotonic;
+};
+extern struct vsyscall_gtod_data __vsyscall_gtod_data
+__section_vsyscall_gtod_data;
+extern struct vsyscall_gtod_data vsyscall_gtod_data;
+
+#endif
diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
index 82b4afe..3b8ceb4 100644
--- a/include/asm-x86_64/vsyscall.h
+++ b/include/asm-x86_64/vsyscall.h
@@ -22,6 +22,8 @@
 /* Definitions for CONFIG_GENERIC_TIME definitions */
 #define __section_vsyscall_gtod_data __attribute__ \
 	((unused, __section__ (".vsyscall_gtod_data"),aligned(16)))
+#define __section_vsyscall_clock __attribute__ \
+	((unused, __section__ (".vsyscall_clock"),aligned(16)))
 #define __vsyscall_fn __attribute__ ((unused,__section__(".vsyscall_fn")))
 
 #define VGETCPU_RDTSCP	1
@@ -36,7 +38,6 @@
 /* kernel space (writeable) */
 extern int vgetcpu_mode;
 extern struct timezone sys_tz;
-extern struct vsyscall_gtod_data_t vsyscall_gtod_data;
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index dc234c5..d5680cd 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -88,10 +88,8 @@
 int __init acpi_table_parse_entries(char *id, unsigned long table_size,
 	int entry_id, acpi_table_entry_handler handler, unsigned int max_entries);
 int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_type id, acpi_table_entry_handler handler, unsigned int max_entries);
 int acpi_parse_mcfg (struct acpi_table_header *header);
 void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
-void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
 
 /* the following four functions are architecture-dependent */
 #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -233,6 +231,9 @@
 
 extern int pnpacpi_disabled;
 
+#define PXM_INVAL	(-1)
+#define NID_INVAL	(-1)
+
 #else	/* CONFIG_ACPI */
 
 static inline int acpi_boot_init(void)
diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h
index ff12550..bdca3f1 100644
--- a/include/linux/async_tx.h
+++ b/include/linux/async_tx.h
@@ -51,10 +51,6 @@
  * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
  * dependency chain
  * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
- * @ASYNC_TX_KMAP_SRC: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the source page(s)
- * @ASYNC_TX_KMAP_DST: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the dest page(s)
  */
 enum async_tx_flags {
 	ASYNC_TX_XOR_ZERO_DST	 = (1 << 0),
@@ -62,8 +58,6 @@
 	ASYNC_TX_ASSUME_COHERENT = (1 << 2),
 	ASYNC_TX_ACK		 = (1 << 3),
 	ASYNC_TX_DEP_ACK	 = (1 << 4),
-	ASYNC_TX_KMAP_SRC	 = (1 << 5),
-	ASYNC_TX_KMAP_DST	 = (1 << 6),
 };
 
 #ifdef CONFIG_DMA_ENGINE
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 8ca7ca0..4bbd860 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -161,7 +161,7 @@
  * are currently used in an audit field constant understood by the kernel.
  * If you are adding a new #define AUDIT_<whatever>, please ensure that
  * AUDIT_UNUSED_BITS is updated if need be. */
-#define AUDIT_UNUSED_BITS	0x0FFFFC00
+#define AUDIT_UNUSED_BITS	0x07FFFC00
 
 
 /* Rule fields */
@@ -213,25 +213,29 @@
 #define AUDIT_NEGATE			0x80000000
 
 /* These are the supported operators.
- *	4  2  1
- *	=  >  <
- *	-------
- *	0  0  0		0	nonsense
- *	0  0  1		1	<
- *	0  1  0		2	>
- *	0  1  1		3	!=
- *	1  0  0		4	=
- *	1  0  1		5	<=
- *	1  1  0		6	>=
- *	1  1  1		7	all operators
+ *	4  2  1  8
+ *	=  >  <  ?
+ *	----------
+ *	0  0  0	 0	00	nonsense
+ *	0  0  0	 1	08	&  bit mask
+ *	0  0  1	 0	10	<
+ *	0  1  0	 0	20	>
+ *	0  1  1	 0	30	!=
+ *	1  0  0	 0	40	=
+ *	1  0  0	 1	48	&=  bit test
+ *	1  0  1	 0	50	<=
+ *	1  1  0	 0	60	>=
+ *	1  1  1	 1	78	all operators
  */
+#define AUDIT_BIT_MASK			0x08000000
 #define AUDIT_LESS_THAN			0x10000000
 #define AUDIT_GREATER_THAN		0x20000000
 #define AUDIT_NOT_EQUAL			0x30000000
 #define AUDIT_EQUAL			0x40000000
+#define AUDIT_BIT_TEST			(AUDIT_BIT_MASK|AUDIT_EQUAL)
 #define AUDIT_LESS_THAN_OR_EQUAL	(AUDIT_LESS_THAN|AUDIT_EQUAL)
 #define AUDIT_GREATER_THAN_OR_EQUAL	(AUDIT_GREATER_THAN|AUDIT_EQUAL)
-#define AUDIT_OPERATORS			(AUDIT_EQUAL|AUDIT_NOT_EQUAL)
+#define AUDIT_OPERATORS			(AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK)
 
 /* Status symbols */
 				/* Mask values */
@@ -407,7 +411,6 @@
 extern int audit_socketcall(int nargs, unsigned long *args);
 extern int audit_sockaddr(int len, void *addr);
 extern int __audit_fd_pair(int fd1, int fd2);
-extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern int audit_set_macxattr(const char *name);
 extern int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
 extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
@@ -487,7 +490,6 @@
 #define audit_socketcall(n,a) ({ 0; })
 #define audit_fd_pair(n,a) ({ 0; })
 #define audit_sockaddr(len, addr) ({ 0; })
-#define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_set_macxattr(n) do { ; } while (0)
 #define audit_mq_open(o,m,a) ({ 0; })
 #define audit_mq_timedsend(d,l,p,t) ({ 0; })
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 1023ba0..c897c7b 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -69,8 +69,8 @@
 
 	/* The framebuffer notifier block */
 	struct notifier_block fb_notif;
-	/* The class device structure */
-	struct class_device class_dev;
+
+	struct device dev;
 };
 
 static inline void backlight_update_status(struct backlight_device *bd)
@@ -85,6 +85,11 @@
 	struct device *dev, void *devdata, struct backlight_ops *ops);
 extern void backlight_device_unregister(struct backlight_device *bd);
 
-#define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
+#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)
+
+static inline void * bl_get_data(struct backlight_device *bl_dev)
+{
+	return dev_get_drvdata(&bl_dev->dev);
+}
 
 #endif
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 8486e78..e0bd46e 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -23,6 +23,7 @@
 	CLOCK_EVT_MODE_SHUTDOWN,
 	CLOCK_EVT_MODE_PERIODIC,
 	CLOCK_EVT_MODE_ONESHOT,
+	CLOCK_EVT_MODE_RESUME,
 };
 
 /* Clock event notification values */
@@ -119,10 +120,6 @@
 
 extern void clockevents_exchange_device(struct clock_event_device *old,
 					struct clock_event_device *new);
-extern
-struct clock_event_device *clockevents_request_device(unsigned int features,
-						      cpumask_t cpumask);
-extern void clockevents_release_device(struct clock_event_device *dev);
 extern void clockevents_set_mode(struct clock_event_device *dev,
 				 enum clock_event_mode mode);
 extern int clockevents_register_notifier(struct notifier_block *nb);
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index bf297b0..16ea337 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -67,6 +67,12 @@
 	unsigned long flags;
 	cycle_t (*vread)(void);
 	void (*resume)(void);
+#ifdef CONFIG_IA64
+	void *fsys_mmio;        /* used by fsyscall asm code */
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      ((mmio) = (addr))
+#else
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      do { } while (0)
+#endif
 
 	/* timekeeping specific data, ignore */
 	cycle_t cycle_interval;
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index c4079b4..1c47a34 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -36,7 +36,6 @@
 
 /* operations shared over more than one file */
 int coda_open(struct inode *i, struct file *f);
-int coda_flush(struct file *f, fl_owner_t id);
 int coda_release(struct inode *i, struct file *f);
 int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
 int coda_revalidate_inode(struct dentry *);
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index aa8f454..07ae8f8 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -33,9 +33,6 @@
 int venus_lookup(struct super_block *sb, struct CodaFid *fid, 
 		 const char *name, int length, int *type, 
 		 struct CodaFid *resfid);
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
-		vuid_t uid);
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags);
 int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
 		vuid_t uid);
 int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index a03e9398..14f74942 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -23,3 +23,21 @@
  * code
  */
 #define uninitialized_var(x) x = x
+
+#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+/* Mark functions as cold. gcc will assume any path leading to a call
+   to them will be unlikely.  This means a lot of manual unlikely()s
+   are unnecessary now for any paths leading to the usual suspects
+   like BUG(), printk(), panic() etc. [but let's keep them for now for
+   older compilers]
+
+   Early snapshots of gcc 4.3 don't support this and we can't detect this
+   in the preprocessor, but we can live with this because they're unreleased.
+   Maketime probing would be overkill here.
+
+   gcc also has a __attribute__((__hot__)) to move hot functions into
+   a special section, but I don't see any sense in this right now in
+   the kernel context */
+#define __cold			__attribute__((__cold__))
+
+#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 8287a72..12a1291 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -174,4 +174,13 @@
 # define __attribute_const__	/* unimplemented */
 #endif
 
+/*
+ * Tell gcc if a function is cold. The compiler will assume any path
+ * directly leading to the call is unlikely.
+ */
+
+#ifndef __cold
+#define __cold
+#endif
+
 #endif /* __LINUX_COMPILER_H */
diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h
index 0fe7cdf..98c69ab 100644
--- a/include/linux/dcookies.h
+++ b/include/linux/dcookies.h
@@ -12,6 +12,7 @@
 
 #ifdef CONFIG_PROFILING
  
+#include <linux/dcache.h>
 #include <linux/types.h>
  
 struct dcookie_user;
diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
index 0311bad..5834e84 100644
--- a/include/linux/elf-em.h
+++ b/include/linux/elf-em.h
@@ -20,7 +20,8 @@
 #define EM_PARISC	15	/* HPPA */
 #define EM_SPARC32PLUS	18	/* Sun's "v8plus" */
 #define EM_PPC		20	/* PowerPC */
-#define EM_PPC64	21       /* PowerPC64 */
+#define EM_PPC64	21	 /* PowerPC64 */
+#define EM_SPU		23	/* Cell BE SPU */
 #define EM_SH		42	/* SuperH */
 #define EM_SPARCV9	43	/* SPARC v9 64-bit */
 #define EM_IA_64	50	/* HP/Intel IA-64 */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index aa83d41..b690148 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -115,9 +115,10 @@
 #define I2C_DRIVERID_KS0127	86	/* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87	/* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208	88	/* Intersil ISL1208 RTC		*/
-#define I2C_DRIVERID_WM8731		89	/* Wolfson WM8731 audio codec */
-#define I2C_DRIVERID_WM8750		90	/* Wolfson WM8750 audio codec */
-#define I2C_DRIVERID_WM8753		91	/* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_WM8731	89	/* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750	90	/* Wolfson WM8750 audio codec */
+#define I2C_DRIVERID_WM8753	91	/* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_LM4857 	92 	/* LM4857 Audio Amplifier */
 
 #define I2C_DRIVERID_I2CDEV	900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
diff --git a/include/linux/init.h b/include/linux/init.h
index 5b52853..f0d0e32 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -40,10 +40,10 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init		__attribute__ ((__section__ (".init.text")))
+#define __init		__attribute__ ((__section__ (".init.text"))) __cold
 #define __initdata	__attribute__ ((__section__ (".init.data")))
 #define __exitdata	__attribute__ ((__section__(".exit.data")))
-#define __exit_call	__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+#define __exit_call	__attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) __cold
 
 /* modpost check for section mismatches during the kernel build.
  * A section mismatch happens when there are references from a
@@ -59,9 +59,9 @@
 #define __initdata_refok          __attribute__ ((__section__ (".data.init.refok")))
 
 #ifdef MODULE
-#define __exit		__attribute__ ((__section__(".exit.text")))
+#define __exit		__attribute__ ((__section__(".exit.text"))) __cold
 #else
-#define __exit		__attribute_used__ __attribute__ ((__section__(".exit.text")))
+#define __exit		__attribute_used__ __attribute__ ((__section__(".exit.text"))) __cold
 #endif
 
 /* For assembly routines */
diff --git a/include/linux/input.h b/include/linux/input.h
index 18c98b5..e02c6a6 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -344,7 +344,8 @@
 #define KEY_BRIGHTNESSUP	225
 #define KEY_MEDIA		226
 
-#define KEY_SWITCHVIDEOMODE	227
+#define KEY_SWITCHVIDEOMODE	227	/* Cycle between available video
+					   outputs (Monitor/LCD/TV-out/etc) */
 #define KEY_KBDILLUMTOGGLE	228
 #define KEY_KBDILLUMDOWN	229
 #define KEY_KBDILLUMUP		230
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index 2eaa142..baf2938 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -53,6 +53,14 @@
 	return IOPRIO_NORM;
 }
 
+static inline int task_ioprio_class(struct task_struct *task)
+{
+	if (ioprio_valid(task->ioprio))
+		return IOPRIO_PRIO_CLASS(task->ioprio);
+
+	return IOPRIO_CLASS_BE;
+}
+
 static inline int task_nice_ioprio(struct task_struct *task)
 {
 	return (task_nice(task) + 20) / 5;
diff --git a/include/linux/irda.h b/include/linux/irda.h
index 8e37357..28f88ec 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -77,6 +77,7 @@
 	IRDA_ACT200L_DONGLE      = 10,
 	IRDA_MA600_DONGLE        = 11,
 	IRDA_TOIM3232_DONGLE     = 12,
+	IRDA_EP7211_DONGLE       = 13,
 } IRDA_DONGLE;
 
 /* Protocol types to be used for SOCK_DGRAM */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 1eb9cde..4300bb4 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -106,7 +106,7 @@
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(long time);
 NORET_TYPE void panic(const char * fmt, ...)
-	__attribute__ ((NORET_AND format (printf, 1, 2)));
+	__attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
 extern void oops_enter(void);
 extern void oops_exit(void);
 extern int oops_may_print(void);
@@ -155,14 +155,14 @@
 asmlinkage int vprintk(const char *fmt, va_list args)
 	__attribute__ ((format (printf, 1, 0)));
 asmlinkage int printk(const char * fmt, ...)
-	__attribute__ ((format (printf, 1, 2)));
+	__attribute__ ((format (printf, 1, 2))) __cold;
 #else
 static inline int vprintk(const char *s, va_list args)
 	__attribute__ ((format (printf, 1, 0)));
 static inline int vprintk(const char *s, va_list args) { return 0; }
 static inline int printk(const char *s, ...)
 	__attribute__ ((format (printf, 1, 2)));
-static inline int printk(const char *s, ...) { return 0; }
+static inline int __cold printk(const char *s, ...) { return 0; }
 #endif
 
 unsigned long int_sqrt(unsigned long);
@@ -212,7 +212,7 @@
 #define TAINT_USER			(1<<6)
 #define TAINT_DIE			(1<<7)
 
-extern void dump_stack(void);
+extern void dump_stack(void) __cold;
 
 enum {
 	DUMP_PREFIX_NONE,
diff --git a/include/linux/lcd.h b/include/linux/lcd.h
index 598793c..1d37978 100644
--- a/include/linux/lcd.h
+++ b/include/linux/lcd.h
@@ -62,8 +62,8 @@
 	struct mutex update_lock;
 	/* The framebuffer notifier block */
 	struct notifier_block fb_notif;
-	/* The class device structure */
-	struct class_device class_dev;
+
+	struct device dev;
 };
 
 static inline void lcd_set_power(struct lcd_device *ld, int power)
@@ -75,9 +75,15 @@
 }
 
 extern struct lcd_device *lcd_device_register(const char *name,
-	void *devdata, struct lcd_ops *ops);
+	struct device *parent, void *devdata, struct lcd_ops *ops);
 extern void lcd_device_unregister(struct lcd_device *ld);
 
-#define to_lcd_device(obj) container_of(obj, struct lcd_device, class_dev)
+#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
+
+static inline void * lcd_get_data(struct lcd_device *ld_dev)
+{
+	return dev_get_drvdata(&ld_dev->dev);
+}
+
 
 #endif
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 494bed7..4211750 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -15,7 +15,6 @@
 #include <linux/list.h>
 
 struct device;
-struct class_device;
 /*
  * LED Core
  */
@@ -37,7 +36,7 @@
 	void		(*brightness_set)(struct led_classdev *led_cdev,
 					  enum led_brightness brightness);
 
-	struct class_device	*class_dev;
+	struct device		*dev;
 	struct list_head	 node;			/* LED Device list */
 	char			*default_trigger;	/* Trigger to use */
 
@@ -109,4 +108,18 @@
 #define ledtrig_ide_activity() do {} while(0)
 #endif
 
+/* For the leds-gpio driver */
+struct gpio_led {
+	const char *name;
+	char *default_trigger;
+	unsigned 	gpio;
+	u8 		active_low;
+};
+
+struct gpio_led_platform_data {
+	int 		num_leds;
+	struct gpio_led *leds;
+};
+
+
 #endif		/* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 47cd2a1..be5a439 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -323,6 +323,7 @@
 	AC_ERR_INVALID		= (1 << 7), /* invalid argument */
 	AC_ERR_OTHER		= (1 << 8), /* unknown */
 	AC_ERR_NODEV_HINT	= (1 << 9), /* polling device detection hint */
+	AC_ERR_NCQ		= (1 << 10), /* marker for offending NCQ qc */
 };
 
 /* forward declarations */
@@ -530,6 +531,7 @@
 	unsigned int		cbl;	/* cable type; ATA_CBL_xxx */
 	unsigned int		hw_sata_spd_limit;
 	unsigned int		sata_spd_limit;	/* SATA PHY speed limit */
+	unsigned int		sata_spd;	/* current SATA PHY speed */
 
 	/* record runtime error info, protected by host lock */
 	struct ata_eh_info	eh_info;
@@ -563,6 +565,9 @@
 	pm_message_t		pm_mesg;
 	int			*pm_result;
 
+	struct timer_list	fastdrain_timer;
+	unsigned long		fastdrain_cnt;
+
 	void			*private_data;
 
 #ifdef CONFIG_ATA_ACPI
@@ -619,9 +624,8 @@
 	u8 (*irq_on) (struct ata_port *);
 	u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
 
-	u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
-	void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
-			   u32 val);
+	int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+	int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 	int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
 	int (*port_resume) (struct ata_port *ap);
@@ -764,7 +768,8 @@
  */
 extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+			  u8 pmp, int is_cmd, u8 *fis);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
@@ -909,27 +914,21 @@
 /*
  * ata_eh_info helpers
  */
-#define ata_ehi_push_desc(ehi, fmt, args...) do { \
-	(ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
-				     ATA_EH_DESC_LEN - (ehi)->desc_len, \
-				     fmt , ##args); \
-} while (0)
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
 
-#define ata_ehi_clear_desc(ehi) do { \
-	(ehi)->desc[0] = '\0'; \
-	(ehi)->desc_len = 0; \
-} while (0)
-
-static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
+static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
 {
-	ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
+	ehi->flags |= ATA_EHI_RESUME_LINK;
 	ehi->action |= ATA_EH_SOFTRESET;
 	ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
 
 static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
-	__ata_ehi_hotplugged(ehi);
+	ata_ehi_schedule_probe(ehi);
+	ehi->flags |= ATA_EHI_HOTPLUGGED;
 	ehi->err_mask |= AC_ERR_ATA_BUS;
 }
 
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9820ca1..4a616d7 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -575,7 +575,7 @@
 
 	/* The TX queue control structures */
 	unsigned int			egress_subqueue_count;
-	struct net_device_subqueue	egress_subqueue[0];
+	struct net_device_subqueue	egress_subqueue[1];
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
diff --git a/include/linux/of.h b/include/linux/of.h
new file mode 100644
index 0000000..47734ff
--- /dev/null
+++ b/include/linux/of.h
@@ -0,0 +1,61 @@
+#ifndef _LINUX_OF_H
+#define _LINUX_OF_H
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh and other computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC64 by David S. Miller
+ * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+
+#include <asm/bitops.h>
+#include <asm/prom.h>
+
+/* flag descriptions */
+#define OF_DYNAMIC	1 /* node and properties were allocated via kmalloc */
+#define OF_DETACHED	2 /* node has been detached from the device tree */
+
+#define OF_BAD_ADDR	((u64)-1)
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+	const char *name);
+#define for_each_node_by_name(dn, name) \
+	for (dn = of_find_node_by_name(NULL, name); dn; \
+	     dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+	const char *type);
+#define for_each_node_by_type(dn, type) \
+	for (dn = of_find_node_by_type(NULL, type); dn; \
+	     dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+	const char *type, const char *compat);
+#define for_each_compatible_node(dn, type, compatible) \
+	for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+	     dn = of_find_compatible_node(dn, type, compatible))
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+					     struct device_node *prev);
+extern struct property *of_find_property(const struct device_node *np,
+					 const char *name,
+					 int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+				   const char *);
+extern const void *of_get_property(const struct device_node *node,
+				const char *name,
+				int *lenp);
+#define get_property(a, b, c)	of_get_property((a), (b), (c))
+extern int of_n_addr_cells(struct device_node *np);
+extern int of_n_size_cells(struct device_node *np);
+
+#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
new file mode 100644
index 0000000..91bf84b
--- /dev/null
+++ b/include/linux/of_device.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_OF_DEVICE_H
+#define _LINUX_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/of_device.h>
+
+#define	to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_node(
+	const struct of_device_id *matches, const struct device_node *node);
+extern const struct of_device_id *of_match_device(
+	const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
new file mode 100644
index 0000000..448f70b
--- /dev/null
+++ b/include/linux/of_platform.h
@@ -0,0 +1,57 @@
+#ifndef _LINUX_OF_PLATFORM_H
+#define _LINUX_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type) (or ISA, EBUS and SBUS
+ * busses on sparc).
+ */
+struct of_platform_driver
+{
+	const char		*name;
+	const struct of_device_id	*match_table;
+	struct module		*owner;
+
+	int	(*probe)(struct of_device* dev,
+			 const struct of_device_id *match);
+	int	(*remove)(struct of_device* dev);
+
+	int	(*suspend)(struct of_device* dev, pm_message_t state);
+	int	(*resume)(struct of_device* dev);
+	int	(*shutdown)(struct of_device* dev);
+
+	struct device_driver	driver;
+};
+#define	to_of_platform_driver(drv) \
+	container_of(drv,struct of_platform_driver, driver)
+
+#include <asm/of_platform.h>
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+
+extern int of_bus_type_init(struct bus_type *bus, const char *name);
+
+#endif	/* _LINUX_OF_PLATFORM_H */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 0d514b2..041bb31 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -17,6 +17,26 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
  
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ * These #defines live in this file so that arch-specific
+ * buffer sync'ing code can access them.
+ */
+#define ESCAPE_CODE			~0UL
+#define CTX_SWITCH_CODE			1
+#define CPU_SWITCH_CODE			2
+#define COOKIE_SWITCH_CODE		3
+#define KERNEL_ENTER_SWITCH_CODE	4
+#define KERNEL_EXIT_SWITCH_CODE		5
+#define MODULE_LOADED_CODE		6
+#define CTX_TGID_CODE			7
+#define TRACE_BEGIN_CODE		8
+#define TRACE_END_CODE			9
+#define XEN_ENTER_SWITCH_CODE		10
+#define SPU_PROFILING_CODE		11
+#define SPU_CTX_SWITCH_CODE		12
+
 struct super_block;
 struct dentry;
 struct file_operations;
@@ -35,6 +55,14 @@
 	int (*start)(void);
 	/* Stop delivering interrupts. */
 	void (*stop)(void);
+	/* Arch-specific buffer sync functions.
+	 * Return value = 0:  Success
+	 * Return value = -1: Failure
+	 * Return value = 1:  Run generic sync function
+	 */
+	int (*sync_start)(void);
+	int (*sync_stop)(void);
+
 	/* Initiate a stack backtrace. Optional. */
 	void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
 	/* CPU identification string. */
@@ -56,6 +84,13 @@
 void oprofile_arch_exit(void);
 
 /**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
+/**
  * Add a sample. This may be called from any context. Pass
  * smp_processor_id() as cpu.
  */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index b15c649..ced4d3f 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2040,6 +2040,8 @@
 #define PCI_DEVICE_ID_ALTIMA_AC9100	0x03ea
 #define PCI_DEVICE_ID_ALTIMA_AC1003	0x03eb
 
+#define PCI_VENDOR_ID_LENOVO		0x17aa
+
 #define PCI_VENDOR_ID_ARECA		0x17d3
 #define PCI_DEVICE_ID_ARECA_1110	0x1110
 #define PCI_DEVICE_ID_ARECA_1120	0x1120
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
index 81e9299..f3f4f28 100644
--- a/include/linux/resume-trace.h
+++ b/include/linux/resume-trace.h
@@ -2,6 +2,7 @@
 #define RESUME_TRACE_H
 
 #ifdef CONFIG_PM_TRACE
+#include <asm/resume-trace.h>
 
 extern int pm_trace_enabled;
 
@@ -9,20 +10,10 @@
 extern void set_trace_device(struct device *);
 extern void generate_resume_trace(void *tracedata, unsigned int user);
 
-#define TRACE_DEVICE(dev) set_trace_device(dev)
-#define TRACE_RESUME(user) do {					\
-	if (pm_trace_enabled) {					\
-		void *tracedata;				\
-		asm volatile("movl $1f,%0\n"			\
-			".section .tracedata,\"a\"\n"		\
-			"1:\t.word %c1\n"			\
-			"\t.long %c2\n"				\
-			".previous"				\
-			:"=r" (tracedata)			\
-			: "i" (__LINE__), "i" (__FILE__));	\
-		generate_resume_trace(tracedata, user);		\
-	}							\
-} while (0)
+#define TRACE_DEVICE(dev) do { \
+	if (pm_trace_enabled) \
+		set_trace_device(dev); \
+	} while(0)
 
 #else
 
diff --git a/include/linux/serio.h b/include/linux/serio.h
index d9377ce..9f38250 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -210,5 +210,6 @@
 #define SERIO_TOUCHRIGHT	0x32
 #define SERIO_TOUCHWIN	0x33
 #define SERIO_TAOSEVM	0x34
+#define SERIO_FUJITSU	0x35
 
 #endif
diff --git a/include/linux/signal.h b/include/linux/signal.h
index ea91abe..0ae3388 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -237,12 +237,15 @@
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern int show_unhandled_signals;
 
 struct pt_regs;
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
 
 extern struct kmem_cache *sighand_cachep;
 
+int unhandled_signal(struct task_struct *tsk, int sig);
+
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
  * or to the process as a whole (Linux thread group).  How the signal
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 7d0ecc1..d859354 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -40,7 +40,7 @@
  */
 #define ZERO_SIZE_PTR ((void *)16)
 
-#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) < \
+#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
 				(unsigned long)ZERO_SIZE_PTR)
 
 /*
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 07f7e4c..124270d 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -160,7 +160,7 @@
 #define SLUB_DMA __GFP_DMA
 #else
 /* Disable DMA functionality */
-#define SLUB_DMA 0
+#define SLUB_DMA (__force gfp_t)0
 #endif
 
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index 3387e44..334d314 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -16,6 +16,20 @@
 	u16	vref_delay_usecs;	/* 0 for external vref; etc */
 	int	keep_vref_on:1;		/* set to keep vref on for differential
 					 * measurements as well */
+
+	/* Settling time of the analog signals; a function of Vcc and the
+	 * capacitance on the X/Y drivers.  If set to non-zero, two samples
+	 * are taken with settle_delay us apart, and the second one is used.
+	 * ~150 uSec with 0.01uF caps.
+	 */
+	u16	settle_delay_usecs;
+
+	/* If set to non-zero, after samples are taken this delay is applied
+	 * and penirq is rechecked, to help avoid false events.  This value
+	 * is affected by the material used to build the touch layer.
+	 */
+	u16	penirq_recheck_delay_usecs;
+
 	u16	x_plate_ohms;
 	u16	y_plate_ohms;
 
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 7a8b1e3..61def7c8 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -549,7 +549,7 @@
 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
 				 __u32 __user *ustatus);
 asmlinkage long sys_spu_create(const char __user *name,
-		unsigned int flags, mode_t mode);
+		unsigned int flags, mode_t mode, int fd);
 
 asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
 			    unsigned dev);
diff --git a/include/linux/time.h b/include/linux/time.h
index ec3b0ce..e6aea51 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 
 #ifdef __KERNEL__
+# include <linux/cache.h>
 # include <linux/seqlock.h>
 #endif
 
@@ -94,6 +95,8 @@
 extern seqlock_t xtime_lock __attribute__((weak));
 
 extern unsigned long read_persistent_clock(void);
+extern int update_persistent_clock(struct timespec now);
+extern int no_sync_cmos_clock __read_mostly;
 void timekeeping_init(void);
 
 static inline unsigned long get_seconds(void)
diff --git a/include/linux/timex.h b/include/linux/timex.h
index da929db..37ac3ff 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -224,66 +224,6 @@
 	__x < 0 ? -(-__x >> __s) : __x >> __s;	\
 })
 
-
-#ifdef CONFIG_TIME_INTERPOLATION
-
-#define TIME_SOURCE_CPU 0
-#define TIME_SOURCE_MMIO64 1
-#define TIME_SOURCE_MMIO32 2
-#define TIME_SOURCE_FUNCTION 3
-
-/* For proper operations time_interpolator clocks must run slightly slower
- * than the standard clock since the interpolator may only correct by having
- * time jump forward during a tick. A slower clock is usually a side effect
- * of the integer divide of the nanoseconds in a second by the frequency.
- * The accuracy of the division can be increased by specifying a shift.
- * However, this may cause the clock not to be slow enough.
- * The interpolator will self-tune the clock by slowing down if no
- * resets occur or speeding up if the time jumps per analysis cycle
- * become too high.
- *
- * Setting jitter compensates for a fluctuating timesource by comparing
- * to the last value read from the timesource to insure that an earlier value
- * is not returned by a later call. The price to pay
- * for the compensation is that the timer routines are not as scalable anymore.
- */
-
-struct time_interpolator {
-	u16 source;			/* time source flags */
-	u8 shift;			/* increases accuracy of multiply by shifting. */
-				/* Note that bits may be lost if shift is set too high */
-	u8 jitter;			/* if set compensate for fluctuations */
-	u32 nsec_per_cyc;		/* set by register_time_interpolator() */
-	void *addr;			/* address of counter or function */
-	cycles_t mask;			/* mask the valid bits of the counter */
-	unsigned long offset;		/* nsec offset at last update of interpolator */
-	u64 last_counter;		/* counter value in units of the counter at last update */
-	cycles_t last_cycle;		/* Last timer value if TIME_SOURCE_JITTER is set */
-	u64 frequency;			/* frequency in counts/second */
-	long drift;			/* drift in parts-per-million (or -1) */
-	unsigned long skips;		/* skips forward */
-	unsigned long ns_skipped;	/* nanoseconds skipped */
-	struct time_interpolator *next;
-};
-
-extern void register_time_interpolator(struct time_interpolator *);
-extern void unregister_time_interpolator(struct time_interpolator *);
-extern void time_interpolator_reset(void);
-extern unsigned long time_interpolator_get_offset(void);
-extern void time_interpolator_update(long delta_nsec);
-
-#else /* !CONFIG_TIME_INTERPOLATION */
-
-static inline void time_interpolator_reset(void)
-{
-}
-
-static inline void time_interpolator_update(long delta_nsec)
-{
-}
-
-#endif /* !CONFIG_TIME_INTERPOLATION */
-
 #define TICK_LENGTH_SHIFT	32
 
 #ifdef CONFIG_NO_HZ
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index d16a2b5..c66c8a3 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -60,6 +60,7 @@
 #include <linux/compiler.h> /* need __user */
 #else
 #define __user
+#include <sys/time.h>
 #endif
 #include <linux/types.h>
 
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index c2b10ca..89338b4 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -58,6 +58,13 @@
 /*
  *	Lowlevel-APIs (not for driver use!)
  */
+
+static inline size_t get_vm_area_size(const struct vm_struct *area)
+{
+	/* return actual size without guard page */
+	return area->size - PAGE_SIZE;
+}
+
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 					unsigned long start, unsigned long end);
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index aa49dda..fd0a6c4 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -43,6 +43,7 @@
 struct snd_akm4xxx_dac_channel {
 	char *name;		/* mixer volume name */
 	unsigned int num_channels;
+	char *switch_name;		/* mixer switch*/
 };
 
 /* ADC labels and channels */
diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h
index 685928e..353910c 100644
--- a/include/sound/cs46xx.h
+++ b/include/sound/cs46xx.h
@@ -1723,6 +1723,10 @@
 	struct snd_cs46xx_pcm *playback_pcm;
 	unsigned int play_ctl;
 #endif
+
+#ifdef CONFIG_PM
+	u32 *saved_regs;
+#endif
 };
 
 int snd_cs46xx_create(struct snd_card *card,
diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h
index da934de..d9da9e5 100644
--- a/include/sound/cs46xx_dsp_spos.h
+++ b/include/sound/cs46xx_dsp_spos.h
@@ -107,6 +107,7 @@
 	char scb_name[DSP_MAX_SCB_NAME];
 	u32 address;
 	int index;
+	u32 *data;
 
 	struct dsp_scb_descriptor * sub_list_ptr;
 	struct dsp_scb_descriptor * next_scb_ptr;
@@ -127,6 +128,7 @@
 	int size;
 	u32 address;
 	int index;
+	u32 *data;
 };
 
 struct dsp_pcm_channel_descriptor {
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 23e45a4..529d0a5 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1120,6 +1120,16 @@
 /************************************************************************************************/
 /* EMU1010m HANA Destinations									*/
 /************************************************************************************************/
+/* 32-bit destinations of signal in the Hana FPGA. Destinations are either
+ * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
+ * - 16 x EMU_DST_ALICE2_EMU32_X.
+ */
+/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */
+/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture.
+ * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on
+ * setup of mixer control for each destination - see emumixer.c -
+ * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
+ */
 #define EMU_DST_ALICE2_EMU32_0	0x000f	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_1	0x0000	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_2	0x0001	/* 16 EMU32 channels to Alice2 +0 to +0xf */
@@ -1199,6 +1209,12 @@
 /************************************************************************************************/
 /* EMU1010m HANA Sources									*/
 /************************************************************************************************/
+/* 32-bit sources of signal in the Hana FPGA. The sources are routed to
+ * destinations using mixer control for each destination - see emumixer.c
+ * Sources are either physical inputs of FPGA,
+ * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A +
+ * 16 x EMU_SRC_ALICE_EMU32B
+ */
 #define EMU_SRC_SILENCE		0x0000	/* Silence */
 #define EMU_SRC_DOCK_MIC_A1	0x0100	/* Audio Dock Mic A, 1st or 48kHz only */
 #define EMU_SRC_DOCK_MIC_A2	0x0101	/* Audio Dock Mic A, 2nd or 96kHz */
diff --git a/include/sound/sb.h b/include/sound/sb.h
index 2dd5c8e..3ad854b 100644
--- a/include/sound/sb.h
+++ b/include/sound/sb.h
@@ -38,6 +38,7 @@
 	SB_HW_ALS100,		/* Avance Logic ALS100 chip */
 	SB_HW_ALS4000,		/* Avance Logic ALS4000 chip */
 	SB_HW_DT019X,		/* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+	SB_HW_CS5530,		/* Cyrix/NatSemi 5530 VSA1 */
 };
 
 #define SB_OPEN_PCM			0x01
diff --git a/include/sound/version.h b/include/sound/version.h
index 8e5b2f0..6bbcfef 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
 #define CONFIG_SND_VERSION "1.0.14"
-#define CONFIG_SND_DATE " (Thu May 31 09:03:25 2007 UTC)"
+#define CONFIG_SND_DATE " (Fri Jul 20 09:12:58 2007 UTC)"
diff --git a/include/sound/wavefront_fx.h b/include/sound/wavefront_fx.h
deleted file mode 100644
index cec92b1..0000000
--- a/include/sound/wavefront_fx.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __SOUND_WAVEFRONT_FX_H
-#define __SOUND_WAVEFRONT_FX_H
-
-extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
-extern void snd_wavefront_fx_ioctl  (snd_synth_t *sdev, 
-				     unsigned int cmd, 
-				     unsigned long arg);
-
-#endif  __SOUND_WAVEFRONT_FX_H
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 1bf093d..359645c 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -304,7 +304,7 @@
 
 int audit_match_class(int class, unsigned syscall)
 {
-	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32)))
+	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
 		return 0;
 	if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class]))
 		return 0;
@@ -456,6 +456,13 @@
 		case AUDIT_DEVMINOR:
 		case AUDIT_EXIT:
 		case AUDIT_SUCCESS:
+			/* bit ops are only useful on syscall args */
+			if (f->op == AUDIT_BIT_MASK ||
+						f->op == AUDIT_BIT_TEST) {
+				err = -EINVAL;
+				goto exit_free;
+			}
+			break;
 		case AUDIT_ARG0:
 		case AUDIT_ARG1:
 		case AUDIT_ARG2:
@@ -1566,6 +1573,10 @@
 		return (left > right);
 	case AUDIT_GREATER_THAN_OR_EQUAL:
 		return (left >= right);
+	case AUDIT_BIT_MASK:
+		return (left & right);
+	case AUDIT_BIT_TEST:
+		return ((left & right) == right);
 	}
 	BUG();
 	return 0;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 145cbb7..bde1124 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -173,12 +173,6 @@
 	int	fd[2];
 };
 
-struct audit_aux_data_path {
-	struct audit_aux_data	d;
-	struct dentry		*dentry;
-	struct vfsmount		*mnt;
-};
-
 struct audit_aux_data_pids {
 	struct audit_aux_data	d;
 	pid_t			target_pid[AUDIT_AUX_PIDS];
@@ -654,12 +648,6 @@
 	struct audit_aux_data *aux;
 
 	while ((aux = context->aux)) {
-		if (aux->type == AUDIT_AVC_PATH) {
-			struct audit_aux_data_path *axi = (void *)aux;
-			dput(axi->dentry);
-			mntput(axi->mnt);
-		}
-
 		context->aux = aux->next;
 		kfree(aux);
 	}
@@ -995,7 +983,7 @@
 		case AUDIT_IPC: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab, 
-				 "ouid=%u ogid=%u mode=%x",
+				 "ouid=%u ogid=%u mode=%#o",
 				 axi->uid, axi->gid, axi->mode);
 			if (axi->osid != 0) {
 				char *ctx = NULL;
@@ -1014,7 +1002,7 @@
 		case AUDIT_IPC_SET_PERM: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab,
-				"qbytes=%lx ouid=%u ogid=%u mode=%x",
+				"qbytes=%lx ouid=%u ogid=%u mode=%#o",
 				axi->qbytes, axi->uid, axi->gid, axi->mode);
 			break; }
 
@@ -1038,11 +1026,6 @@
 			audit_log_hex(ab, axs->a, axs->len);
 			break; }
 
-		case AUDIT_AVC_PATH: {
-			struct audit_aux_data_path *axi = (void *)aux;
-			audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
-			break; }
-
 		case AUDIT_FD_PAIR: {
 			struct audit_aux_data_fd_pair *axs = (void *)aux;
 			audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
@@ -1991,36 +1974,6 @@
 }
 
 /**
- * audit_avc_path - record the granting or denial of permissions
- * @dentry: dentry to record
- * @mnt: mnt to record
- *
- * Returns 0 for success or NULL context or < 0 on error.
- *
- * Called from security/selinux/avc.c::avc_audit()
- */
-int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
-{
-	struct audit_aux_data_path *ax;
-	struct audit_context *context = current->audit_context;
-
-	if (likely(!context))
-		return 0;
-
-	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
-	if (!ax)
-		return -ENOMEM;
-
-	ax->dentry = dget(dentry);
-	ax->mnt = mntget(mnt);
-
-	ax->d.type = AUDIT_AVC_PATH;
-	ax->d.next = context->aux;
-	context->aux = (void *)ax;
-	return 0;
-}
-
-/**
  * audit_signal_info - record signal info for shutting down audit subsystem
  * @sig: signal value
  * @t: task being signaled
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 72d0342..eb1ddeb 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -558,7 +558,8 @@
  */
 static int hrtimer_switch_to_hres(void)
 {
-	struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
+	int cpu = smp_processor_id();
+	struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu);
 	unsigned long flags;
 
 	if (base->hres_active)
@@ -568,6 +569,8 @@
 
 	if (tick_init_highres()) {
 		local_irq_restore(flags);
+		printk(KERN_WARNING "Could not switch to high resolution "
+				    "mode on CPU %d\n", cpu);
 		return 0;
 	}
 	base->hres_active = 1;
@@ -683,6 +686,7 @@
 	struct rb_node **link = &base->active.rb_node;
 	struct rb_node *parent = NULL;
 	struct hrtimer *entry;
+	int leftmost = 1;
 
 	/*
 	 * Find the right place in the rbtree:
@@ -694,18 +698,19 @@
 		 * We dont care about collisions. Nodes with
 		 * the same expiry time stay together.
 		 */
-		if (timer->expires.tv64 < entry->expires.tv64)
+		if (timer->expires.tv64 < entry->expires.tv64) {
 			link = &(*link)->rb_left;
-		else
+		} else {
 			link = &(*link)->rb_right;
+			leftmost = 0;
+		}
 	}
 
 	/*
 	 * Insert the timer to the rbtree and check whether it
 	 * replaces the first pending timer
 	 */
-	if (!base->first || timer->expires.tv64 <
-	    rb_entry(base->first, struct hrtimer, node)->expires.tv64) {
+	if (leftmost) {
 		/*
 		 * Reprogram the clock event device. When the timer is already
 		 * expired hrtimer_enqueue_reprogram has either called the
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index b4f1674..50b81b9 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -19,7 +19,15 @@
 static int irq_affinity_read_proc(char *page, char **start, off_t off,
 				  int count, int *eof, void *data)
 {
-	int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity);
+	struct irq_desc *desc = irq_desc + (long)data;
+	cpumask_t *mask = &desc->affinity;
+	int len;
+
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+	if (desc->status & IRQ_MOVE_PENDING)
+		mask = &desc->pending_mask;
+#endif
+	len = cpumask_scnprintf(page, count, *mask);
 
 	if (count - len < 2)
 		return -EINVAL;
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 2565e1b..d0e5c48 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -65,8 +65,8 @@
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
-extern const char __start_notes __attribute__((weak));
-extern const char __stop_notes __attribute__((weak));
+extern const void __start_notes __attribute__((weak));
+extern const void __stop_notes __attribute__((weak));
 #define	notes_size (&__stop_notes - &__start_notes)
 
 static ssize_t notes_read(struct kobject *kobj, struct bin_attribute *bin_attr,
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 7358609..c1a106d 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -57,7 +57,7 @@
 
 config PM_TRACE
 	bool "Suspend/resume event tracing"
-	depends on PM_DEBUG && X86_32 && EXPERIMENTAL
+	depends on PM_DEBUG && X86 && EXPERIMENTAL
 	default n
 	---help---
 	This enables some cheesy code to save the last PM event point in the
diff --git a/kernel/signal.c b/kernel/signal.c
index 39d1227..ef8156a 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -255,6 +255,16 @@
 	}
 }
 
+int unhandled_signal(struct task_struct *tsk, int sig)
+{
+	if (is_init(tsk))
+		return 1;
+	if (tsk->ptrace & PT_PTRACED)
+		return 0;
+	return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
+		(tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
+}
+
 
 /* Notify the system that a driver wants to block all signals for this
  * process, and wants to be notified if any signals at all were to be
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 2222998..ddebf3f 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1203,6 +1203,16 @@
 };
 
 static ctl_table debug_table[] = {
+#ifdef CONFIG_X86
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "exception-trace",
+		.data		= &show_unhandled_signals,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+#endif
 	{ .ctl_name = 0 }
 };
 
diff --git a/kernel/time.c b/kernel/time.c
index ffe1914..5b81da0 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -57,17 +57,14 @@
  */
 asmlinkage long sys_time(time_t __user * tloc)
 {
-	/*
-	 * We read xtime.tv_sec atomically - it's updated
-	 * atomically by update_wall_time(), so no need to
-	 * even read-lock the xtime seqlock:
-	 */
-	time_t i = xtime.tv_sec;
+	time_t i;
+	struct timespec tv;
 
-	smp_rmb(); /* sys_time() results are coherent */
+	getnstimeofday(&tv);
+	i = tv.tv_sec;
 
 	if (tloc) {
-		if (put_user(i, tloc))
+		if (put_user(i,tloc))
 			i = -EFAULT;
 	}
 	return i;
@@ -136,7 +133,6 @@
 	write_seqlock_irq(&xtime_lock);
 	wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
 	xtime.tv_sec += sys_tz.tz_minuteswest * 60;
-	time_interpolator_reset();
 	write_sequnlock_irq(&xtime_lock);
 	clock_was_set();
 }
@@ -309,92 +305,6 @@
 }
 EXPORT_SYMBOL(timespec_trunc);
 
-#ifdef CONFIG_TIME_INTERPOLATION
-void getnstimeofday (struct timespec *tv)
-{
-	unsigned long seq,sec,nsec;
-
-	do {
-		seq = read_seqbegin(&xtime_lock);
-		sec = xtime.tv_sec;
-		nsec = xtime.tv_nsec+time_interpolator_get_offset();
-	} while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-	while (unlikely(nsec >= NSEC_PER_SEC)) {
-		nsec -= NSEC_PER_SEC;
-		++sec;
-	}
-	tv->tv_sec = sec;
-	tv->tv_nsec = nsec;
-}
-EXPORT_SYMBOL_GPL(getnstimeofday);
-
-int do_settimeofday (struct timespec *tv)
-{
-	time_t wtm_sec, sec = tv->tv_sec;
-	long wtm_nsec, nsec = tv->tv_nsec;
-
-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-		return -EINVAL;
-
-	write_seqlock_irq(&xtime_lock);
-	{
-		wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-		wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-		set_normalized_timespec(&xtime, sec, nsec);
-		set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-		time_adjust = 0;		/* stop active adjtime() */
-		time_status |= STA_UNSYNC;
-		time_maxerror = NTP_PHASE_LIMIT;
-		time_esterror = NTP_PHASE_LIMIT;
-		time_interpolator_reset();
-	}
-	write_sequnlock_irq(&xtime_lock);
-	clock_was_set();
-	return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-
-void do_gettimeofday (struct timeval *tv)
-{
-	unsigned long seq, nsec, usec, sec, offset;
-	do {
-		seq = read_seqbegin(&xtime_lock);
-		offset = time_interpolator_get_offset();
-		sec = xtime.tv_sec;
-		nsec = xtime.tv_nsec;
-	} while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-	usec = (nsec + offset) / 1000;
-
-	while (unlikely(usec >= USEC_PER_SEC)) {
-		usec -= USEC_PER_SEC;
-		++sec;
-	}
-
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-
-	/*
-	 * Make sure xtime.tv_sec [returned by sys_time()] always
-	 * follows the gettimeofday() result precisely. This
-	 * condition is extremely unlikely, it can hit at most
-	 * once per second:
-	 */
-	if (unlikely(xtime.tv_sec != tv->tv_sec)) {
-		unsigned long flags;
-
-		write_seqlock_irqsave(&xtime_lock, flags);
-		update_wall_time();
-		write_sequnlock_irqrestore(&xtime_lock, flags);
-	}
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-#else	/* CONFIG_TIME_INTERPOLATION */
-
 #ifndef CONFIG_GENERIC_TIME
 /*
  * Simulate gettimeofday using do_gettimeofday which only allows a timeval
@@ -410,7 +320,6 @@
 }
 EXPORT_SYMBOL_GPL(getnstimeofday);
 #endif
-#endif	/* CONFIG_TIME_INTERPOLATION */
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 438c6b7..cd91237 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -10,6 +10,7 @@
 
 #include <linux/mm.h>
 #include <linux/time.h>
+#include <linux/timer.h>
 #include <linux/timex.h>
 #include <linux/jiffies.h>
 #include <linux/hrtimer.h>
@@ -116,11 +117,6 @@
 		if (xtime.tv_sec % 86400 == 0) {
 			xtime.tv_sec--;
 			wall_to_monotonic.tv_sec++;
-			/*
-			 * The timer interpolator will make time change
-			 * gradually instead of an immediate jump by one second
-			 */
-			time_interpolator_update(-NSEC_PER_SEC);
 			time_state = TIME_OOP;
 			printk(KERN_NOTICE "Clock: inserting leap second "
 					"23:59:60 UTC\n");
@@ -130,11 +126,6 @@
 		if ((xtime.tv_sec + 1) % 86400 == 0) {
 			xtime.tv_sec++;
 			wall_to_monotonic.tv_sec--;
-			/*
-			 * Use of time interpolator for a gradual change of
-			 * time
-			 */
-			time_interpolator_update(NSEC_PER_SEC);
 			time_state = TIME_WAIT;
 			printk(KERN_NOTICE "Clock: deleting leap second "
 					"23:59:59 UTC\n");
@@ -185,12 +176,64 @@
 	return tick_length;
 }
 
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
 
-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+/* Disable the cmos update - used by virtualization and embedded */
+int no_sync_cmos_clock  __read_mostly;
+
+static void sync_cmos_clock(unsigned long dummy);
+
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
+
+static void sync_cmos_clock(unsigned long dummy)
 {
-	return;
+	struct timespec now, next;
+	int fail = 1;
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 * This code is run on a timer.  If the clock is set, that timer
+	 * may not expire at the correct time.  Thus, we adjust...
+	 */
+	if (!ntp_synced())
+		/*
+		 * Not synced, exit, do not restart a timer (if one is
+		 * running, let it run out).
+		 */
+		return;
+
+	getnstimeofday(&now);
+	if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+		fail = update_persistent_clock(now);
+
+	next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
+	if (next.tv_nsec <= 0)
+		next.tv_nsec += NSEC_PER_SEC;
+
+	if (!fail)
+		next.tv_sec = 659;
+	else
+		next.tv_sec = 0;
+
+	if (next.tv_nsec >= NSEC_PER_SEC) {
+		next.tv_sec++;
+		next.tv_nsec -= NSEC_PER_SEC;
+	}
+	mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next));
 }
 
+static void notify_cmos_timer(void)
+{
+	if (no_sync_cmos_clock)
+		mod_timer(&sync_cmos_timer, jiffies + 1);
+}
+
+#else
+static inline void notify_cmos_timer(void) { }
+#endif
+
 /* adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
  */
@@ -355,6 +398,6 @@
 	txc->stbcnt	   = 0;
 	write_sequnlock_irq(&xtime_lock);
 	do_gettimeofday(&txc->time);
-	notify_arch_cmos_timer();
+	notify_cmos_timer();
 	return(result);
 }
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 8001d37..db8e0f3 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -31,6 +31,12 @@
 static cpumask_t tick_broadcast_mask;
 static DEFINE_SPINLOCK(tick_broadcast_lock);
 
+#ifdef CONFIG_TICK_ONESHOT
+static void tick_broadcast_clear_oneshot(int cpu);
+#else
+static inline void tick_broadcast_clear_oneshot(int cpu) { }
+#endif
+
 /*
  * Debugging: see timer_list.c
  */
@@ -49,7 +55,7 @@
  */
 static void tick_broadcast_start_periodic(struct clock_event_device *bc)
 {
-	if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
+	if (bc)
 		tick_setup_periodic(bc, 1);
 }
 
@@ -99,8 +105,19 @@
 		cpu_set(cpu, tick_broadcast_mask);
 		tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
 		ret = 1;
-	}
+	} else {
+		/*
+		 * When the new device is not affected by the stop
+		 * feature and the cpu is marked in the broadcast mask
+		 * then clear the broadcast bit.
+		 */
+		if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
+			int cpu = smp_processor_id();
 
+			cpu_clear(cpu, tick_broadcast_mask);
+			tick_broadcast_clear_oneshot(cpu);
+		}
+	}
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 	return ret;
 }
@@ -299,7 +316,7 @@
 	spin_lock_irqsave(&tick_broadcast_lock, flags);
 
 	bc = tick_broadcast_device.evtdev;
-	if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+	if (bc)
 		clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
 
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -316,6 +333,8 @@
 	bc = tick_broadcast_device.evtdev;
 
 	if (bc) {
+		clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);
+
 		switch (tick_broadcast_device.mode) {
 		case TICKDEV_MODE_PERIODIC:
 			if(!cpus_empty(tick_broadcast_mask))
@@ -485,6 +504,16 @@
 	spin_unlock_irqrestore(&tick_broadcast_lock, flags);
 }
 
+/*
+ * Reset the one shot broadcast for a cpu
+ *
+ * Called with tick_broadcast_lock held
+ */
+static void tick_broadcast_clear_oneshot(int cpu)
+{
+	cpu_clear(cpu, tick_broadcast_oneshot_mask);
+}
+
 /**
  * tick_broadcast_setup_highres - setup the broadcast device for highres
  */
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index a96ec9a..77a21ab 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -318,12 +318,17 @@
 {
 	struct tick_device *td = &__get_cpu_var(tick_cpu_device);
 	unsigned long flags;
+	int broadcast = tick_resume_broadcast();
 
 	spin_lock_irqsave(&tick_device_lock, flags);
-	if (td->mode == TICKDEV_MODE_PERIODIC)
-		tick_setup_periodic(td->evtdev, 0);
-	else
-		tick_resume_oneshot();
+	clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
+
+	if (!broadcast) {
+		if (td->mode == TICKDEV_MODE_PERIODIC)
+			tick_setup_periodic(td->evtdev, 0);
+		else
+			tick_resume_oneshot();
+	}
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
@@ -360,8 +365,7 @@
 		break;
 
 	case CLOCK_EVT_NOTIFY_RESUME:
-		if (!tick_resume_broadcast())
-			tick_resume();
+		tick_resume();
 		break;
 
 	default:
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index f6997ab..0258d31 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -73,8 +73,21 @@
 	struct clock_event_device *dev = td->evtdev;
 
 	if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
-	    !tick_device_is_functional(dev))
+		    !tick_device_is_functional(dev)) {
+
+		printk(KERN_INFO "Clockevents: "
+		       "could not switch to one-shot mode:");
+		if (!dev) {
+			printk(" no tick device\n");
+		} else {
+			if (!tick_device_is_functional(dev))
+				printk(" %s is not functional.\n", dev->name);
+			else
+				printk(" %s does not support one-shot mode.\n",
+				       dev->name);
+		}
 		return -EINVAL;
+	}
 
 	td->mode = TICKDEV_MODE_ONESHOT;
 	dev->event_handler = handler;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 52db9e3..b416995 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -546,6 +546,7 @@
 {
 	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 	ktime_t now = ktime_get();
+	u64 offset;
 
 	/*
 	 * Emulate tick processing via per-CPU hrtimers:
@@ -554,8 +555,12 @@
 	ts->sched_timer.function = tick_sched_timer;
 	ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
 
-	/* Get the next period */
+	/* Get the next period (per cpu) */
 	ts->sched_timer.expires = tick_init_jiffy_update();
+	offset = ktime_to_ns(tick_period) >> 1;
+	do_div(offset, NR_CPUS);
+	offset *= smp_processor_id();
+	ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
 
 	for (;;) {
 		hrtimer_forward(&ts->sched_timer, now, tick_period);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 8969877..88c8102 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -466,10 +466,6 @@
 			second_overflow();
 		}
 
-		/* interpolator bits */
-		time_interpolator_update(clock->xtime_interval
-						>> clock->shift);
-
 		/* accumulate error between NTP and clock interval */
 		clock->error += current_tick_length();
 		clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
diff --git a/kernel/timer.c b/kernel/timer.c
index d1e8b97..6ce1952 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1349,194 +1349,6 @@
 	open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
 }
 
-#ifdef CONFIG_TIME_INTERPOLATION
-
-struct time_interpolator *time_interpolator __read_mostly;
-static struct time_interpolator *time_interpolator_list __read_mostly;
-static DEFINE_SPINLOCK(time_interpolator_lock);
-
-static inline cycles_t time_interpolator_get_cycles(unsigned int src)
-{
-	unsigned long (*x)(void);
-
-	switch (src)
-	{
-		case TIME_SOURCE_FUNCTION:
-			x = time_interpolator->addr;
-			return x();
-
-		case TIME_SOURCE_MMIO64	:
-			return readq_relaxed((void __iomem *)time_interpolator->addr);
-
-		case TIME_SOURCE_MMIO32	:
-			return readl_relaxed((void __iomem *)time_interpolator->addr);
-
-		default: return get_cycles();
-	}
-}
-
-static inline u64 time_interpolator_get_counter(int writelock)
-{
-	unsigned int src = time_interpolator->source;
-
-	if (time_interpolator->jitter)
-	{
-		cycles_t lcycle;
-		cycles_t now;
-
-		do {
-			lcycle = time_interpolator->last_cycle;
-			now = time_interpolator_get_cycles(src);
-			if (lcycle && time_after(lcycle, now))
-				return lcycle;
-
-			/* When holding the xtime write lock, there's no need
-			 * to add the overhead of the cmpxchg.  Readers are
-			 * force to retry until the write lock is released.
-			 */
-			if (writelock) {
-				time_interpolator->last_cycle = now;
-				return now;
-			}
-			/* Keep track of the last timer value returned. The use of cmpxchg here
-			 * will cause contention in an SMP environment.
-			 */
-		} while (unlikely(cmpxchg(&time_interpolator->last_cycle, lcycle, now) != lcycle));
-		return now;
-	}
-	else
-		return time_interpolator_get_cycles(src);
-}
-
-void time_interpolator_reset(void)
-{
-	time_interpolator->offset = 0;
-	time_interpolator->last_counter = time_interpolator_get_counter(1);
-}
-
-#define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
-
-unsigned long time_interpolator_get_offset(void)
-{
-	/* If we do not have a time interpolator set up then just return zero */
-	if (!time_interpolator)
-		return 0;
-
-	return time_interpolator->offset +
-		GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
-}
-
-#define INTERPOLATOR_ADJUST 65536
-#define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
-
-void time_interpolator_update(long delta_nsec)
-{
-	u64 counter;
-	unsigned long offset;
-
-	/* If there is no time interpolator set up then do nothing */
-	if (!time_interpolator)
-		return;
-
-	/*
-	 * The interpolator compensates for late ticks by accumulating the late
-	 * time in time_interpolator->offset. A tick earlier than expected will
-	 * lead to a reset of the offset and a corresponding jump of the clock
-	 * forward. Again this only works if the interpolator clock is running
-	 * slightly slower than the regular clock and the tuning logic insures
-	 * that.
-	 */
-
-	counter = time_interpolator_get_counter(1);
-	offset = time_interpolator->offset +
-			GET_TI_NSECS(counter, time_interpolator);
-
-	if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
-		time_interpolator->offset = offset - delta_nsec;
-	else {
-		time_interpolator->skips++;
-		time_interpolator->ns_skipped += delta_nsec - offset;
-		time_interpolator->offset = 0;
-	}
-	time_interpolator->last_counter = counter;
-
-	/* Tuning logic for time interpolator invoked every minute or so.
-	 * Decrease interpolator clock speed if no skips occurred and an offset is carried.
-	 * Increase interpolator clock speed if we skip too much time.
-	 */
-	if (jiffies % INTERPOLATOR_ADJUST == 0)
-	{
-		if (time_interpolator->skips == 0 && time_interpolator->offset > tick_nsec)
-			time_interpolator->nsec_per_cyc--;
-		if (time_interpolator->ns_skipped > INTERPOLATOR_MAX_SKIP && time_interpolator->offset == 0)
-			time_interpolator->nsec_per_cyc++;
-		time_interpolator->skips = 0;
-		time_interpolator->ns_skipped = 0;
-	}
-}
-
-static inline int
-is_better_time_interpolator(struct time_interpolator *new)
-{
-	if (!time_interpolator)
-		return 1;
-	return new->frequency > 2*time_interpolator->frequency ||
-	    (unsigned long)new->drift < (unsigned long)time_interpolator->drift;
-}
-
-void
-register_time_interpolator(struct time_interpolator *ti)
-{
-	unsigned long flags;
-
-	/* Sanity check */
-	BUG_ON(ti->frequency == 0 || ti->mask == 0);
-
-	ti->nsec_per_cyc = ((u64)NSEC_PER_SEC << ti->shift) / ti->frequency;
-	spin_lock(&time_interpolator_lock);
-	write_seqlock_irqsave(&xtime_lock, flags);
-	if (is_better_time_interpolator(ti)) {
-		time_interpolator = ti;
-		time_interpolator_reset();
-	}
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-
-	ti->next = time_interpolator_list;
-	time_interpolator_list = ti;
-	spin_unlock(&time_interpolator_lock);
-}
-
-void
-unregister_time_interpolator(struct time_interpolator *ti)
-{
-	struct time_interpolator *curr, **prev;
-	unsigned long flags;
-
-	spin_lock(&time_interpolator_lock);
-	prev = &time_interpolator_list;
-	for (curr = *prev; curr; curr = curr->next) {
-		if (curr == ti) {
-			*prev = curr->next;
-			break;
-		}
-		prev = &curr->next;
-	}
-
-	write_seqlock_irqsave(&xtime_lock, flags);
-	if (ti == time_interpolator) {
-		/* we lost the best time-interpolator: */
-		time_interpolator = NULL;
-		/* find the next-best interpolator */
-		for (curr = time_interpolator_list; curr; curr = curr->next)
-			if (is_better_time_interpolator(curr))
-				time_interpolator = curr;
-		time_interpolator_reset();
-	}
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-	spin_unlock(&time_interpolator_lock);
-}
-#endif /* CONFIG_TIME_INTERPOLATION */
-
 /**
  * msleep - sleep safely even with waitqueue interruptions
  * @msecs: Time in milliseconds to sleep for
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 10c13ad..a7381d5 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -357,7 +357,8 @@
 	 * This is needed when we sync the memory.  Then we sync the buffer if
 	 * needed.
 	 */
-	io_tlb_orig_addr[index] = buffer;
+	for (i = 0; i < nslots; i++)
+		io_tlb_orig_addr[index+i] = buffer + (i << IO_TLB_SHIFT);
 	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
 		memcpy(dma_addr, buffer, size);
 
@@ -418,6 +419,8 @@
 	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
 	char *buffer = io_tlb_orig_addr[index];
 
+	buffer += ((unsigned long)dma_addr & ((1 << IO_TLB_SHIFT) - 1));
+
 	switch (target) {
 	case SYNC_FOR_CPU:
 		if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
diff --git a/mm/memory.c b/mm/memory.c
index 8aace3d..ca8cac1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2659,8 +2659,6 @@
 	return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
 }
 
-EXPORT_SYMBOL_GPL(handle_mm_fault);
-
 #ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.
diff --git a/mm/nommu.c b/mm/nommu.c
index 1b105d2..9eef6a39 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -54,12 +54,6 @@
 struct vm_operations_struct generic_file_vm_ops = {
 };
 
-EXPORT_SYMBOL(vfree);
-EXPORT_SYMBOL(vmalloc_to_page);
-EXPORT_SYMBOL(vmalloc_32);
-EXPORT_SYMBOL(vmap);
-EXPORT_SYMBOL(vunmap);
-
 /*
  * Handle all mappings that got truncated by a "truncate()"
  * system call.
@@ -168,7 +162,6 @@
 finish_or_fault:
 	return i ? : -EFAULT;
 }
-
 EXPORT_SYMBOL(get_user_pages);
 
 DEFINE_RWLOCK(vmlist_lock);
@@ -178,6 +171,7 @@
 {
 	kfree(addr);
 }
+EXPORT_SYMBOL(vfree);
 
 void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
 {
@@ -186,17 +180,19 @@
 	 */
 	return kmalloc(size, (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM);
 }
+EXPORT_SYMBOL(__vmalloc);
 
 struct page * vmalloc_to_page(void *addr)
 {
 	return virt_to_page(addr);
 }
+EXPORT_SYMBOL(vmalloc_to_page);
 
 unsigned long vmalloc_to_pfn(void *addr)
 {
 	return page_to_pfn(virt_to_page(addr));
 }
-
+EXPORT_SYMBOL(vmalloc_to_pfn);
 
 long vread(char *buf, char *addr, unsigned long count)
 {
@@ -237,9 +233,8 @@
 }
 EXPORT_SYMBOL(vmalloc_node);
 
-/*
- *	vmalloc_32  -  allocate virtually continguos memory (32bit addressable)
- *
+/**
+ * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  *	@size:		allocation size
  *
  *	Allocate enough 32bit PA addressable pages to cover @size from the
@@ -249,17 +244,33 @@
 {
 	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
 }
+EXPORT_SYMBOL(vmalloc_32);
+
+/**
+ * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
+ *	@size:		allocation size
+ *
+ * The resulting memory area is 32bit addressable and zeroed so it can be
+ * mapped to userspace without leaking data.
+ */
+void *vmalloc_32_user(unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+}
+EXPORT_SYMBOL(vmalloc_32_user);
 
 void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot)
 {
 	BUG();
 	return NULL;
 }
+EXPORT_SYMBOL(vmap);
 
 void vunmap(void *addr)
 {
 	BUG();
 }
+EXPORT_SYMBOL(vunmap);
 
 /*
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
@@ -269,6 +280,13 @@
 {
 }
 
+int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
+		   struct page *page)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(vm_insert_page);
+
 /*
  *  sys_brk() for the most part doesn't need the global kernel
  *  lock, except when an application is doing something nasty
@@ -994,6 +1012,7 @@
 	show_free_areas();
 	return -ENOMEM;
 }
+EXPORT_SYMBOL(do_mmap_pgoff);
 
 /*
  * handle mapping disposal for uClinux
@@ -1074,6 +1093,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(do_munmap);
 
 asmlinkage long sys_munmap(unsigned long addr, size_t len)
 {
@@ -1164,6 +1184,7 @@
 
 	return vma->vm_start;
 }
+EXPORT_SYMBOL(do_mremap);
 
 asmlinkage unsigned long sys_mremap(unsigned long addr,
 	unsigned long old_len, unsigned long new_len,
@@ -1231,7 +1252,6 @@
 
 	return get_area(file, addr, len, pgoff, flags);
 }
-
 EXPORT_SYMBOL(get_unmapped_area);
 
 /*
@@ -1346,6 +1366,7 @@
 	BUG();
 	return 0;
 }
+EXPORT_SYMBOL(filemap_fault);
 
 /*
  * Access another process' address space.
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 43cb3b3..40954fb 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -138,7 +138,7 @@
 #endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   unsigned long __initdata required_kernelcore;
   unsigned long __initdata required_movablecore;
-  unsigned long __initdata zone_movable_pfn[MAX_NUMNODES];
+  unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 
   /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
   int movable_zone;
diff --git a/mm/slob.c b/mm/slob.c
index d50920e..ec33fcd 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -293,6 +293,7 @@
 static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
 	struct slob_page *sp;
+	struct list_head *prev;
 	slob_t *b = NULL;
 	unsigned long flags;
 
@@ -307,12 +308,22 @@
 		if (node != -1 && page_to_nid(&sp->page) != node)
 			continue;
 #endif
+		/* Enough room on this page? */
+		if (sp->units < SLOB_UNITS(size))
+			continue;
 
-		if (sp->units >= SLOB_UNITS(size)) {
-			b = slob_page_alloc(sp, size, align);
-			if (b)
-				break;
-		}
+		/* Attempt to alloc */
+		prev = sp->list.prev;
+		b = slob_page_alloc(sp, size, align);
+		if (!b)
+			continue;
+
+		/* Improve fragment distribution and reduce our average
+		 * search time by starting our next search here. (see
+		 * Knuth vol 1, sec 2.5, pg 449) */
+		if (free_slob_pages.next != prev->next)
+			list_move_tail(&free_slob_pages, prev->next);
+		break;
 	}
 	spin_unlock_irqrestore(&slob_lock, flags);
 
diff --git a/mm/sparse.c b/mm/sparse.c
index e03b39f..3047bf0 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -209,7 +209,7 @@
 	return 1;
 }
 
-__attribute__((weak))
+__attribute__((weak)) __init
 void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
 {
 	return NULL;
diff --git a/net/core/dev.c b/net/core/dev.c
index 38212c3..ee40355 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3624,7 +3624,7 @@
 
 	/* ensure 32-byte alignment of both the device and private area */
 	alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST +
-		     (sizeof(struct net_device_subqueue) * queue_count)) &
+		     (sizeof(struct net_device_subqueue) * (queue_count - 1))) &
 		     ~NETDEV_ALIGN_CONST;
 	alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
 
@@ -3642,7 +3642,7 @@
 		dev->priv = ((char *)dev +
 			     ((sizeof(struct net_device) +
 			       (sizeof(struct net_device_subqueue) *
-				queue_count) + NETDEV_ALIGN_CONST)
+				(queue_count - 1)) + NETDEV_ALIGN_CONST)
 			      & ~NETDEV_ALIGN_CONST));
 	}
 
diff --git a/net/core/sock.c b/net/core/sock.c
index bd209c4..cfed7d4 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -182,7 +182,8 @@
   "clock-21"       , "clock-AF_SNA"      , "clock-AF_IRDA"     ,
   "clock-AF_PPPOX" , "clock-AF_WANPIPE"  , "clock-AF_LLC"      ,
   "clock-27"       , "clock-28"          , "clock-29"          ,
-  "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_MAX"
+  "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
+  "clock-AF_RXRPC" , "clock-AF_MAX"
 };
 #endif
 
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 6cbce96..771031d 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -158,7 +158,7 @@
 #define lookup(_daddr,_stack) 					\
 ({								\
 	struct inet_peer *u, **v;				\
-	if (_stack) {						\
+	if (_stack != NULL) {					\
 		stackptr = _stack;				\
 		*stackptr++ = &peer_root;			\
 	}							\
@@ -169,7 +169,7 @@
 			v = &u->avl_left;			\
 		else						\
 			v = &u->avl_right;			\
-		if (_stack)					\
+		if (_stack != NULL)				\
 			*stackptr++ = v;			\
 		u = *v;						\
 	}							\
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 281aee4..df30976f6 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -962,8 +962,8 @@
 	dsfield = ipv4_get_dsfield(iph);
 
 	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
-		fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
-					  & IPV6_TCLASS_MASK);
+		fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+					  & IPV6_TCLASS_MASK;
 
 	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
 	if (err != 0) {
diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c
index db71658..694ea4d 100644
--- a/net/irda/irnetlink.c
+++ b/net/irda/irnetlink.c
@@ -1,7 +1,7 @@
 /*
  * IrDA netlink layer, for stack configuration.
  *
- * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz>
+ * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
  *
  * Partly based on the 802.11 nelink implementation
  * (see net/wireless/nl80211.c) which is:
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index b1179dd..ca10df4 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -194,7 +194,7 @@
 	.id	= NF_CT_EXT_HELPER,
 };
 
-int nf_conntrack_helper_init()
+int nf_conntrack_helper_init(void)
 {
 	int err;
 
@@ -216,7 +216,7 @@
 	return err;
 }
 
-void nf_conntrack_helper_fini()
+void nf_conntrack_helper_fini(void)
 {
 	nf_ct_extend_unregister(&helper_extend);
 	nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
diff --git a/scripts/Lindent b/scripts/Lindent
index 7d8d889..9468ec7 100755
--- a/scripts/Lindent
+++ b/scripts/Lindent
@@ -1,2 +1,2 @@
 #!/bin/sh
-indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 "$@"
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 04579a5..5ab7914 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1076,6 +1076,7 @@
 		".plt",			/* seen on ARCH=um build on x86_64. Harmless */
 		".smp_locks",
 		".stab",
+		".m68k_fixup",
 		NULL
 	};
 	/* Start of section names */
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index ecd0673..0e69adf 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -570,10 +570,12 @@
 		case AVC_AUDIT_DATA_FS:
 			if (a->u.fs.dentry) {
 				struct dentry *dentry = a->u.fs.dentry;
-				if (a->u.fs.mnt)
-					audit_avc_path(dentry, a->u.fs.mnt);
-				audit_log_format(ab, " name=");
-				audit_log_untrustedstring(ab, dentry->d_name.name);
+				if (a->u.fs.mnt) {
+					audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt);
+				} else {
+					audit_log_format(ab, " name=");
+					audit_log_untrustedstring(ab, dentry->d_name.name);
+				}
 				inode = dentry->d_inode;
 			} else if (a->u.fs.inode) {
 				struct dentry *dentry;
@@ -624,9 +626,8 @@
 				case AF_UNIX:
 					u = unix_sk(sk);
 					if (u->dentry) {
-						audit_avc_path(u->dentry, u->mnt);
-						audit_log_format(ab, " name=");
-						audit_log_untrustedstring(ab, u->dentry->d_name.name);
+						audit_log_d_path(ab, "path=",
+								 u->dentry, u->mnt);
 						break;
 					}
 					if (!u->addr)
diff --git a/sound/Kconfig b/sound/Kconfig
index 9ea4738..e48b9b3 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -65,6 +65,8 @@
 
 source "sound/mips/Kconfig"
 
+source "sound/sh/Kconfig"
+
 # the following will depend on the order of config.
 # here assuming USB is defined before ALSA
 source "sound/usb/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index b7c7fb7..3ead922 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index ded5167..0288523 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -661,7 +661,7 @@
 		.tag = 2,
 	},
 #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
-Once alsa gets supports for this kind of thing we can add it...
+	/* Once alsa gets supports for this kind of thing we can add it... */
 	{
 		/* digital compressed output */
 		.formats =  SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
@@ -713,7 +713,7 @@
 	if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
 		/* mute and lock analog output */
 		onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
-		if (onyx_write_register(onyx
+		if (onyx_write_register(onyx,
 					ONYX_REG_DAC_CONTROL,
 					v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
 			goto out_unlock;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a96733a..59b29cd 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1487,7 +1487,7 @@
 
 	snd_pcm_stream_lock_irq(substream);
 	/* resume pause */
-	if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
+	if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
 		snd_pcm_pause(substream, 0);
 
 	/* pre-start/stop - all running streams are changed to DRAINING state */
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
index f30d171..5efe652 100644
--- a/sound/core/seq/seq_instr.c
+++ b/sound/core/seq/seq_instr.c
@@ -109,7 +109,7 @@
 			spin_lock_irqsave(&list->lock, flags);
 			while (instr->use) {
 				spin_unlock_irqrestore(&list->lock, flags);
-				schedule_timeout_interruptible(1);
+				schedule_timeout(1);
 				spin_lock_irqsave(&list->lock, flags);
 			}				
 			spin_unlock_irqrestore(&list->lock, flags);
@@ -199,7 +199,7 @@
 			instr = flist;
 			flist = instr->next;
 			while (instr->use)
-				schedule_timeout_interruptible(1);
+				schedule_timeout(1);
 			if (snd_seq_instr_free(instr, atomic)<0)
 				snd_printk(KERN_WARNING "instrument free problem\n");
 			instr = next;
@@ -555,7 +555,7 @@
 					   SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
 		while (instr->use) {
 			spin_unlock_irqrestore(&list->lock, flags);
-			schedule_timeout_interruptible(1);
+			schedule_timeout(1);
 			spin_lock_irqsave(&list->lock, flags);
 		}				
 		spin_unlock_irqrestore(&list->lock, flags);
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 67520b3..f2bbace 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1549,9 +1549,11 @@
 	int err = 0;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	t = tu->timeri->timer;
-	snd_assert(t != NULL, return -ENXIO);
+	if (!t)
+		return -EBADFD;
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (! info)
@@ -1579,9 +1581,11 @@
 	int err;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	t = tu->timeri->timer;
-	snd_assert(t != NULL, return -ENXIO);
+	if (!t)
+		return -EBADFD;
 	if (copy_from_user(&params, _params, sizeof(params)))
 		return -EFAULT;
 	if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
@@ -1675,7 +1679,8 @@
 	struct snd_timer_status status;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	memset(&status, 0, sizeof(status));
 	status.tstamp = tu->tstamp;
 	status.resolution = snd_timer_resolution(tu->timeri);
@@ -1695,7 +1700,8 @@
 	struct snd_timer_user *tu;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	snd_timer_stop(tu->timeri);
 	tu->timeri->lost = 0;
 	tu->last_resolution = 0;
@@ -1708,7 +1714,8 @@
 	struct snd_timer_user *tu;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
 }
 
@@ -1718,7 +1725,8 @@
 	struct snd_timer_user *tu;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	tu->timeri->lost = 0;
 	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
@@ -1729,7 +1737,8 @@
 	struct snd_timer_user *tu;
 
 	tu = file->private_data;
-	snd_assert(tu->timeri != NULL, return -ENXIO);
+	if (!tu->timeri)
+		return -EBADFD;
 	return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
 }
 
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index a0f28f5..4360ae9 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -659,7 +659,7 @@
 	},
 };
 
-static void __init_or_module snd_dummy_unregister_all(void)
+static void snd_dummy_unregister_all(void)
 {
 	int i;
 
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 1d563e5..67c6e97 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -228,7 +228,7 @@
 static struct pnp_driver snd_mpu401_pnp_driver;
 #endif
 
-static void __init_or_module snd_mpu401_unregister_all(void)
+static void snd_mpu401_unregister_all(void)
 {
 	int i;
 
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 497cafb..0eb9b5c 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -833,7 +833,7 @@
 /*********************************************************************
  * module init stuff
  *********************************************************************/
-static void __init_or_module snd_portman_unregister_all(void)
+static void snd_portman_unregister_all(void)
 {
 	int i;
 
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 838a427..d3e6a20 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -998,7 +998,7 @@
 	},
 };
 
-static void __init_or_module snd_serial_unregister_all(void)
+static void snd_serial_unregister_all(void)
 {
 	int i;
 
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 46f3d34..915c867 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -145,7 +145,7 @@
 	},
 };
 
-static void __init_or_module snd_virmidi_unregister_all(void)
+static void snd_virmidi_unregister_all(void)
 {
 	int i;
 
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 8805110..fd33515 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -481,8 +481,8 @@
 	int addr = AK_GET_ADDR(kcontrol->private_value);
 	int shift = AK_GET_SHIFT(kcontrol->private_value);
 	int invert = AK_GET_INVERT(kcontrol->private_value);
-	unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
+	/* we observe the (1<<shift) bit only */
+	unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
 	if (invert)
 		val = ! val;
 	ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
@@ -585,6 +585,26 @@
 
 	mixer_ch = 0;
 	for (idx = 0; idx < ak->num_dacs; ) {
+		/* mute control for Revolution 7.1 - AK4381 */
+		if (ak->type == SND_AK4381 
+				&&  ak->dac_info[mixer_ch].switch_name) {
+			memset(&knew, 0, sizeof(knew));
+			knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+			knew.count = 1;
+			knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+			knew.name = ak->dac_info[mixer_ch].switch_name;
+			knew.info = ak4xxx_switch_info;
+			knew.get = ak4xxx_switch_get;
+			knew.put = ak4xxx_switch_put;
+			knew.access = 0;
+			/* register 1, bit 0 (SMUTE): 0 = normal operation,
+			   1 = mute */
+			knew.private_value =
+				AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
+			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+			if (err < 0)
+				return err;
+		}
 		memset(&knew, 0, sizeof(knew));
 		if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
 			knew.name = "DAC Volume";
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index cf3803c..ea5084a 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -1,8 +1,5 @@
 # ALSA ISA drivers
 
-menu "ISA devices"
-	depends on SND!=n && ISA && ISA_DMA_API
-
 config SND_AD1848_LIB
         tristate
         select SND_PCM
@@ -11,6 +8,22 @@
         tristate
         select SND_PCM
 
+config SND_SB_COMMON
+        tristate
+
+config SND_SB8_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+config SND_SB16_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+menu "ISA devices"
+	depends on SND!=n && ISA && ISA_DMA_API
+
 config SND_ADLIB
 	tristate "AdLib FM card"
 	depends on SND
@@ -55,7 +68,7 @@
 	select ISAPNP
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_SB16_DSP
 	help
 	  Say Y here to include support for soundcards based on Avance
 	  Logic ALS100, ALS110, ALS120 and ALS200 chips.
@@ -81,6 +94,7 @@
 	tristate "C-Media CMI8330"
 	depends on SND
 	select SND_AD1848_LIB
+	select SND_SB16_DSP
 	help
 	  Say Y here to include support for soundcards based on the
 	  C-Media CMI8330 chip.
@@ -132,7 +146,7 @@
 	select ISAPNP
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_SB16_DSP
 	help
 	  Say Y here to include support for soundcards based on the
 	  Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
@@ -145,7 +159,7 @@
 	depends on SND && PNP && ISA
 	select ISAPNP
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_SB8_DSP
 	help
 	  Say Y here to include support for ESS AudioDrive ES968 chips.
 
@@ -321,7 +335,7 @@
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_RAWMIDI
-	select SND_PCM
+	select SND_SB8_DSP
 	help
 	  Say Y here to include support for Creative Sound Blaster 1.0/
 	  2.0/Pro (8-bit) or 100% compatible soundcards.
@@ -334,7 +348,7 @@
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_SB16_DSP
 	help
 	  Say Y here to include support for Sound Blaster 16 soundcards
 	  (including the Plug and Play version).
@@ -347,7 +361,7 @@
 	depends on SND
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
-	select SND_PCM
+	select SND_SB16_DSP
 	help
 	  Say Y here to include support for Sound Blaster AWE soundcards
 	  (including the Plug and Play version).
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 8094282..1bc2e3f 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -245,7 +245,7 @@
 			snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
 			return;
 		}
-		time = schedule_timeout_interruptible(time);
+		time = schedule_timeout(time);
 		spin_lock_irqsave(&chip->reg_lock, flags);
 	}
 #if 0
@@ -258,7 +258,7 @@
 			snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
 			return;
 		}
-		time = schedule_timeout_interruptible(time);
+		time = schedule_timeout(time);
 		spin_lock_irqsave(&chip->reg_lock, flags);
 	}
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 4f6800b..e70db32 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -164,6 +164,8 @@
 	{ .id = "YMH0801", .devs = { { "YMH0021" } } },
 	/* NeoMagic MagicWave 3DX */
 	{ .id = "NMX2200", .devs = { { "YMH2210" } } },
+	/* NeoMagic MagicWave 3D */
+	{ .id = "NMX2200", .devs = { { "NMX2210" } } },
 	/* --- */
 	{ .id = "" }	/* end */
 };
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 60c120f..049d479 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -1927,10 +1927,12 @@
 static int __devinit snd_opti9xx_isa_match(struct device *devptr,
 					   unsigned int dev)
 {
+#ifdef CONFIG_PNP
 	if (snd_opti9xx_pnp_is_probed)
 		return 0;
 	if (isapnp)
 		return 0;
+#endif
 	return 1;
 }
 
@@ -2096,6 +2098,7 @@
 	pnp_register_card_driver(&opti9xx_pnpc_driver);
 	if (snd_opti9xx_pnp_is_probed)
 		return 0;
+	pnp_unregister_card_driver(&opti9xx_pnpc_driver);
 #endif
 	return isa_register_driver(&snd_opti9xx_driver, 1);
 }
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index fd9d9c5..556e669 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -22,14 +22,13 @@
 sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
+obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
+obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
+obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
+obj-$(CONFIG_SND_SB8) += snd-sb8.o
+obj-$(CONFIG_SND_SB16) += snd-sb16.o
+obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 383911b..5d4d3aa 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -563,6 +563,11 @@
       __open_ok:
 	if (chip->hardware == SB_HW_ALS100)
 		runtime->hw.rate_max = 48000;
+	if (chip->hardware == SB_HW_CS5530) {
+		runtime->hw.buffer_bytes_max = 32 * 1024;
+		runtime->hw.periods_min = 2;
+		runtime->hw.rate_min = 44100;
+	}
 	if (chip->mode & SB_RATE_LOCK)
 		runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
 	chip->playback_substream = substream;
@@ -633,6 +638,11 @@
       __open_ok:
 	if (chip->hardware == SB_HW_ALS100)
 		runtime->hw.rate_max = 48000;
+	if (chip->hardware == SB_HW_CS5530) {
+		runtime->hw.buffer_bytes_max = 32 * 1024;
+		runtime->hw.periods_min = 2;
+		runtime->hw.rate_min = 44100;
+	}
 	if (chip->mode & SB_RATE_LOCK)
 		runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
 	chip->capture_substream = substream;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 3094f38..efa9d5c 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -128,7 +128,7 @@
 	minor = version & 0xff;
 	snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
 		    chip->port, major, minor);
-	
+
 	switch (chip->hardware) {
 	case SB_HW_AUTO:
 		switch (major) {
@@ -168,6 +168,9 @@
 	case SB_HW_DT019X:
 		str = "(DT019X/ALS007)";
 		break;
+	case SB_HW_CS5530:
+		str = "16 (CS5530)";
+		break;
 	default:
 		return -ENODEV;
 	}
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 490b1ca..3d4befc 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -821,6 +821,7 @@
 		break;
 	case SB_HW_16:
 	case SB_HW_ALS100:
+	case SB_HW_CS5530:
 		if ((err = snd_sbmixer_init(chip,
 					    snd_sb16_controls,
 					    ARRAY_SIZE(snd_sb16_controls),
@@ -950,6 +951,7 @@
 		break;
 	case SB_HW_16:
 	case SB_HW_ALS100:
+	case SB_HW_CS5530:
 		save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
 		break;
 	case SB_HW_ALS4000:
@@ -975,6 +977,7 @@
 		break;
 	case SB_HW_16:
 	case SB_HW_ALS100:
+	case SB_HW_CS5530:
 		restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
 		break;
 	case SB_HW_ALS4000:
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 9ea417b..cbad2a5 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -382,7 +382,7 @@
 		unsigned long flags;
 		unsigned char x;
 
-		schedule_timeout_interruptible(1);
+		schedule_timeout(1);
 
 		spin_lock_irqsave(&s->lock, flags);
 		x = inb(HOST_DATA_IO(s->io_base));
@@ -409,7 +409,7 @@
 		unsigned long flags;
 		unsigned char x;
 
-		schedule_timeout_interruptible(1);
+		schedule_timeout(1);
 
 		spin_lock_irqsave(&s->lock, flags);
 		x = inb(HOST_DATA_IO(s->io_base));
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 78020d8..bacc51c 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1780,7 +1780,7 @@
 	outb (val,port);
 	spin_unlock_irq(&dev->irq_lock);
 	while (1) {
-		if ((timeout = schedule_timeout_interruptible(timeout)) == 0)
+		if ((timeout = schedule_timeout(timeout)) == 0)
 			return;
 		if (dev->irq_ok)
 			return;
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 61e35ec..c6b4410 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -33,6 +33,7 @@
 	select SND_OPL3_LIB
 	select SND_MPU401_UART
 	select SND_PCM
+	select SND_SB_COMMON
 	help
 	  Say Y here to include support for soundcards based on Avance Logic
 	  ALS4000 chips.
@@ -215,6 +216,16 @@
 
 	  This works better than the old code, so say Y.
 
+config SND_CS5530
+	tristate "CS5530 Audio"
+	depends on SND && ISA_DMA_API
+	select SND_SB16_DSP
+	help
+	  Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-cs5530.
+
 config SND_CS5535AUDIO
 	tristate "CS5535/CS5536 Audio"
 	depends on SND && X86 && !X86_64
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index e06736d..cd76e029 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -12,6 +12,7 @@
 snd-bt87x-objs := bt87x.o
 snd-cmipci-objs := cmipci.o
 snd-cs4281-objs := cs4281.o
+snd-cs5530-objs := cs5530.o
 snd-ens1370-objs := ens1370.o
 snd-ens1371-objs := ens1371.o
 snd-es1938-objs := es1938.o
@@ -36,6 +37,7 @@
 obj-$(CONFIG_SND_BT87X) += snd-bt87x.o
 obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o
 obj-$(CONFIG_SND_CS4281) += snd-cs4281.o
+obj-$(CONFIG_SND_CS5530) += snd-cs5530.o
 obj-$(CONFIG_SND_ENS1370) += snd-ens1370.o
 obj-$(CONFIG_SND_ENS1371) += snd-ens1371.o
 obj-$(CONFIG_SND_ES1938) += snd-es1938.o
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 41543a4..05b4c86 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -239,7 +239,7 @@
 
 
 struct snd_ali {
-	unsigned long	irq;
+	int		irq;
 	unsigned long	port;
 	unsigned char	revision;
 
@@ -731,8 +731,7 @@
 		return;
 	}
 
-	count = 0;
-	while (count++ <= 50000) {
+	for (count = 0; count <= 50000; count++) {
 		snd_ali_delay(codec, 6);
 		bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));
 		R2 = bval & 0x1F;
@@ -2343,7 +2342,7 @@
 	strcpy(card->driver, "ALI5451");
 	strcpy(card->shortname, "ALI 5451");
 	
-	sprintf(card->longname, "%s at 0x%lx, irq %li",
+	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, codec->port, codec->irq);
 
 	snd_ali_printk("register card.\n");
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8afcb98..48cc39b 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -88,8 +88,8 @@
 #define PLAYBACK_BLOCK_COUNTER	0x9A
 #define RECORD_BLOCK_COUNTER	0x9B
 
-#define DEBUG_CALLS	1
-#define DEBUG_PLAY_REC	1
+#define DEBUG_CALLS	0
+#define DEBUG_PLAY_REC	0
 
 #if DEBUG_CALLS
 #define snd_als300_dbgcalls(format, args...) printk(format, ##args)
@@ -733,7 +733,8 @@
 
 	snd_als300_init(chip);
 
-	if (snd_als300_ac97(chip) < 0) {
+	err = snd_als300_ac97(chip);
+	if (err < 0) {
 		snd_printk(KERN_WARNING "Could not create ac97\n");
 		snd_als300_free(chip);
 		return err;
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 9fd7b8a..fcab8fb 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -168,6 +168,25 @@
 #include "ca0106.h"
 
 static struct snd_ca0106_details ca0106_chip_details[] = {
+	 /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
+	 /* It is really just a normal SB Live 24bit. */
+	 /*
+ 	  * CTRL:CA0111-WTLF
+	  * ADC: WM8775SEDS
+	  * DAC: CS4382-KQZ
+	  */
+	 /* Tested:
+	  * Playback on front, rear, center/lfe speakers
+	  * Capture from Mic in.
+	  * Not-Tested:
+	  * Capture from Line in.
+	  * Playback to digital out.
+	  */
+	 { .serial = 0x10121102,
+	   .name   = "X-Fi Extreme Audio [SB0790]",
+	   .gpio_type = 1,
+	   .i2c_adc = 1 } ,
+	 /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
 	 /* AudigyLS[SB0310] */
 	 { .serial = 0x10021102,
 	   .name   = "AudigyLS [SB0310]",
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index bef1f6d..71d7aab 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2897,6 +2897,10 @@
 	}
 #endif
 	
+#ifdef CONFIG_PM
+	kfree(chip->saved_regs);
+#endif
+
 	pci_disable_device(chip->pci);
 	kfree(chip);
 	return 0;
@@ -3140,6 +3144,23 @@
 /*
  *  start and load DSP 
  */
+
+static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
+{
+	unsigned int tmp;
+
+	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
+        
+	tmp = snd_cs46xx_peek(chip, BA1_PFIE);
+	tmp &= ~0x0000f03f;
+	snd_cs46xx_poke(chip, BA1_PFIE, tmp);	/* playback interrupt enable */
+
+	tmp = snd_cs46xx_peek(chip, BA1_CIE);
+	tmp &= ~0x0000003f;
+	tmp |=  0x00000001;
+	snd_cs46xx_poke(chip, BA1_CIE, tmp);	/* capture interrupt enable */
+}
+
 int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
 {	
 	unsigned int tmp;
@@ -3214,19 +3235,7 @@
 
 	snd_cs46xx_proc_start(chip);
 
-	/*
-	 *  Enable interrupts on the part.
-	 */
-	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-        
-	tmp = snd_cs46xx_peek(chip, BA1_PFIE);
-	tmp &= ~0x0000f03f;
-	snd_cs46xx_poke(chip, BA1_PFIE, tmp);	/* playback interrupt enable */
-
-	tmp = snd_cs46xx_peek(chip, BA1_CIE);
-	tmp &= ~0x0000003f;
-	tmp |=  0x00000001;
-	snd_cs46xx_poke(chip, BA1_CIE, tmp);	/* capture interrupt enable */
+	cs46xx_enable_stream_irqs(chip);
 	
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
 	/* set the attenuation to 0dB */ 
@@ -3665,11 +3674,19 @@
  * APM support
  */
 #ifdef CONFIG_PM
+static unsigned int saved_regs[] = {
+	BA0_ACOSV,
+	BA0_ASER_FADDR,
+	BA0_ASER_MASTER,
+	BA1_PVOL,
+	BA1_CVOL,
+};
+
 int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct snd_cs46xx *chip = card->private_data;
-	int amp_saved;
+	int i, amp_saved;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	chip->in_suspend = 1;
@@ -3680,6 +3697,10 @@
 	snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
 	snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+	/* save some registers */
+	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+		chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]);
+
 	amp_saved = chip->amplifier;
 	/* turn off amp */
 	chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3698,7 +3719,7 @@
 {
 	struct snd_card *card = pci_get_drvdata(pci);
 	struct snd_cs46xx *chip = card->private_data;
-	int amp_saved;
+	int i, amp_saved;
 
 	pci_set_power_state(pci, PCI_D0);
 	pci_restore_state(pci);
@@ -3716,6 +3737,16 @@
 
 	snd_cs46xx_chip_init(chip);
 
+	snd_cs46xx_reset(chip);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cs46xx_dsp_resume(chip);
+	/* restore some registers */
+	for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+		snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]);
+#else
+	snd_cs46xx_download_image(chip);
+#endif
+
 #if 0
 	snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 
 			       chip->ac97_general_purpose);
@@ -3730,6 +3761,13 @@
 	snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
 	snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+	/* reset playback/capture */
+	snd_cs46xx_set_play_sample_rate(chip, 8000);
+	snd_cs46xx_set_capture_sample_rate(chip, 8000);
+	snd_cs46xx_proc_start(chip);
+
+	cs46xx_enable_stream_irqs(chip);
+
 	if (amp_saved)
 		chip->amplifier_ctrl(chip, 1); /* turn amp on */
 	else
@@ -3896,6 +3934,15 @@
 	
 	snd_cs46xx_proc_init(card, chip);
 
+#ifdef CONFIG_PM
+	chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
+				   ARRAY_SIZE(saved_regs), GFP_KERNEL);
+	if (!chip->saved_regs) {
+		snd_cs46xx_free(chip);
+		return -ENOMEM;
+	}
+#endif
+
 	chip->active_ctrl(chip, -1); /* disable CLKRUN */
 
 	snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index f75750c..20dcd72 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -86,6 +86,9 @@
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip);
+#endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
 						   int symbol_type);
 #ifdef CONFIG_PROC_FS
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 336e77e..590b35d 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -306,13 +306,59 @@
 	mutex_unlock(&chip->spos_mutex);
 }
 
+static int dsp_load_parameter(struct snd_cs46xx *chip,
+			      struct dsp_segment_desc *parameter)
+{
+	u32 doffset, dsize;
+
+	if (!parameter) {
+		snd_printdd("dsp_spos: module got no parameter segment\n");
+		return 0;
+	}
+
+	doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
+	dsize   = parameter->size * 4;
+
+	snd_printdd("dsp_spos: "
+		    "downloading parameter data to chip (%08x-%08x)\n",
+		    doffset,doffset + dsize);
+	if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
+		snd_printk(KERN_ERR "dsp_spos: "
+			   "failed to download parameter data to DSP\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dsp_load_sample(struct snd_cs46xx *chip,
+			   struct dsp_segment_desc *sample)
+{
+	u32 doffset, dsize;
+
+	if (!sample) {
+		snd_printdd("dsp_spos: module got no sample segment\n");
+		return 0;
+	}
+
+	doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
+	dsize   =  sample->size * 4;
+
+	snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+		    doffset,doffset + dsize);
+
+	if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
+		snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
-	struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
-	struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
 	u32 doffset, dsize;
+	int err;
 
 	if (ins->nmodules == DSP_MAX_MODULES - 1) {
 		snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
@@ -326,49 +372,20 @@
 		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
 	}
   
-	if (parameter == NULL) {
-		snd_printdd("dsp_spos: module got no parameter segment\n");
-	} else {
-		if (ins->nmodules > 0) {
-			snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
-		}
-
-		doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
-		dsize   = parameter->size * 4;
-
-		snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
-			    doffset,doffset + dsize);
-
-		if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
-			snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
-			return -EINVAL;
-		}
-	}
+	err = dsp_load_parameter(chip, get_segment_desc(module,
+							SEGTYPE_SP_PARAMETER));
+	if (err < 0)
+		return err;
 
 	if (ins->nmodules == 0) {
 		snd_printdd("dsp_spos: clearing sample area\n");
 		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
 	}
 
-	if (sample == NULL) {
-		snd_printdd("dsp_spos: module got no sample segment\n");
-	} else {
-		if (ins->nmodules > 0) {
-			snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
-		}
-
-		doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
-		dsize   =  sample->size * 4;
-
-		snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
-			    doffset,doffset + dsize);
-
-		if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
-			snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
-			return -EINVAL;
-		}
-	}
-
+	err = dsp_load_sample(chip, get_segment_desc(module,
+						     SEGTYPE_SP_SAMPLE));
+	if (err < 0)
+		return err;
 
 	if (ins->nmodules == 0) {
 		snd_printdd("dsp_spos: clearing code area\n");
@@ -986,7 +1003,10 @@
 		return NULL;
 	}
 
-	strcpy(ins->tasks[ins->ntask].task_name,name);
+	if (name)
+		strcpy(ins->tasks[ins->ntask].task_name, name);
+	else
+		strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
 	ins->tasks[ins->ntask].address = dest;
 	ins->tasks[ins->ntask].size = size;
 
@@ -995,7 +1015,8 @@
 	desc = (ins->tasks + ins->ntask);
 	ins->ntask++;
 
-	add_symbol (chip,name,dest,SYMBOL_PARAMETER);
+	if (name)
+		add_symbol (chip,name,dest,SYMBOL_PARAMETER);
 	return desc;
 }
 
@@ -1006,6 +1027,7 @@
 
 	desc = _map_scb (chip,name,dest);
 	if (desc) {
+		desc->data = scb_data;
 		_dsp_create_scb(chip,scb_data,dest);
 	} else {
 		snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
@@ -1023,6 +1045,7 @@
 
 	desc = _map_task_tree (chip,name,dest,size);
 	if (desc) {
+		desc->data = task_data;
 		_dsp_create_task_tree(chip,task_data,dest,size);
 	} else {
 		snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
@@ -1320,8 +1343,10 @@
 			0x0000ffff
 		};
     
-		/* dirty hack ... */
-		_dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
+		if (!cs46xx_dsp_create_task_tree(chip, NULL,
+						 (u32 *)&mix2_ostream_spb,
+						 WRITE_BACK_SPB, 2))
+			goto _fail_end;
 	}
 
 	/* input sample converter */
@@ -1622,7 +1647,6 @@
 	return 0;
 }
 
-
 static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
@@ -1894,3 +1918,61 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip)
+{
+	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
+	int i, err;
+
+	/* clear parameter, sample and code areas */
+	snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
+			     DSP_PARAMETER_BYTE_SIZE);
+	snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
+			     DSP_SAMPLE_BYTE_SIZE);
+	snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
+
+	for (i = 0; i < ins->nmodules; i++) {
+		struct dsp_module_desc *module = &ins->modules[i];
+		struct dsp_segment_desc *seg;
+		u32 doffset, dsize;
+
+		seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
+		err = dsp_load_parameter(chip, seg);
+		if (err < 0)
+			return err;
+
+		seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
+		err = dsp_load_sample(chip, seg);
+		if (err < 0)
+			return err;
+
+		seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
+		if (!seg)
+			continue;
+
+		doffset = seg->offset * 4 + module->load_address * 4
+			+ DSP_CODE_BYTE_OFFSET;
+		dsize   = seg->size * 4;
+		err = snd_cs46xx_download(chip,
+					  ins->code.data + module->load_address,
+					  doffset, dsize);
+		if (err < 0)
+			return err;
+	}
+
+	for (i = 0; i < ins->ntask; i++) {
+		struct dsp_task_descriptor *t = &ins->tasks[i];
+		_dsp_create_task_tree(chip, t->data, t->address, t->size);
+	}
+
+	for (i = 0; i < ins->nscb; i++) {
+		struct dsp_scb_descriptor *s = &ins->scbs[i];
+		if (s->deleted)
+			continue;
+		_dsp_create_scb(chip, s->data, s->address);
+	}
+
+	return 0;
+}
+#endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
new file mode 100644
index 0000000..240a0a4
--- /dev/null
+++ b/sound/pci/cs5530.c
@@ -0,0 +1,306 @@
+/*
+ * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ * 	(C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
+ *	(C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
+ * mess with it a bit. The chip seems to have to have trouble with full duplex
+ * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
+ * simultaneously play back audio at 16bit 44100kHz, the device actually plays
+ * back in the same format in which it is capturing. By forcing the chip to
+ * always play/capture in 16/44100, we can let alsa-lib convert the samples and
+ * that way we can hack up some full duplex audio. 
+ * 
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * TO DO:
+ *	Investigate whether we can portably support Cognac (5520) in the
+ *	same manner.
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/sb.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ash Willis");
+MODULE_DESCRIPTION("CS5530 Audio");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+struct snd_cs5530 {
+	struct snd_card *card;
+	struct pci_dev *pci;
+	struct snd_sb *sb;
+	unsigned long pci_base;
+};
+
+static struct pci_device_id snd_cs5530_ids[] = {
+	{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
+							PCI_ANY_ID, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
+
+static int snd_cs5530_free(struct snd_cs5530 *chip)
+{
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+	kfree(chip);
+	return 0;
+}
+
+static int snd_cs5530_dev_free(struct snd_device *device)
+{
+	struct snd_cs5530 *chip = device->device_data;
+	return snd_cs5530_free(chip);
+}
+
+static void __devexit snd_cs5530_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg)
+{
+	outb(reg, io + 4);
+	udelay(20);
+	reg = inb(io + 5);
+	udelay(20);
+	return reg;
+}
+
+static int __devinit snd_cs5530_create(struct snd_card *card,
+				       struct pci_dev *pci,
+				       struct snd_cs5530 **rchip)
+{
+	struct snd_cs5530 *chip;
+	unsigned long sb_base;
+	u8 irq, dma8, dma16 = 0;
+	u16 map;
+	void __iomem *mem;
+	int err;
+
+	static struct snd_device_ops ops = {
+		.dev_free = snd_cs5530_dev_free,
+	};
+	*rchip = NULL;
+
+	err = pci_enable_device(pci);
+ 	if (err < 0)
+		return err;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL) {
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	chip->pci = pci;
+
+	err = pci_request_regions(pci, "CS5530");
+	if (err < 0) {
+		kfree(chip); 
+		pci_disable_device(pci);
+		return err;
+	}
+	chip->pci_base = pci_resource_start(pci, 0);
+
+	mem = ioremap_nocache(chip->pci_base, pci_resource_len(pci, 0));
+	if (mem == NULL) {
+		kfree(chip);
+		pci_disable_device(pci);
+		return -EBUSY;
+	}
+
+	map = readw(mem + 0x18);
+	iounmap(mem);
+
+	/* Map bits
+		0:1	* 0x20 + 0x200 = sb base
+		2	sb enable
+		3	adlib enable
+		5	MPU enable 0x330
+		6	MPU enable 0x300
+
+	   The other bits may be used internally so must be masked */
+
+	sb_base = 0x220 + 0x20 * (map & 3);
+
+	if (map & (1<<2))
+		printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+	else {
+		printk(KERN_ERR "Could not find XpressAudio!\n");
+		snd_cs5530_free(chip);
+		return -ENODEV;
+	}
+
+	if (map & (1<<5))
+		printk(KERN_INFO "CS5530: MPU at 0x300\n");
+	else if (map & (1<<6))
+		printk(KERN_INFO "CS5530: MPU at 0x330\n");
+
+	irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
+	dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
+
+	if (dma8 & 0x20)
+		dma16 = 5;
+	else if (dma8 & 0x40)
+		dma16 = 6;
+	else if (dma8 & 0x80)
+		dma16 = 7;
+	else {
+		printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+		snd_cs5530_free(chip);
+		return -ENODEV;
+	}
+
+	if (dma8 & 0x01)
+		dma8 = 0;
+	else if (dma8 & 02)
+		dma8 = 1;
+	else if (dma8 & 0x08)
+		dma8 = 3;
+	else {
+		printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+		snd_cs5530_free(chip);
+		return -ENODEV;
+	}
+
+	if (irq & 1)
+		irq = 9;
+	else if (irq & 2)
+		irq = 5;
+	else if (irq & 4)
+		irq = 7;
+	else if (irq & 8)
+		irq = 10;
+	else {
+		printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+		snd_cs5530_free(chip);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, 
+									dma16);
+
+	err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
+						dma16, SB_HW_CS5530, &chip->sb);
+	if (err < 0) {
+		printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+		snd_cs5530_free(chip);
+		return err;
+	}
+
+	err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+	if (err < 0) {
+		printk(KERN_ERR "CS5530: Could not create PCM\n");
+		snd_cs5530_free(chip);
+		return err;
+	}
+
+	err = snd_sbmixer_new(chip->sb);
+	if (err < 0) {
+		printk(KERN_ERR "CS5530: Could not create Mixer\n");
+		snd_cs5530_free(chip);
+		return err;
+	}
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (err < 0) {
+		snd_cs5530_free(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+	*rchip = chip;
+	return 0;
+}
+
+static int __devinit snd_cs5530_probe(struct pci_dev *pci,
+					const struct pci_device_id *pci_id)
+{
+	static int dev;
+	struct snd_card *card;
+	struct snd_cs5530 *chip = NULL;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+	if (card == NULL)
+		return -ENOMEM;
+
+	err = snd_cs5530_create(card, pci, &chip);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	strcpy(card->driver, "CS5530");
+	strcpy(card->shortname, "CS5530 Audio");
+	sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	pci_set_drvdata(pci, card);
+	dev++;
+	return 0;
+}
+
+static struct pci_driver driver = {
+	.name = "CS5530_Audio",
+	.id_table = snd_cs5530_ids,
+	.probe = snd_cs5530_probe,
+	.remove = __devexit_p(snd_cs5530_remove),
+};
+
+static int __init alsa_card_cs5530_init(void)
+{
+	return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_cs5530_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_cs5530_init)
+module_exit(alsa_card_cs5530_exit)
+
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 4a9b59a..404ae1b 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -51,9 +51,15 @@
 
 #define HANA_FILENAME "emu/hana.fw"
 #define DOCK_FILENAME "emu/audio_dock.fw"
+#define EMU1010B_FILENAME "emu/emu1010b.fw"
+#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
 
 MODULE_FIRMWARE(HANA_FILENAME);
 MODULE_FIRMWARE(DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010B_FILENAME);
+MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
 
 
 /*************************************************************************
@@ -660,10 +666,12 @@
 		return err;
 	}
 	snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+#if 0
 	if (fw_entry->size != 0x133a4) {
 		snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
 		return -EINVAL;
 	}
+#endif
 
 	/* The FPGA is a Xilinx Spartan IIE XC2S50E */
 	/* GPIO7 -> FPGA PGMN
@@ -694,6 +702,37 @@
 	return 0;
 }
 
+/*
+ * EMU-1010 - details found out from this driver, official MS Win drivers,
+ * testing the card:
+ *
+ * Audigy2 (aka Alice2):
+ * ---------------------
+ * 	* communication over PCI
+ * 	* conversion of 32-bit data coming over EMU32 links from HANA FPGA
+ *	  to 2 x 16-bit, using internal DSP instructions
+ * 	* slave mode, clock supplied by HANA
+ * 	* linked to HANA using:
+ * 		32 x 32-bit serial EMU32 output channels
+ * 		16 x EMU32 input channels
+ * 		(?) x I2S I/O channels (?)
+ *
+ * FPGA (aka HANA):
+ * ---------------
+ * 	* provides all (?) physical inputs and outputs of the card
+ * 		(ADC, DAC, SPDIF I/O, ADAT I/O, etc.)
+ * 	* provides clock signal for the card and Alice2
+ * 	* two crystals - for 44.1kHz and 48kHz multiples
+ * 	* provides internal routing of signal sources to signal destinations
+ * 	* inputs/outputs to Alice2 - see above
+ *
+ * Current status of the driver:
+ * ----------------------------
+ * 	* only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz)
+ * 	* PCM device nb. 2:
+ *		16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
+ * 		16 x 32-bit capture - snd_emu10k1_capture_efx_ops
+ */
 static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
 {
 	unsigned int i;
@@ -727,7 +766,7 @@
 	/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
 	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
 	snd_printdd("reg1=0x%x\n",reg);
-	if (reg == 0x55) {
+	if ((reg & 0x3f) == 0x15) {
 		/* FPGA netlist already present so clear it */
 		/* Return to programming mode */
 
@@ -735,19 +774,32 @@
 	}
 	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
 	snd_printdd("reg2=0x%x\n",reg);
-	if (reg == 0x55) {
+	if ((reg & 0x3f) == 0x15) {
 		/* FPGA failed to return to programming mode */
+		snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
 		return -ENODEV;
 	}
 	snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
-	if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
-		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
-		return err;
+	if (emu->card_capabilities->emu1010 == 1) {
+		if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
+			snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
+			return err;
+		}
+	} else if (emu->card_capabilities->emu1010 == 2) {
+		if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
+			snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
+			return err;
+		}
+	} else if (emu->card_capabilities->emu1010 == 3) {
+		if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
+			snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
+			return err;
+		}
 	}
 
 	/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
 	snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-	if (reg != 0x55) {
+	if ((reg & 0x3f) != 0x15) {
 		/* FPGA failed to be programmed */
 		snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
 		return -ENODEV;
@@ -850,6 +902,27 @@
 		EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
 	snd_emu1010_fpga_link_dst_src_write(emu,
 		EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+	/* Pavel Hofman - setting defaults for 8 more capture channels
+	 * Defaults only, users will set their own values anyways, let's
+	 * just copy/paste.
+	 */
+	
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1);
+	snd_emu1010_fpga_link_dst_src_write(emu,
+		EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1);
 #endif
 #if 0
 	/* Original */
@@ -943,16 +1016,27 @@
 		/* Return to Audio Dock programming mode */
 		snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
 		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
-		if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-			return err;
+		if (emu->card_capabilities->emu1010 == 1) {
+			if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+				return err;
+			}
+		} else if (emu->card_capabilities->emu1010 == 2) {
+			if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+				return err;
+			}
+		} else if (emu->card_capabilities->emu1010 == 3) {
+			if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+				return err;
+			}
 		}
+
 		snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
 		snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
 		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
 		/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
 		snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
 		snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
-		if (reg != 0x55) {
+		if ((reg & 0x3f) != 0x15) {
 			/* FPGA failed to be programmed */
 			snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
 			return 0;
@@ -1227,9 +1311,15 @@
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .ca_cardbus_chip = 1,
-	 .spi_dac = 1,
-	 .i2c_adc = 1,
-	 .spk71 = 1} ,
+	 .spk71 = 1 ,
+	 .emu1010 = 3} ,
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
+	 .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
+	 .id = "EMU1010",
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1,
+	 .spk71 = 1 ,
+	 .emu1010 = 2} ,
 	{.vendor = 0x1102, .device = 0x0008, 
 	 .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
 	 .id = "Audigy2",
@@ -1663,12 +1753,13 @@
 	emu->fx8010.extout_mask = extout_mask;
 	emu->enable_ir = enable_ir;
 
+	if (emu->card_capabilities->ca_cardbus_chip) {
+		if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+			goto error;
+	}
 	if (emu->card_capabilities->ecard) {
 		if ((err = snd_emu10k1_ecard_init(emu)) < 0)
 			goto error;
-	} else if (emu->card_capabilities->ca_cardbus_chip) {
-		if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
-			goto error;
  	} else if (emu->card_capabilities->emu1010) {
  		if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
  			snd_emu10k1_free(emu);
@@ -1814,10 +1905,10 @@
 
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
 {
+	if (emu->card_capabilities->ca_cardbus_chip)
+		snd_emu10k1_cardbus_init(emu);
 	if (emu->card_capabilities->ecard)
 		snd_emu10k1_ecard_init(emu);
-	else if (emu->card_capabilities->ca_cardbus_chip)
-		snd_emu10k1_cardbus_init(emu);
 	else if (emu->card_capabilities->emu1010)
  		snd_emu10k1_emu1010_init(emu);
 	else
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index c02012c..7206c0f 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1123,6 +1123,11 @@
 	ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
 }
 
+/*
+ * Used for emu1010 - conversion from 32-bit capture inputs from HANA
+ * to 2 x 16-bit registers in audigy - their values are read via DMA.
+ * Conversion is performed by Audigy DSP instructions of FX8010.
+ */
 static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
 				struct snd_emu10k1_fx8010_code *icode,
 				u32 *ptr, int tmp, int bit_shifter16,
@@ -1193,7 +1198,11 @@
 	snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
 #if 1
-	/* PCM front Playback Volume (independent from stereo mix) */
+	/* PCM front Playback Volume (independent from stereo mix)
+	 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
+	 * where gpr contains attenuation from corresponding mixer control
+	 * (snd_emu10k1_init_stereo_control)
+	 */
 	A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
 	A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
 	snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
@@ -1549,7 +1558,7 @@
 
 	if (emu->card_capabilities->emu1010) {
 		snd_printk("EMU inputs on\n");
-		/* Capture 8 channels of S32_LE sound */
+		/* Capture 16 (originally 8) channels of S32_LE sound */
 		
 		/* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
 		/* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
@@ -1560,6 +1569,11 @@
 		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
 		/* Right ADC in 1 of 2 */
 		gpr_map[gpr++] = 0x00000000;
+		/* Delaying by one sample: instead of copying the input
+		 * value A_P16VIN to output A_FXBUS2 as in the first channel,
+		 * we use an auxiliary register, delaying the value by one
+		 * sample
+		 */
 		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
 		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
 		gpr_map[gpr++] = 0x00000000;
@@ -1583,6 +1597,66 @@
 		gpr_map[gpr++] = 0x00000000;
 		snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
 		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+		/* Pavel Hofman - we still have voices, A_FXBUS2s, and
+		 * A_P16VINs available -
+		 * let's add 8 more capture channels - total of 16
+		 */
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x10));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x12));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x14));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x16));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x18));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x1a));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x1c));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
+		     A_C_00000000, A_C_00000000);
+		gpr_map[gpr++] = 0x00000000;
+		snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+							  bit_shifter16,
+							  A_GPR(gpr - 1),
+							  A_FXBUS2(0x1e));
+		A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
+		     A_C_00000000, A_C_00000000);
 
 #if 0
 		for (z = 4; z < 8; z++) {
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 4db6e1c..7b2c1dc 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -77,6 +77,10 @@
 	return 0;
 }
 
+/*
+ * Items labels in enum mixer controls assigning source data to
+ * each destination
+ */
 static char *emu1010_src_texts[] = { 
 	"Silence",
 	"Dock Mic A",
@@ -133,6 +137,9 @@
 	"DSP 31",
 };
 
+/*
+ * List of data sources available for each destination
+ */
 static unsigned int emu1010_src_regs[] = {
 	EMU_SRC_SILENCE,/* 0 */
 	EMU_SRC_DOCK_MIC_A1, /* 1 */
@@ -189,6 +196,10 @@
 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
 };
 
+/*
+ * Data destinations - physical EMU outputs.
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_output_dst[] = {
 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
@@ -216,6 +227,11 @@
 	EMU_DST_HANA_ADAT+7, /* 23 */
 };
 
+/*
+ * Data destinations - HANA outputs going to Alice2 (audigy) for
+ *   capture (EMU32 + I2S links)
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_input_dst[] = {
 	EMU_DST_ALICE2_EMU32_0,
 	EMU_DST_ALICE2_EMU32_1,
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index ab4f5df..eda5cb3 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1233,24 +1233,26 @@
 	runtime->hw.rate_min = runtime->hw.rate_max = 48000;
 	spin_lock_irq(&emu->reg_lock);
 	if (emu->card_capabilities->emu1010) {
-		/* TODO 
+		/*  Nb. of channels has been increased to 16 */
+		/* TODO
 		 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
 		 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
 		 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
 		 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
 		 * rate_min = 44100,
 		 * rate_max = 192000,
-		 * channels_min = 8,
-		 * channels_max = 8,
+		 * channels_min = 16,
+		 * channels_max = 16,
 		 * Need to add mixer control to fix sample rate
 		 *                 
-		 * There are 16 mono channels of 16bits each.
+		 * There are 32 mono channels of 16bits each.
 		 * 24bit Audio uses 2x channels over 16bit
 		 * 96kHz uses 2x channels over 48kHz
 		 * 192kHz uses 4x channels over 48kHz
-		 * So, for 48kHz 24bit, one has 8 channels
-		 * for 96kHz 24bit, one has 4 channels
-		 * for 192kHz 24bit, one has 2 channels
+		 * So, for 48kHz 24bit, one has 16 channels
+		 * for 96kHz 24bit, one has 8 channels
+		 * for 192kHz 24bit, one has 4 channels
+		 *
 		 */
 #if 1
 		switch (emu->emu1010.internal_clock) {
@@ -1258,13 +1260,15 @@
 			/* For 44.1kHz */
 			runtime->hw.rates = SNDRV_PCM_RATE_44100;
 			runtime->hw.rate_min = runtime->hw.rate_max = 44100;
-			runtime->hw.channels_min = runtime->hw.channels_max = 8;
+			runtime->hw.channels_min =
+				runtime->hw.channels_max = 16;
 			break;
 		case 1:
 			/* For 48kHz */
 			runtime->hw.rates = SNDRV_PCM_RATE_48000;
 			runtime->hw.rate_min = runtime->hw.rate_max = 48000;
-			runtime->hw.channels_min = runtime->hw.channels_max = 8;
+			runtime->hw.channels_min =
+				runtime->hw.channels_max = 16;
 			break;
 		};
 #endif
@@ -1282,7 +1286,7 @@
 #endif
 		runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
 		/* efx_voices_mask[0] is expected to be zero
- 		 * efx_voices_mask[1] is expected to have 16bits set
+ 		 * efx_voices_mask[1] is expected to have 32bits set
 		 */
 	} else {
 		runtime->hw.channels_min = runtime->hw.channels_max = 0;
@@ -1787,11 +1791,24 @@
 	/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
 	if (emu->audigy) {
 		emu->efx_voices_mask[0] = 0;
-		emu->efx_voices_mask[1] = 0xffff;
+		if (emu->card_capabilities->emu1010)
+			/* Pavel Hofman - 32 voices will be used for
+			 * capture (write mode) -
+			 * each bit = corresponding voice
+			 */
+			emu->efx_voices_mask[1] = 0xffffffff;
+		else
+			emu->efx_voices_mask[1] = 0xffff;
 	} else {
 		emu->efx_voices_mask[0] = 0xffff0000;
 		emu->efx_voices_mask[1] = 0;
 	}
+	/* For emu1010, the control has to set 32 upper bits (voices)
+	 * out of the 64 bits (voices) to true for the 16-channels capture
+	 * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
+	 * is already defined but the snd_emu10k1_pcm_efx_voices_mask
+	 * control can override this register's value.
+	 */
 	kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
 	if (!kctl)
 		return -ENOMEM;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 7c40396..21cb426 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1607,8 +1607,8 @@
 	unsigned char rev;		/* revision */
 };
 
-static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
-					 struct es1371_quirk *list)
+static int es1371_quirk_lookup(struct ensoniq *ensoniq,
+				struct es1371_quirk *list)
 {
 	while (list->vid != (unsigned short)PCI_ANY_ID) {
 		if (ensoniq->pci->vendor == list->vid &&
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 2fa281c..92bc8b3 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -341,6 +341,9 @@
 	unsigned int single_cmd :1;
 	unsigned int polling_mode :1;
 	unsigned int msi :1;
+
+	/* for debugging */
+	unsigned int last_cmd;	/* last issued command (to sync) */
 };
 
 /* driver types */
@@ -466,18 +469,10 @@
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-			     unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
 {
 	struct azx *chip = codec->bus->private_data;
 	unsigned int wp;
-	u32 val;
-
-	val = (u32)(codec->addr & 0x0f) << 28;
-	val |= (u32)direct << 27;
-	val |= (u32)nid << 20;
-	val |= verb << 8;
-	val |= para;
 
 	/* add command to corb */
 	wp = azx_readb(chip, CORBWP);
@@ -538,12 +533,12 @@
 		}
 		if (! chip->rirb.cmds)
 			return chip->rirb.res; /* the last value */
-		schedule_timeout_interruptible(1);
+		schedule_timeout(1);
 	} while (time_after_eq(timeout, jiffies));
 
 	if (chip->msi) {
 		snd_printk(KERN_WARNING "hda_intel: No response from codec, "
-			   "disabling MSI...\n");
+			   "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 		pci_disable_msi(chip->pci);
@@ -555,13 +550,15 @@
 
 	if (!chip->polling_mode) {
 		snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
-			   "switching to polling mode...\n");
+			   "switching to polling mode: last cmd=0x%08x\n",
+			   chip->last_cmd);
 		chip->polling_mode = 1;
 		goto again;
 	}
 
 	snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-		   "switching to single_cmd mode...\n");
+		   "switching to single_cmd mode: last cmd=0x%08x\n",
+		   chip->last_cmd);
 	chip->rirb.rp = azx_readb(chip, RIRBWP);
 	chip->rirb.cmds = 0;
 	/* switch to single_cmd mode */
@@ -581,20 +578,11 @@
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-			       int direct, unsigned int verb,
-			       unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 {
 	struct azx *chip = codec->bus->private_data;
-	u32 val;
 	int timeout = 50;
 
-	val = (u32)(codec->addr & 0x0f) << 28;
-	val |= (u32)direct << 27;
-	val |= (u32)nid << 20;
-	val |= verb << 8;
-	val |= para;
-
 	while (timeout--) {
 		/* check ICB busy bit */
 		if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
@@ -639,10 +627,19 @@
 			unsigned int para)
 {
 	struct azx *chip = codec->bus->private_data;
+	u32 val;
+
+	val = (u32)(codec->addr & 0x0f) << 28;
+	val |= (u32)direct << 27;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= para;
+	chip->last_cmd = val;
+
 	if (chip->single_cmd)
-		return azx_single_send_cmd(codec, nid, direct, verb, para);
+		return azx_single_send_cmd(codec, val);
 	else
-		return azx_corb_send_cmd(codec, nid, direct, verb, para);
+		return azx_corb_send_cmd(codec, val);
 }
 
 /* get a response */
@@ -1788,6 +1785,12 @@
 	{ 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
 	{ 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
 	{ 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+	{ 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+	{ 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+	{ 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+	{ 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+	{ 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+	{ 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index e313e68..ac15066 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -250,6 +250,12 @@
 	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
 	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+
+	if (codec->mfg)
+		snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
+	else
+		snd_iprintf(buffer, "No Modem Function Group found\n");
+
 	if (! codec->afg)
 		return;
 	snd_iprintf(buffer, "Default PCM:\n");
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0e1a879..4d7f8d1 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1,7 +1,8 @@
 /*
- * HD audio interface patch for AD1981HD, AD1983, AD1986A, AD1988
+ * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ *   AD1986A, AD1988
  *
- * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -61,7 +62,7 @@
 	int num_channel_mode;
 
 	/* PCM information */
-	struct hda_pcm pcm_rec[2];	/* used in alc_build_pcms() */
+	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
 
 	struct mutex amp_mutex;	/* PCM volume/mute control mutex */
 	unsigned int spdif_route;
@@ -2775,11 +2776,634 @@
 
 
 /*
+ * AD1884 / AD1984
+ *
+ * port-B - front line/mic-in
+ * port-E - aux in/out
+ * port-F - aux in/out
+ * port-C - rear line/mic-in
+ * port-D - rear line/hp-out
+ * port-A - front line/hp-out
+ *
+ * AD1984 = AD1884 + two digital mic-ins
+ *
+ * FIXME:
+ * For simplicity, we share the single DAC for both HP and line-outs
+ * right now.  The inidividual playbacks could be easily implemented,
+ * but no build-up framework is given, so far.
+ */
+
+static hda_nid_t ad1884_dac_nids[1] = {
+	0x04,
+};
+
+static hda_nid_t ad1884_adc_nids[2] = {
+	0x08, 0x09,
+};
+
+static hda_nid_t ad1884_capsrc_nids[2] = {
+	0x0c, 0x0d,
+};
+
+#define AD1884_SPDIF_OUT	0x02
+
+static struct hda_input_mux ad1884_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Front Mic", 0x0 },
+		{ "Mic", 0x1 },
+		{ "CD", 0x2 },
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884_base_mixers[] = {
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+	/*
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+	*/
+	HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	/* SPDIF controls */
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		/* identical with ad1983 */
+		.info = ad1983_spdif_route_info,
+		.get = ad1983_spdif_route_get,
+		.put = ad1983_spdif_route_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
+			     HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
+			   HDA_INPUT),
+	{ } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884_init_verbs[] = {
+	/* DACs; mute as default */
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	/* Port-A (HP) mixer */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-A pin */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* HP selector - select DAC2 */
+	{0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* Port-D (Line-out) mixer */
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-D pin */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Mono-out mixer */
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Mono-out pin */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Mono selector */
+	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* Port-B (front mic) pin */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-C (rear mic) pin */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog mixer; mute as default */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+	/* SPDIF output selector */
+	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{ } /* end */
+};
+
+static int patch_ad1884(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
+	spec->multiout.dac_nids = ad1884_dac_nids;
+	spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+	spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
+	spec->adc_nids = ad1884_adc_nids;
+	spec->capsrc_nids = ad1884_capsrc_nids;
+	spec->input_mux = &ad1884_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = ad1884_base_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = ad1884_init_verbs;
+	spec->spdif_route = 0;
+
+	codec->patch_ops = ad198x_patch_ops;
+
+	return 0;
+}
+
+/*
+ * Lenovo Thinkpad T61/X61
+ */
+static struct hda_input_mux ad1984_thinkpad_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Internal Mic", 0x1 },
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* additional verbs */
+static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+	/* Port-E (docking station mic) pin */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* docking mic boost */
+	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog mixer - docking mic; mute as default */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* enable EAPD bit */
+	{0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{ } /* end */
+};
+
+/* Digial MIC ADC NID 0x05 + 0x06 */
+static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   unsigned int stream_tag,
+				   unsigned int format,
+				   struct snd_pcm_substream *substream)
+{
+	snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
+				   struct hda_codec *codec,
+				   struct snd_pcm_substream *substream)
+{
+	snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+				   0, 0, 0);
+	return 0;
+}
+
+static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x05,
+	.ops = {
+		.prepare = ad1984_pcm_dmic_prepare,
+		.cleanup = ad1984_pcm_dmic_cleanup
+	},
+};
+
+static int ad1984_build_pcms(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec = codec->spec;
+	struct hda_pcm *info;
+	int err;
+
+	err = ad198x_build_pcms(codec);
+	if (err < 0)
+		return err;
+
+	info = spec->pcm_rec + codec->num_pcms;
+	codec->num_pcms++;
+	info->name = "AD1984 Digital Mic";
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
+	return 0;
+}
+
+/* models */
+enum {
+	AD1984_BASIC,
+	AD1984_THINKPAD,
+	AD1984_MODELS
+};
+
+static const char *ad1984_models[AD1984_MODELS] = {
+	[AD1984_BASIC]		= "basic",
+	[AD1984_THINKPAD]	= "thinkpad",
+};
+
+static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+	/* Lenovo Thinkpad T61/X61 */
+	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+	{}
+};
+
+static int patch_ad1984(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec;
+	int board_config, err;
+
+	err = patch_ad1884(codec);
+	if (err < 0)
+		return err;
+	spec = codec->spec;
+	board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
+						  ad1984_models, ad1984_cfg_tbl);
+	switch (board_config) {
+	case AD1984_BASIC:
+		/* additional digital mics */
+		spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
+		codec->patch_ops.build_pcms = ad1984_build_pcms;
+		break;
+	case AD1984_THINKPAD:
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1984_thinkpad_capture_source;
+		spec->mixers[0] = ad1984_thinkpad_mixers;
+		spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
+		break;
+	}
+	return 0;
+}
+
+
+/*
+ * AD1882
+ *
+ * port-A - front hp-out
+ * port-B - front mic-in
+ * port-C - rear line-in, shared surr-out (3stack)
+ * port-D - rear line-out
+ * port-E - rear mic-in, shared clfe-out (3stack)
+ * port-F - rear surr-out (6stack)
+ * port-G - rear clfe-out (6stack)
+ */
+
+static hda_nid_t ad1882_dac_nids[3] = {
+	0x04, 0x03, 0x05
+};
+
+static hda_nid_t ad1882_adc_nids[2] = {
+	0x08, 0x09,
+};
+
+static hda_nid_t ad1882_capsrc_nids[2] = {
+	0x0c, 0x0d,
+};
+
+#define AD1882_SPDIF_OUT	0x02
+
+/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
+static struct hda_input_mux ad1882_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "Front Mic", 0x1 },
+		{ "Mic", 0x4 },
+		{ "Line", 0x2 },
+		{ "CD", 0x3 },
+		{ "Mix", 0x7 },
+	},
+};
+
+static struct snd_kcontrol_new ad1882_base_mixers[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	/* SPDIF controls */
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		/* identical with ad1983 */
+		.info = ad1983_spdif_route_info,
+		.get = ad1983_spdif_route_get,
+		.put = ad1983_spdif_route_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = ad198x_ch_mode_info,
+		.get = ad198x_ch_mode_get,
+		.put = ad198x_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+static struct hda_verb ad1882_ch2_init[] = {
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{ } /* end */
+};
+
+static struct hda_verb ad1882_ch4_init[] = {
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{ } /* end */
+};
+
+static struct hda_verb ad1882_ch6_init[] = {
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{ } /* end */
+};
+
+static struct hda_channel_mode ad1882_modes[3] = {
+	{ 2, ad1882_ch2_init },
+	{ 4, ad1882_ch4_init },
+	{ 6, ad1882_ch6_init },
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1882_init_verbs[] = {
+	/* DACs; mute as default */
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	/* Port-A (HP) mixer */
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-A pin */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* HP selector - select DAC2 */
+	{0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* Port-D (Line-out) mixer */
+	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-D pin */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Mono-out mixer */
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Mono-out pin */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-B (front mic) pin */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+	/* Port-C (line-in) pin */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+	/* Port-C mixer - mute as input */
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	/* Port-E (mic-in) pin */
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+	/* Port-E mixer - mute as input */
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	/* Port-F (surround) */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-G (CLFE) */
+	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog mixer; mute as default */
+	/* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+	/* SPDIF output selector */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{ } /* end */
+};
+
+/* models */
+enum {
+	AD1882_3STACK,
+	AD1882_6STACK,
+	AD1882_MODELS
+};
+
+static const char *ad1882_models[AD1986A_MODELS] = {
+	[AD1882_3STACK]		= "3stack",
+	[AD1882_6STACK]		= "6stack",
+};
+
+
+static int patch_ad1882(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 6;
+	spec->multiout.num_dacs = 3;
+	spec->multiout.dac_nids = ad1882_dac_nids;
+	spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
+	spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
+	spec->adc_nids = ad1882_adc_nids;
+	spec->capsrc_nids = ad1882_capsrc_nids;
+	spec->input_mux = &ad1882_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = ad1882_base_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = ad1882_init_verbs;
+	spec->spdif_route = 0;
+
+	codec->patch_ops = ad198x_patch_ops;
+
+	/* override some parameters */
+	board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
+						  ad1882_models, NULL);
+	switch (board_config) {
+	default:
+	case AD1882_3STACK:
+		spec->num_mixers = 2;
+		spec->mixers[1] = ad1882_3stack_mixers;
+		spec->channel_mode = ad1882_modes;
+		spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
+		spec->need_dac_fix = 1;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		break;
+	case AD1882_6STACK:
+		spec->num_mixers = 2;
+		spec->mixers[1] = ad1882_6stack_mixers;
+		break;
+	}
+	return 0;
+}
+
+
+/*
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_analog[] = {
+	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+	{ .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
 	{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
 	{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
+	{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
 	{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
 	{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
 	{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index f8eb4c9..72d3ab9 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -172,6 +172,7 @@
  */
 struct hda_codec_preset snd_hda_preset_atihdmi[] = {
 	{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
 	{} /* terminator */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index bef214b..4d8e8af 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -801,7 +801,9 @@
 	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
+	SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
 	SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
+	SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
 	SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
 	{}
 };
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4776de9..9a47eec 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -94,10 +94,18 @@
 	ALC262_HP_BPC_D7000_WF,
 	ALC262_BENQ_ED8,
 	ALC262_SONY_ASSAMD,
+	ALC262_BENQ_T31,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
 };
 
+/* ALC268 models */
+enum {
+	ALC268_3ST,
+	ALC268_AUTO,
+	ALC268_MODEL_LAST /* last tag */
+};
+
 /* ALC861 models */
 enum {
 	ALC861_3ST,
@@ -115,6 +123,7 @@
 /* ALC861-VD models */
 enum {
 	ALC660VD_3ST,
+	ALC660VD_3ST_DIG,
 	ALC861VD_3ST,
 	ALC861VD_3ST_DIG,
 	ALC861VD_6ST_DIG,
@@ -144,6 +153,7 @@
 	ALC882_TARGA,
 	ALC882_ASUS_A7J,
 	ALC885_MACPRO,
+	ALC885_IMAC24,
 	ALC882_AUTO,
 	ALC882_MODEL_LAST,
 };
@@ -163,6 +173,8 @@
 	ALC883_LENOVO_101E_2ch,
 	ALC883_LENOVO_NB0763,
 	ALC888_LENOVO_MS7195_DIG,		
+	ALC888_6ST_HP,
+	ALC888_3ST_HP,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -713,6 +725,38 @@
 }
 
 /*
+ * Fix-up pin default configurations
+ */
+
+struct alc_pincfg {
+	hda_nid_t nid;
+	u32 val;
+};
+
+static void alc_fix_pincfg(struct hda_codec *codec,
+			   const struct snd_pci_quirk *quirk,
+			   const struct alc_pincfg **pinfix)
+{
+	const struct alc_pincfg *cfg;
+
+	quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+	if (!quirk)
+		return;
+
+	cfg = pinfix[quirk->value];
+	for (; cfg->nid; cfg++) {
+		int i;
+		u32 val = cfg->val;
+		for (i = 0; i < 4; i++) {
+			snd_hda_codec_write(codec, cfg->nid, 0,
+				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
+				    val & 0xff);
+			val >>= 8;
+		}
+	}
+}
+
+/*
  * ALC880 3-stack model
  *
  * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
@@ -1878,31 +1922,53 @@
  * Pin assignment:
  *   Speaker-out: 0x14
  *   Mic-In: 0x18
- *   Built-in Mic-In: 0x19 (?)
- *   HP-Out: 0x1b
+ *   Built-in Mic-In: 0x19
+ *   Line-In: 0x1b
+ *   HP-Out: 0x1a
  *   SPDIF-Out: 0x1e
  */
 
-/* seems analog CD is not working */
 static struct hda_input_mux alc880_lg_lw_capture_source = {
-	.num_items = 2,
+	.num_items = 3,
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Internal Mic", 0x1 },
+		{ "Line In", 0x2 },
 	},
 };
 
+#define alc880_lg_lw_modes alc880_threestack_modes
+
 static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc_ch_mode_info,
+		.get = alc_ch_mode_get,
+		.put = alc_ch_mode_put,
+	},
 	{ } /* end */
 };
 
 static struct hda_verb alc880_lg_lw_init_verbs[] = {
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+	{0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+	{0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
 	/* set capture source to mic-in */
 	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1912,7 +1978,6 @@
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* HP-out */
-	{0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* mic-in to input */
@@ -2856,11 +2921,11 @@
 		.mixers = { alc880_lg_lw_mixer },
 		.init_verbs = { alc880_volume_init_verbs,
 				alc880_lg_lw_init_verbs },
-		.num_dacs = 1,
+		.num_dacs = ARRAY_SIZE(alc880_dac_nids),
 		.dac_nids = alc880_dac_nids,
 		.dig_out_nid = ALC880_DIGOUT_NID,
-		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-		.channel_mode = alc880_2_jack_modes,
+		.num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
+		.channel_mode = alc880_lg_lw_modes,
 		.input_mux = &alc880_lg_lw_capture_source,
 		.unsol_event = alc880_lg_lw_unsol_event,
 		.init_hook = alc880_lg_lw_automute,
@@ -5054,6 +5119,60 @@
 	{ }
 };
 
+/* iMac 24 mixer. */
+static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
+	{ } /* end */
+};
+
+/* iMac 24 init verbs. */
+static struct hda_verb alc885_imac24_init_verbs[] = {
+	/* Internal speakers: output 0 (0x0c) */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Internal speakers: output 0 (0x0c) */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Headphone: output 0 (0x0c) */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	/* Front Mic: input vref at 80% */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{ }
+};
+
+/* Toggle speaker-output according to the hp-jack state */
+static void alc885_imac24_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+
+ 	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+/* Processes unsolicited events. */
+static void alc885_imac24_unsol_event(struct hda_codec *codec,
+				      unsigned int res)
+{
+	/* Headphone insertion or removal. */
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc885_imac24_automute(codec);
+}
+
 static struct hda_verb alc882_targa_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -5274,6 +5393,7 @@
 	[ALC882_ARIMA]		= "arima",
 	[ALC882_W2JC]		= "w2jc",
 	[ALC885_MACPRO]		= "macpro",
+	[ALC885_IMAC24]		= "imac24",
 	[ALC882_AUTO]		= "auto",
 };
 
@@ -5284,6 +5404,7 @@
 	SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
 	SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
 	SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+	SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
 	{}
@@ -5345,6 +5466,19 @@
 		.channel_mode = alc882_ch_modes,
 		.input_mux = &alc882_capture_source,
 	},
+	[ALC885_IMAC24] = {
+		.mixers = { alc885_imac24_mixer },
+		.init_verbs = { alc885_imac24_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc882_dac_nids),
+		.dac_nids = alc882_dac_nids,
+		.dig_out_nid = ALC882_DIGOUT_NID,
+		.dig_in_nid = ALC882_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+		.channel_mode = alc882_ch_modes,
+		.input_mux = &alc882_capture_source,
+		.unsol_event = alc885_imac24_unsol_event,
+		.init_hook = alc885_imac24_automute,
+	},
 	[ALC882_TARGA] = {
 		.mixers = { alc882_targa_mixer, alc882_chmode_mixer,
 			    alc882_capture_mixer },
@@ -5379,6 +5513,29 @@
 
 
 /*
+ * Pin config fixes
+ */
+enum { 
+	PINFIX_ABIT_AW9D_MAX
+};
+
+static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+	{ 0x15, 0x01080104 }, /* side */
+	{ 0x16, 0x01011012 }, /* rear */
+	{ 0x17, 0x01016011 }, /* clfe */
+	{ }
+};
+
+static const struct alc_pincfg *alc882_pin_fixes[] = {
+	[PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+};
+
+static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+	{}
+};
+
+/*
  * BIOS auto configuration
  */
 static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
@@ -5494,6 +5651,9 @@
 		case 0x106b0c00: /* Mac Pro */
 			board_config = ALC885_MACPRO;
 			break;
+		case 0x106b1000: /* iMac 24 */
+			board_config = ALC885_IMAC24;
+			break;
 		default:
 			printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
 		       			 "trying auto-probe from BIOS...\n");
@@ -5501,6 +5661,8 @@
 		}
 	}
 
+	alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+
 	if (board_config == ALC882_AUTO) {
 		/* automatic parse from the BIOS config */
 		err = alc882_parse_auto_config(codec);
@@ -5518,7 +5680,7 @@
 	if (board_config != ALC882_AUTO)
 		setup_preset(spec, &alc882_presets[board_config]);
 
-	if (board_config == ALC885_MACPRO) {
+	if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) {
 		alc882_gpio_mute(codec, 0, 0);
 		alc882_gpio_mute(codec, 1, 0);
 	}
@@ -5995,6 +6157,84 @@
 	{ } /* end */
 };	
 
+static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc883_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -6126,6 +6366,42 @@
 	{ } /* end */
 };
 
+static struct hda_verb alc888_6st_hp_verbs[] = {
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x02},	/* Rear : output 2 (0x0e) */
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* CLFE : output 1 (0x0d) */
+	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},	/* Side : output 3 (0x0f) */
+	{ }
+};
+
+static struct hda_verb alc888_3st_hp_verbs[] = {
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
+	{ }
+};
+
+static struct hda_verb alc888_3st_hp_2ch_init[] = {
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{ 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+	{ }
+};
+
+static struct hda_verb alc888_3st_hp_6ch_init[] = {
+	{ 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{ 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+	{ 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+	{ }
+};
+
+static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+	{ 2, alc888_3st_hp_2ch_init },
+	{ 6, alc888_3st_hp_6ch_init },
+};
+
 /* toggle front-jack and RCA according to the hp-jack state */
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
@@ -6368,11 +6644,14 @@
 	[ALC883_LENOVO_101E_2ch] = "lenovo-101e",
 	[ALC883_LENOVO_NB0763]	= "lenovo-nb0763",
 	[ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+	[ALC888_6ST_HP]		= "6stack-hp",
+	[ALC888_3ST_HP]		= "3stack-hp",
 	[ALC883_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc883_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -6381,6 +6660,8 @@
 	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
@@ -6400,6 +6681,9 @@
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
 	SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+	SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+	SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
 	SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
 	{}
 };
@@ -6584,6 +6868,31 @@
 		.unsol_event = alc883_lenovo_ms7195_unsol_event,
 		.init_hook = alc888_lenovo_ms7195_front_automute,
 	},	
+	[ALC888_6ST_HP] = {
+		.mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.dig_in_nid = ALC883_DIGIN_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+		.channel_mode = alc883_sixstack_modes,
+		.input_mux = &alc883_capture_source,
+	},
+	[ALC888_3ST_HP] = {
+		.mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+		.adc_nids = alc883_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+		.channel_mode = alc888_3st_hp_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_capture_source,
+	},
 };
 
 
@@ -6857,7 +7166,16 @@
 	{ } /* end */
 };
 
-
+static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	{ } /* end */
+};
 
 #define alc262_capture_mixer		alc882_capture_mixer
 #define alc262_capture_alt_mixer	alc882_capture_alt_mixer
@@ -7189,6 +7507,15 @@
 	{}
 };
 
+static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+	{0x20, AC_VERB_SET_PROC_COEF,  0x3050},
+	{}
+};
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 					     const struct auto_pin_cfg *cfg)
@@ -7584,7 +7911,8 @@
 	[ALC262_HP_BPC]		= "hp-bpc",
 	[ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
 	[ALC262_BENQ_ED8]	= "benq",
-	[ALC262_BENQ_ED8]	= "sony-assamd",
+	[ALC262_BENQ_T31]	= "benq-t31",
+	[ALC262_SONY_ASSAMD]	= "sony-assamd",
 	[ALC262_AUTO]		= "auto",
 };
 
@@ -7592,8 +7920,12 @@
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
 	SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -7606,6 +7938,7 @@
 	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
 	SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
 	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
+	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
 	SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
@@ -7710,6 +8043,17 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 		.unsol_event = alc262_hippo_unsol_event,
+	},
+	[ALC262_BENQ_T31] = {
+		.mixers = { alc262_benq_t31_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+		.unsol_event = alc262_hippo_unsol_event,
 	},	
 };
 
@@ -7800,6 +8144,515 @@
 }
 
 /*
+ *  ALC268 channel source setting (2 channel)
+ */
+#define ALC268_DIGOUT_NID	ALC880_DIGOUT_NID
+#define alc268_modes		alc260_modes
+	
+static hda_nid_t alc268_dac_nids[2] = {
+	/* front, hp */
+	0x02, 0x03
+};
+
+static hda_nid_t alc268_adc_nids[2] = {
+	/* ADC0-1 */
+	0x08, 0x07
+};
+
+static hda_nid_t alc268_adc_nids_alt[1] = {
+	/* ADC0 */
+	0x08
+};
+
+static struct snd_kcontrol_new alc268_base_mixer[] = {
+	/* output mixer control */
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	{ }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_base_init_verbs[] = {
+	/* Unmute DAC0-1 and set vol = 0 */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	/*
+	 * Set up output mixers (0x0c - 0x0e)
+	 */
+	/* set vol=0 to output mixers */
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+	/* FIXME: use matrix-type input source selection */
+	/* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
+	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+	/* Input mixer2 */
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+	{ }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_volume_init_verbs[] = {
+	/* set output DAC */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+	/* set PCBEEP vol = 0 */
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
+
+	{ }
+};
+
+#define alc268_mux_enum_info alc_mux_enum_info
+#define alc268_mux_enum_get alc_mux_enum_get
+
+static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	const struct hda_input_mux *imux = spec->input_mux;
+	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+	static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
+	hda_nid_t nid = capture_mixers[adc_idx];
+	unsigned int *cur_val = &spec->cur_mux[adc_idx];
+	unsigned int i, idx;
+
+	idx = ucontrol->value.enumerated.item[0];
+	if (idx >= imux->num_items)
+		idx = imux->num_items - 1;
+	if (*cur_val == idx && !codec->in_resume)
+		return 0;
+	for (i = 0; i < imux->num_items; i++) {
+		unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    v | (imux->items[i].index << 8));
+                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+				    idx );
+	}
+	*cur_val = idx;
+	return 1;
+}
+
+static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc268_mux_enum_info,
+		.get = alc268_mux_enum_get,
+		.put = alc268_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc268_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 * FIXME: the controls appear in the "playback" view!
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc268_mux_enum_info,
+		.get = alc268_mux_enum_get,
+		.put = alc268_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_input_mux alc268_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Front Mic", 0x1 },
+		{ "Line", 0x2 },
+		{ "CD", 0x3 },
+	},
+};
+
+/* create input playback/capture controls for the given pin */
+static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+				    const char *ctlname, int idx)
+{
+	char name[32];
+	int err;
+
+	sprintf(name, "%s Playback Volume", ctlname);
+	if (nid == 0x14) {
+		err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+				  HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
+						      HDA_OUTPUT));
+		if (err < 0)
+			return err;
+	} else if (nid == 0x15) {
+		err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+				  HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+						      HDA_OUTPUT));
+		if (err < 0)
+			return err;
+	} else
+		return -1;
+	sprintf(name, "%s Playback Switch", ctlname);
+	err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+			  HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	hda_nid_t nid;
+	int err;
+
+	spec->multiout.num_dacs = 2;	/* only use one dac */
+	spec->multiout.dac_nids = spec->private_dac_nids;
+	spec->multiout.dac_nids[0] = 2;
+	spec->multiout.dac_nids[1] = 3;
+
+	nid = cfg->line_out_pins[0];
+	if (nid)
+		alc268_new_analog_output(spec, nid, "Front", 0);	
+
+	nid = cfg->speaker_pins[0];
+	if (nid == 0x1d) {
+		err = add_control(spec, ALC_CTL_WIDGET_VOL,
+				  "Speaker Playback Volume",
+				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+		if (err < 0)
+			return err;
+	}
+	nid = cfg->hp_pins[0];
+	if (nid)
+		alc268_new_analog_output(spec, nid, "Headphone", 0);
+
+	nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
+	if (nid == 0x16) {
+		err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+				  "Mono Playback Switch",
+				  HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+		if (err < 0)
+			return err;
+	}
+	return 0;	
+}
+
+/* create playback/capture controls for input pins */
+static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	struct hda_input_mux *imux = &spec->private_imux;
+	int i, idx1;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		switch(cfg->input_pins[i]) {
+		case 0x18:
+			idx1 = 0;	/* Mic 1 */
+			break;
+		case 0x19:
+			idx1 = 1;	/* Mic 2 */
+			break;
+		case 0x1a:
+			idx1 = 2;	/* Line In */
+			break;
+		case 0x1c:	
+			idx1 = 3;	/* CD */
+			break;
+		default:
+			continue;
+		}
+		imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
+		imux->items[imux->num_items].index = idx1;
+		imux->num_items++;	
+	}
+	return 0;
+}
+
+static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+	hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+	hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+	unsigned int	dac_vol1, dac_vol2;
+
+	if (speaker_nid) {
+		snd_hda_codec_write(codec, speaker_nid, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+		snd_hda_codec_write(codec, 0x0f, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(1));
+		snd_hda_codec_write(codec, 0x10, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_IN_UNMUTE(1));
+	} else {
+		snd_hda_codec_write(codec, 0x0f, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+		snd_hda_codec_write(codec, 0x10, 0,
+				    AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+	}
+
+	dac_vol1 = dac_vol2 = 0xb000 | 0x40;	/* set max volume  */
+	if (line_nid == 0x14)	
+		dac_vol2 = AMP_OUT_ZERO;
+	else if (line_nid == 0x15)
+		dac_vol1 = AMP_OUT_ZERO;
+	if (hp_nid == 0x14)	
+		dac_vol2 = AMP_OUT_ZERO;
+	else if (hp_nid == 0x15)
+		dac_vol1 = AMP_OUT_ZERO;
+	if (line_nid != 0x16 || hp_nid != 0x16 ||
+	    spec->autocfg.line_out_pins[1] != 0x16 ||
+	    spec->autocfg.line_out_pins[2] != 0x16)
+		dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
+
+	snd_hda_codec_write(codec, 0x02, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
+	snd_hda_codec_write(codec, 0x03, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
+}
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc268_pcm_analog_playback	alc880_pcm_analog_playback
+#define alc268_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc268_pcm_digital_playback	alc880_pcm_digital_playback
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	static hda_nid_t alc268_ignore[] = { 0 };
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+					   alc268_ignore);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs)
+		return 0; /* can't find valid BIOS pin config */
+
+	err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = 2;
+
+	/* digital only support output */
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+	spec->num_mux_defs = 1;
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+#define alc268_auto_init_multi_out	alc882_auto_init_multi_out
+#define alc268_auto_init_hp_out		alc882_auto_init_hp_out
+#define alc268_auto_init_analog_input	alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc268_auto_init(struct hda_codec *codec)
+{
+	alc268_auto_init_multi_out(codec);
+	alc268_auto_init_hp_out(codec);
+	alc268_auto_init_mono_speaker_out(codec);
+	alc268_auto_init_analog_input(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc268_models[ALC268_MODEL_LAST] = {
+	[ALC268_3ST]		= "3stack",
+	[ALC268_AUTO]		= "auto",
+};
+
+static struct snd_pci_quirk alc268_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+	{}
+};
+
+static struct alc_config_preset alc268_presets[] = {
+	[ALC268_3ST] = {
+		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+		.init_verbs = { alc268_base_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+                .adc_nids = alc268_adc_nids_alt,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC268_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+	},
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int board_config;
+	int err;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+						  alc268_models,
+						  alc268_cfg_tbl);
+
+	if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+		printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+		       "trying auto-probe from BIOS...\n");
+		board_config = ALC268_AUTO;
+	}
+
+	if (board_config == ALC268_AUTO) {
+		/* automatic parse from the BIOS config */
+		err = alc268_parse_auto_config(codec);
+		if (err < 0) {
+			alc_free(codec);
+			return err;
+		} else if (!err) {
+			printk(KERN_INFO
+			       "hda_codec: Cannot set up configuration "
+			       "from BIOS.  Using base mode...\n");
+			board_config = ALC268_3ST;
+		}
+	}
+
+	if (board_config != ALC268_AUTO)
+		setup_preset(spec, &alc268_presets[board_config]);
+
+	spec->stream_name_analog = "ALC268 Analog";
+	spec->stream_analog_playback = &alc268_pcm_analog_playback;
+	spec->stream_analog_capture = &alc268_pcm_analog_capture;
+
+	spec->stream_name_digital = "ALC268 Digital";
+	spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+	if (board_config == ALC268_AUTO) {
+		if (!spec->adc_nids && spec->input_mux) {
+			/* check whether NID 0x07 is valid */
+			unsigned int wcap = get_wcaps(codec, 0x07);
+
+			/* get type */
+			wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+			if (wcap != AC_WID_AUD_IN) {
+				spec->adc_nids = alc268_adc_nids_alt;
+				spec->num_adc_nids =
+					ARRAY_SIZE(alc268_adc_nids_alt);
+				spec->mixers[spec->num_mixers] =
+					alc268_capture_alt_mixer;
+				spec->num_mixers++;
+			} else {
+				spec->adc_nids = alc268_adc_nids;
+				spec->num_adc_nids =
+					ARRAY_SIZE(alc268_adc_nids);
+				spec->mixers[spec->num_mixers] =
+					alc268_capture_mixer;
+				spec->num_mixers++;
+			}
+		}
+	}
+	codec->patch_ops = alc_patch_ops;
+	if (board_config == ALC268_AUTO)
+		spec->init_hook = alc268_auto_init;
+		
+	return 0;
+}
+
+/*
  *  ALC861 channel source setting (2/6 channel selection for 3-stack)
  */
 
@@ -8767,13 +9620,21 @@
 	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
+	SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+	SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
 	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
-	SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+	/* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
+	 *        Any other models that need this preset?
+	 */
+	/* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
 	SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
 	SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
 	SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
 	SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
+	SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+	SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
 	{}
 };
 
@@ -9464,6 +10325,7 @@
  */
 static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
 	[ALC660VD_3ST]		= "3stack-660",
+	[ALC660VD_3ST_DIG]= "3stack-660-digout",
 	[ALC861VD_3ST]		= "3stack",
 	[ALC861VD_3ST_DIG]	= "3stack-digout",
 	[ALC861VD_6ST_DIG]	= "6stack-digout",
@@ -9475,7 +10337,7 @@
 static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
-	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST),
+	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
 	SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 
@@ -9483,6 +10345,7 @@
 	SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
 	SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
 	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
 	{}
 };
 
@@ -9499,6 +10362,19 @@
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
 	},
+	[ALC660VD_3ST_DIG] = {
+		.mixers = { alc861vd_3st_mixer },
+		.init_verbs = { alc861vd_volume_init_verbs,
+				 alc861vd_3stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+		.dac_nids = alc660vd_dac_nids,
+		.dig_out_nid = ALC861VD_DIGOUT_NID,
+		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+		.adc_nids = alc861vd_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+		.channel_mode = alc861vd_3stack_2ch_modes,
+		.input_mux = &alc861vd_capture_source,
+	},
 	[ALC861VD_3ST] = {
 		.mixers = { alc861vd_3st_mixer },
 		.init_verbs = { alc861vd_volume_init_verbs,
@@ -10420,7 +11296,7 @@
 	for (i = 0; i < cfg->line_outs; i++) {
 		if (!spec->multiout.dac_nids[i])
 			continue;
-		nid = alc880_idx_to_dac(i);
+		nid = alc880_idx_to_mixer(i);
 		if (i == 2) {
 			/* Center/LFE */
 			err = add_control(spec, ALC_CTL_WIDGET_VOL,
@@ -10643,14 +11519,10 @@
 	spec->num_mux_defs = 1;
 	spec->input_mux = &spec->private_imux;
 	
-	if (err < 0)
-		return err;
-	else if (err > 0)
-		/* hack - override the init verbs */
-		spec->init_verbs[0] = alc662_auto_init_verbs;
+	spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
 	spec->mixers[spec->num_mixers] = alc662_capture_mixer;
 	spec->num_mixers++;
-	return err;
+	return 1;
 }
 
 /* additional initialization for auto-configuration model */
@@ -10687,7 +11559,7 @@
 		if (err < 0) {
 			alc_free(codec);
 			return err;
-		} else if (err) {
+		} else if (!err) {
 			printk(KERN_INFO
 			       "hda_codec: Cannot set up configuration "
 			       "from BIOS.  Using base mode...\n");
@@ -10724,6 +11596,7 @@
 struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+	{ .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	  .patch = patch_alc861 },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 43f537e..6d2ecc3 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -304,8 +304,12 @@
  	{ .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+	/* VIA HDA on Clevo m540 */
+	{ .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 },
 	/* Asus A8J Modem (SM56) */
 	{ .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 },
+	/* LG LW20 modem */
+	{ .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 },
 	{}
 };
 
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index e3964fc..3f25de7 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -44,6 +44,7 @@
 
 enum {
 	STAC_9205_REF,
+	STAC_M43xx,
 	STAC_9205_MODELS
 };
 
@@ -59,11 +60,19 @@
 	STAC_D945_REF,
 	STAC_D945GTP3,
 	STAC_D945GTP5,
+	STAC_922X_DELL,
+	STAC_INTEL_MAC_V1,
+	STAC_INTEL_MAC_V2,
+	STAC_INTEL_MAC_V3,
+	STAC_INTEL_MAC_V4,
+	STAC_INTEL_MAC_V5,
+	/* for backward compitability */
 	STAC_MACMINI,
 	STAC_MACBOOK,
 	STAC_MACBOOK_PRO_V1,
 	STAC_MACBOOK_PRO_V2,
 	STAC_IMAC_INTEL,
+	STAC_IMAC_INTEL_20,
 	STAC_922X_MODELS
 };
 
@@ -210,7 +219,6 @@
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x14, 0x16, 0x17, 0x18,
 	0x21, 0x22,
-	
 };
 
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
@@ -326,8 +334,6 @@
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Input Source",
@@ -549,44 +555,78 @@
 	0x02a19320, 0x40000100,
 };
 
-static unsigned int macbook_pro_v1_pin_configs[10] = {
-	0x0321e230, 0x03a1e020, 0x9017e110, 0x01014010,
-	0x01a19021, 0x0381e021, 0x1345e240, 0x13c5e22e,
-	0x02a19320, 0x400000fb
-};
-
-static unsigned int macbook_pro_v2_pin_configs[10] = {
-	0x0221401f, 0x90a70120, 0x01813024, 0x01014010,
-	0x400000fd, 0x01016011, 0x1345e240, 0x13c5e22e,
+static unsigned int intel_mac_v1_pin_configs[10] = {
+	0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
+	0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
 	0x400000fc, 0x400000fb,
 };
 
-static unsigned int imac_intel_pin_configs[10] = {
-	0x0121e230, 0x90a70120, 0x9017e110, 0x400000fe,
-	0x400000fd, 0x0181e021, 0x1145e040, 0x400000fa,
+static unsigned int intel_mac_v2_pin_configs[10] = {
+	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+	0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
 	0x400000fc, 0x400000fb,
 };
 
+static unsigned int intel_mac_v3_pin_configs[10] = {
+	0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+	0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
+	0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v4_pin_configs[10] = {
+	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
+	0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v5_pin_configs[10] = {
+	0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+	0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
+	0x400000fc, 0x400000fb,
+};
+
+static unsigned int stac922x_dell_pin_configs[10] = {
+	0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310,
+	0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2,
+	0x50a003f3, 0x405003f4
+};
+
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
 	[STAC_D945_REF] = ref922x_pin_configs,
 	[STAC_D945GTP3] = d945gtp3_pin_configs,
 	[STAC_D945GTP5] = d945gtp5_pin_configs,
-	[STAC_MACMINI] = macbook_pro_v1_pin_configs,
-	[STAC_MACBOOK] = macbook_pro_v1_pin_configs,
-	[STAC_MACBOOK_PRO_V1] = macbook_pro_v1_pin_configs,
-	[STAC_MACBOOK_PRO_V2] = macbook_pro_v2_pin_configs,
-	[STAC_IMAC_INTEL] = imac_intel_pin_configs,
+	[STAC_922X_DELL] = stac922x_dell_pin_configs,
+	[STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
+	[STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
+	[STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
+	[STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
+	[STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
+	/* for backward compitability */
+	[STAC_MACMINI] = intel_mac_v3_pin_configs,
+	[STAC_MACBOOK] = intel_mac_v5_pin_configs,
+	[STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
+	[STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
+	[STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
+	[STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
 };
 
 static const char *stac922x_models[STAC_922X_MODELS] = {
 	[STAC_D945_REF]	= "ref",
 	[STAC_D945GTP5]	= "5stack",
 	[STAC_D945GTP3]	= "3stack",
+	[STAC_922X_DELL] = "dell",
+	[STAC_INTEL_MAC_V1] = "intel-mac-v1",
+	[STAC_INTEL_MAC_V2] = "intel-mac-v2",
+	[STAC_INTEL_MAC_V3] = "intel-mac-v3",
+	[STAC_INTEL_MAC_V4] = "intel-mac-v4",
+	[STAC_INTEL_MAC_V5] = "intel-mac-v5",
+	/* for backward compitability */
 	[STAC_MACMINI]	= "macmini",
 	[STAC_MACBOOK]	= "macbook",
 	[STAC_MACBOOK_PRO_V1]	= "macbook-pro-v1",
 	[STAC_MACBOOK_PRO_V2]	= "macbook-pro",
 	[STAC_IMAC_INTEL] = "imac-intel",
+	[STAC_IMAC_INTEL_20] = "imac-intel-20",
 };
 
 static struct snd_pci_quirk stac922x_cfg_tbl[] = {
@@ -649,7 +689,10 @@
 	/* other systems  */
 	/* Apple Mac Mini (early 2006) */
 	SND_PCI_QUIRK(0x8384, 0x7680,
-		      "Mac Mini", STAC_MACMINI),
+		      "Mac Mini", STAC_INTEL_MAC_V3),
+	/* Dell */
+	SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL),
+
 	{} /* terminator */
 };
 
@@ -730,7 +773,8 @@
 };
 
 static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
-	ref9205_pin_configs,
+	[STAC_REF] = ref9205_pin_configs,
+	[STAC_M43xx] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -741,6 +785,10 @@
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_9205_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
+		      "Dell Precision", STAC_M43xx),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
+		      "Dell Precision", STAC_M43xx),
 	{} /* terminator */
 };
 
@@ -770,33 +818,56 @@
 	return 0;
 }
 
+static void stac92xx_set_config_reg(struct hda_codec *codec,
+				    hda_nid_t pin_nid, unsigned int pin_config)
+{
+	int i;
+	snd_hda_codec_write(codec, pin_nid, 0,
+			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+			    pin_config & 0x000000ff);
+	snd_hda_codec_write(codec, pin_nid, 0,
+			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+			    (pin_config & 0x0000ff00) >> 8);
+	snd_hda_codec_write(codec, pin_nid, 0,
+			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+			    (pin_config & 0x00ff0000) >> 16);
+	snd_hda_codec_write(codec, pin_nid, 0,
+			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+			    pin_config >> 24);
+	i = snd_hda_codec_read(codec, pin_nid, 0,
+			       AC_VERB_GET_CONFIG_DEFAULT,
+			       0x00);	
+	snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
+		    pin_nid, i);
+}
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
 	int i;
 	struct sigmatel_spec *spec = codec->spec;
-	unsigned int pin_cfg;
 
-	if (! spec->pin_nids || ! spec->pin_configs)
-		return;
+ 	if (!spec->pin_configs)
+ 		return;
 
-	for (i = 0; i < spec->num_pins; i++) {
-		snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-				    spec->pin_configs[i] & 0x000000ff);
-		snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-				    (spec->pin_configs[i] & 0x0000ff00) >> 8);
-		snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-				    (spec->pin_configs[i] & 0x00ff0000) >> 16);
-		snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-				    spec->pin_configs[i] >> 24);
-		pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
-					     AC_VERB_GET_CONFIG_DEFAULT,
-					     0x00);	
-		snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
-	}
+	for (i = 0; i < spec->num_pins; i++)
+		stac92xx_set_config_reg(codec, spec->pin_nids[i],
+					spec->pin_configs[i]);
+}
+
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
+				      int gpio_mask, int gpio_data)
+{
+	/* Configure GPIOx as output */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+	/* Configure GPIOx as CMOS */
+	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+	/* Assert GPIOx */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_DATA, gpio_data);
+	/* Enable GPIOx */
+	snd_hda_codec_write(codec, codec->afg, 0,
+			    AC_VERB_SET_GPIO_MASK, gpio_mask);
 }
 
 /*
@@ -1168,7 +1239,7 @@
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-				       const struct auto_pin_cfg *cfg)
+				       struct auto_pin_cfg *cfg)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int i, j, conn_len = 0; 
@@ -1193,6 +1264,13 @@
 		}
 
 		if (j == conn_len) {
+			if (spec->multiout.num_dacs > 0) {
+				/* we have already working output pins,
+				 * so let's drop the broken ones again
+				 */
+				cfg->line_outs = spec->multiout.num_dacs;
+				break;
+			}
 			/* error out, no available DAC found */
 			snd_printk(KERN_ERR
 				   "%s: No available DAC for pin 0x%x\n",
@@ -1334,7 +1412,15 @@
 			continue;
 		add_spec_dacs(spec, nid);
 	}
-
+	for (i = 0; i < cfg->line_outs; i++) {
+		nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
+					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+		if (check_in_dac_nids(spec, nid))
+			nid = 0;
+		if (! nid)
+			continue;
+		add_spec_dacs(spec, nid);
+	}
 	for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
 		static const char *pfxs[] = {
 			"Speaker", "External Speaker", "Speaker2",
@@ -1891,7 +1977,7 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->num_pins = 8;
+	spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
 	spec->pin_nids = stac9200_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
 							stac9200_models,
@@ -1941,7 +2027,7 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->num_pins = 8;
+	spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
 	spec->pin_nids = stac925x_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
 							stac925x_models,
@@ -2013,29 +2099,41 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->num_pins = 10;
+	spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
 	spec->pin_nids = stac922x_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
 							stac922x_models,
 							stac922x_cfg_tbl);
-	if (spec->board_config == STAC_MACMINI) {
+	if (spec->board_config == STAC_INTEL_MAC_V3) {
 		spec->gpio_mute = 1;
 		/* Intel Macs have all same PCI SSID, so we need to check
 		 * codec SSID to distinguish the exact models
 		 */
 		printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
 		switch (codec->subsystem_id) {
-		case 0x106b0a00: /* MacBook First generatoin */
-			spec->board_config = STAC_MACBOOK;
+
+		case 0x106b0800:
+			spec->board_config = STAC_INTEL_MAC_V1;
 			break;
-		case 0x106b0200: /* MacBook Pro first generation */
-			spec->board_config = STAC_MACBOOK_PRO_V1;
+		case 0x106b0600:
+		case 0x106b0700:
+			spec->board_config = STAC_INTEL_MAC_V2;
 			break;
-		case 0x106b1e00: /* MacBook Pro second generation */
-			spec->board_config = STAC_MACBOOK_PRO_V2;
+		case 0x106b0e00:
+		case 0x106b0f00:
+		case 0x106b1600:
+		case 0x106b1700:
+		case 0x106b0200:
+		case 0x106b1e00:
+			spec->board_config = STAC_INTEL_MAC_V3;
 			break;
-		case 0x106b0700: /* Intel-based iMac */
-			spec->board_config = STAC_IMAC_INTEL;
+		case 0x106b1a00:
+		case 0x00000100:
+			spec->board_config = STAC_INTEL_MAC_V4;
+			break;
+		case 0x106b0a00:
+		case 0x106b2200:
+			spec->board_config = STAC_INTEL_MAC_V5;
 			break;
 		}
 	}
@@ -2082,6 +2180,13 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	/* Fix Mux capture level; max to 2 */
+	snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
+				  (0 << AC_AMPCAP_OFFSET_SHIFT) |
+				  (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+				  (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+				  (0 << AC_AMPCAP_MUTE_SHIFT));
+
 	return 0;
 }
 
@@ -2095,7 +2200,7 @@
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->num_pins = 14;
+	spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
 	spec->pin_nids = stac927x_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
 							stac927x_models,
@@ -2141,7 +2246,9 @@
 	}
 
 	spec->multiout.dac_nids = spec->dac_nids;
-
+	/* GPIO0 High = Enable EAPD */
+	stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
+	
 	err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
 	if (!err) {
 		if (spec->board_config < 0) {
@@ -2159,27 +2266,20 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
-	/* Fix Mux capture level; max to 2 */
-	snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
-				  (0 << AC_AMPCAP_OFFSET_SHIFT) |
-				  (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-				  (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-				  (0 << AC_AMPCAP_MUTE_SHIFT));
-
 	return 0;
 }
 
 static int patch_stac9205(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
-	int err;
+	int err, gpio_mask, gpio_data;
 
 	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
 	codec->spec = spec;
-	spec->num_pins = 14;
+	spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
 	spec->pin_nids = stac9205_pin_nids;
 	spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
 							stac9205_models,
@@ -2209,19 +2309,21 @@
 	spec->mixer = stac9205_mixer;
 
 	spec->multiout.dac_nids = spec->dac_nids;
+	
+	if (spec->board_config == STAC_M43xx) {
+		/* Enable SPDIF in/out */
+		stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
+		stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
 
-	/* Configure GPIO0 as EAPD output */
-	snd_hda_codec_write(codec, codec->afg, 0,
-			    AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
-	/* Configure GPIO0 as CMOS */
-	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
-	/* Assert GPIO0 high */
-	snd_hda_codec_write(codec, codec->afg, 0,
-			    AC_VERB_SET_GPIO_DATA, 0x00000001);
-	/* Enable GPIO0 */
-	snd_hda_codec_write(codec, codec->afg, 0,
-			    AC_VERB_SET_GPIO_MASK, 0x00000001);
+		gpio_mask = 0x00000007; /* GPIO0-2 */
+		/* GPIO0 High = EAPD, GPIO1 Low = DRM,
+		 * GPIO2 High = Headphone Mute
+		 */
+		gpio_data = 0x00000005;
+	} else
+		gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
+	stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
 	err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
 	if (!err) {
 		if (spec->board_config < 0) {
@@ -2256,8 +2358,8 @@
 	.num_items = 2,
 	.items = {
 		/* { "HP", 0x0 }, */
-		{ "Line", 0x1 },
-		{ "Mic", 0x2 },
+		{ "Mic Jack", 0x1 },
+		{ "Internal Mic", 0x2 },
 		{ "PCM", 0x3 },
 	}
 };
@@ -2268,7 +2370,7 @@
 	{0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
 	{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
@@ -2284,7 +2386,7 @@
 	{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
 /*	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
 	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
 /*	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 690ceb3..d18a31e 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -186,7 +186,12 @@
 #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
 
 static const struct snd_akm4xxx_dac_channel revo71_front[] = {
-	AK_DAC("PCM Playback Volume", 2)
+	{
+		.name = "PCM Playback Volume",
+		.num_channels = 2,
+		/* front channels DAC supports muting */
+		.switch_name = "PCM Playback Switch",
+	},
 };
 
 static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 03b3a47..c7621bd 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1533,7 +1533,8 @@
 				printk(KERN_ERR "  force the driver to load by "
 				       "passing in the module parameter\n");
 				printk(KERN_ERR "    force_ac97=1\n");
-				printk(KERN_ERR "  or try sb16 or cs423x drivers instead.\n");
+				printk(KERN_ERR "  or try sb16, opl3sa2, or "
+				       "cs423x drivers instead.\n");
 				err = -ENXIO;
 				goto __error;
 			}
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index bd7dbd2..2de2740 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -406,7 +406,7 @@
 		} else if (!frag)
 			return 0;
 		offset -= rme9652->max_jitter;
-		if (offset < 0)
+		if ((int)offset < 0)
 			offset += period_size * 2;
 	} else {
 		if (offset > period_size + rme9652->max_jitter) {
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 50c9f92..6ea09df 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2098,7 +2098,7 @@
 		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
 		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
 			break;
-		schedule_timeout_uninterruptible(1);
+		schedule_timeout(1);
 	} while (time_before(jiffies, end_time));
 
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -2117,7 +2117,7 @@
 			chip->ac97_secondary = 1;
 			goto __ac97_ok2;
 		}
-		schedule_timeout_interruptible(1);
+		schedule_timeout(1);
 	} while (time_before(jiffies, end_time));
 	/* This is ok, the most of motherboards have only one codec */
 
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 8cbf8eb..72425e7 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -983,7 +983,7 @@
 		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
 		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
 			break;
-		schedule_timeout_uninterruptible(1);
+		schedule_timeout(1);
 	} while (time_before(jiffies, end_time));
 
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -1001,7 +1001,7 @@
 			chip->ac97_secondary = 1;
 			goto __ac97_ok2;
 		}
-		schedule_timeout_interruptible(1);
+		schedule_timeout(1);
 	} while (time_before(jiffies, end_time));
 	/* This is ok, the most of motherboards have only one codec */
 
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
index a3fb149..cacb0b1 100644
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -33,3 +33,23 @@
 	  option.
 
 endmenu
+
+menu "ALSA PowerPC devices"
+	depends on SND!=n && ( PPC64 || PPC32 )
+
+config SND_PS3
+	tristate "PS3 Audio support"
+	depends on SND && PS3_PS3AV
+	select SND_PCM
+	default m
+	help
+	  Say Y here to include support for audio on the PS3
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd_ps3.
+
+config SND_PS3_DEFAULT_START_DELAY
+	int "Startup delay time in ms"
+	depends on SND_PS3
+	default "2000"
+endmenu
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
index 4d95c65..eacee2d 100644
--- a/sound/ppc/Makefile
+++ b/sound/ppc/Makefile
@@ -6,4 +6,5 @@
 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
+obj-$(CONFIG_SND_POWERMAC)	+= snd-powermac.o
+obj-$(CONFIG_SND_PS3)		+= snd_ps3.o
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
new file mode 100644
index 0000000..1aa0b46
--- /dev/null
+++ b/sound/ppc/snd_ps3.c
@@ -0,0 +1,1125 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony 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; version 2 of the Licence.
+ *
+ * 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/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/asound.h>
+#include <sound/memalloc.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <asm/firmware.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+#include <asm/ps3av.h>
+
+#include "snd_ps3_reg.h"
+#include "snd_ps3.h"
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+
+/* module  entries */
+static int __init snd_ps3_init(void);
+static void __exit snd_ps3_exit(void);
+
+/* ALSA snd driver ops */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+				 int cmd);
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
+					     *substream);
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params);
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
+
+
+/* ps3_system_bus_driver entries */
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
+
+/* address setup */
+static int snd_ps3_map_mmio(void);
+static void snd_ps3_unmap_mmio(void);
+static int snd_ps3_allocate_irq(void);
+static void snd_ps3_free_irq(void);
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
+
+/* interrupt handler */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
+
+
+/* set sampling rate/format */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
+/* take effect parameter change */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
+/* initialize avsetting and take it effect */
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
+/* setup dma */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+			       enum snd_ps3_dma_filltype filltype);
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
+
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  *vaddr, int ch);
+
+
+module_init(snd_ps3_init);
+module_exit(snd_ps3_exit);
+
+/*
+ * global
+ */
+static struct snd_ps3_card_info the_card;
+
+static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
+
+module_param_named(start_delay, snd_ps3_start_delay, uint, 0644);
+MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for PS3 soundchip.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for PS3 soundchip.");
+
+
+/*
+ * PS3 audio register access
+ */
+static inline u32 read_reg(unsigned int reg)
+{
+	return in_be32(the_card.mapped_mmio_vaddr + reg);
+}
+static inline void write_reg(unsigned int reg, u32 val)
+{
+	out_be32(the_card.mapped_mmio_vaddr + reg, val);
+}
+static inline void update_reg(unsigned int reg, u32 or_val)
+{
+	u32 newval = read_reg(reg) | or_val;
+	write_reg(reg, newval);
+}
+static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val)
+{
+	u32 newval = (read_reg(reg) & mask) | or_val;
+	write_reg(reg, newval);
+}
+
+/*
+ * ALSA defs
+ */
+const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_NONINTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats = (SNDRV_PCM_FMTBIT_S16_BE |
+		    SNDRV_PCM_FMTBIT_S24_BE),
+	.rates = (SNDRV_PCM_RATE_44100 |
+		  SNDRV_PCM_RATE_48000 |
+		  SNDRV_PCM_RATE_88200 |
+		  SNDRV_PCM_RATE_96000),
+	.rate_min = 44100,
+	.rate_max = 96000,
+
+	.channels_min = 2, /* stereo only */
+	.channels_max = 2,
+
+	.buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
+
+	/* interrupt by four stages */
+	.period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+	.period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+
+	.periods_min = 16,
+	.periods_max = 32, /* buffer_size_max/ period_bytes_max */
+
+	.fifo_size = PS3_AUDIO_FIFO_SIZE
+};
+
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
+{
+	.open = snd_ps3_pcm_open,
+	.close = snd_ps3_pcm_close,
+	.prepare = snd_ps3_pcm_prepare,
+	.ioctl = snd_pcm_lib_ioctl,
+	.trigger = snd_ps3_pcm_trigger,
+	.pointer = snd_ps3_pcm_pointer,
+	.hw_params = snd_ps3_pcm_hw_params,
+	.hw_free = snd_ps3_pcm_hw_free
+};
+
+static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
+				   int count, int force_stop)
+{
+	int dma_ch, done, retries, stop_forced = 0;
+	uint32_t status;
+
+	for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+		retries = count;
+		do {
+			status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
+				PS3_AUDIO_KICK_STATUS_MASK;
+			switch (status) {
+			case PS3_AUDIO_KICK_STATUS_DONE:
+			case PS3_AUDIO_KICK_STATUS_NOTIFY:
+			case PS3_AUDIO_KICK_STATUS_CLEAR:
+			case PS3_AUDIO_KICK_STATUS_ERROR:
+				done = 1;
+				break;
+			default:
+				done = 0;
+				udelay(10);
+			}
+		} while (!done && --retries);
+		if (!retries && force_stop) {
+			pr_info("%s: DMA ch %d is not stopped.",
+				__func__, dma_ch);
+			/* last resort. force to stop dma.
+			 *  NOTE: this cause DMA done interrupts
+			 */
+			update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR);
+			stop_forced = 1;
+		}
+	}
+	return stop_forced;
+}
+
+/*
+ * wait for all dma is done.
+ * NOTE: caller should reset card->running before call.
+ *       If not, the interrupt handler will re-start DMA,
+ *       then DMA is never stopped.
+ */
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card)
+{
+	int stop_forced;
+	/*
+	 * wait for the last dma is done
+	 */
+
+	/*
+	 * expected maximum DMA done time is 5.7ms + something (DMA itself).
+	 * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next
+	 * DMA kick event would occur.
+	 */
+	stop_forced = snd_ps3_verify_dma_stop(card, 700, 1);
+
+	/*
+	 * clear outstanding interrupts.
+	 */
+	update_reg(PS3_AUDIO_INTR_0, 0);
+	update_reg(PS3_AUDIO_AX_IS, 0);
+
+	/*
+	 *revert CLEAR bit since it will not reset automatically after DMA stop
+	 */
+	if (stop_forced)
+		update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0);
+	/* ensure the hardware sees changes */
+	wmb();
+}
+
+static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
+{
+
+	update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
+	/* ensure the hardware sees the change */
+	wmb();
+}
+
+/*
+ * convert virtual addr to ioif bus addr.
+ */
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
+			   void * paddr,
+			   int ch)
+{
+	return card->dma_start_bus_addr[ch] +
+		(paddr - card->dma_start_vaddr[ch]);
+};
+
+
+/*
+ * increment ring buffer pointer.
+ * NOTE: caller must hold write spinlock
+ */
+static void snd_ps3_bump_buffer(struct snd_ps3_card_info *card,
+				enum snd_ps3_ch ch, size_t byte_count,
+				int stage)
+{
+	if (!stage)
+		card->dma_last_transfer_vaddr[ch] =
+			card->dma_next_transfer_vaddr[ch];
+	card->dma_next_transfer_vaddr[ch] += byte_count;
+	if ((card->dma_start_vaddr[ch] + (card->dma_buffer_size / 2)) <=
+	    card->dma_next_transfer_vaddr[ch]) {
+		card->dma_next_transfer_vaddr[ch] = card->dma_start_vaddr[ch];
+	}
+}
+/*
+ * setup dmac to send data to audio and attenuate samples on the ring buffer
+ */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+			       enum snd_ps3_dma_filltype filltype)
+{
+	/* this dmac does not support over 4G */
+	uint32_t dma_addr;
+	int fill_stages, dma_ch, stage;
+	enum snd_ps3_ch ch;
+	uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
+	void *start_vaddr;
+	unsigned long irqsave;
+	int silent = 0;
+
+	switch (filltype) {
+	case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL:
+		silent = 1;
+		/* intentionally fall thru */
+	case SND_PS3_DMA_FILLTYPE_FIRSTFILL:
+		ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS;
+		break;
+
+	case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING:
+		silent = 1;
+		/* intentionally fall thru */
+	case SND_PS3_DMA_FILLTYPE_RUNNING:
+		ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY;
+		break;
+	}
+
+	snd_ps3_verify_dma_stop(card, 700, 0);
+	fill_stages = 4;
+	spin_lock_irqsave(&card->dma_lock, irqsave);
+	for (ch = 0; ch < 2; ch++) {
+		start_vaddr = card->dma_next_transfer_vaddr[0];
+		for (stage = 0; stage < fill_stages; stage ++) {
+			dma_ch = stage * 2 + ch;
+			if (silent)
+				dma_addr = card->null_buffer_start_dma_addr;
+			else
+				dma_addr =
+				v_to_bus(card,
+					 card->dma_next_transfer_vaddr[ch],
+					 ch);
+
+			write_reg(PS3_AUDIO_SOURCE(dma_ch),
+				  (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY |
+				   dma_addr));
+
+			/* dst: fixed to 3wire#0 */
+			if (ch == 0)
+				write_reg(PS3_AUDIO_DEST(dma_ch),
+					  (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+					   PS3_AUDIO_AO_3W_LDATA(0)));
+			else
+				write_reg(PS3_AUDIO_DEST(dma_ch),
+					  (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+					   PS3_AUDIO_AO_3W_RDATA(0)));
+
+			/* count always 1 DMA block (1/2 stage = 128 bytes) */
+			write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0);
+			/* bump pointer if needed */
+			if (!silent)
+				snd_ps3_bump_buffer(card, ch,
+						    PS3_AUDIO_DMAC_BLOCK_SIZE,
+						    stage);
+
+			/* kick event  */
+			if (dma_ch == 0)
+				write_reg(PS3_AUDIO_KICK(dma_ch),
+					  ch0_kick_event);
+			else
+				write_reg(PS3_AUDIO_KICK(dma_ch),
+					  PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch
+									 - 1) |
+					  PS3_AUDIO_KICK_REQUEST);
+		}
+	}
+	/* ensure the hardware sees the change */
+	wmb();
+	spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+	return 0;
+}
+
+/*
+ * audio mute on/off
+ * mute_on : 0 output enabled
+ *           1 mute
+ */
+static int snd_ps3_mute(int mute_on)
+{
+	return ps3av_audio_mute(mute_on);
+}
+
+/*
+ * PCM operators
+ */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	int pcm_index;
+
+	pcm_index = substream->pcm->device;
+	/* to retrieve substream/runtime in interrupt handler */
+	card->substream = substream;
+
+	runtime->hw = snd_ps3_pcm_hw;
+
+	card->start_delay = snd_ps3_start_delay;
+
+	/* mute off */
+	snd_ps3_mute(0); /* this function sleep */
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				   PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2);
+	return 0;
+};
+
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	size_t size;
+
+	/* alloc transport buffer */
+	size = params_buffer_bytes(hw_params);
+	snd_pcm_lib_malloc_pages(substream, size);
+	return 0;
+};
+
+static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
+				  unsigned int delay_ms)
+{
+	int ret;
+	int rate ;
+
+	rate = substream->runtime->rate;
+	ret = snd_pcm_format_size(substream->runtime->format,
+				  rate * delay_ms / 1000)
+		* substream->runtime->channels;
+
+	pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+		 __func__,
+		 delay_ms,
+		 rate,
+		 snd_pcm_format_size(substream->runtime->format, rate),
+		 rate * delay_ms / 1000,
+		 ret);
+
+	return ret;
+};
+
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	unsigned long irqsave;
+
+	if (!snd_ps3_set_avsetting(substream)) {
+		/* some parameter changed */
+		write_reg(PS3_AUDIO_AX_IE,
+			  PS3_AUDIO_AX_IE_ASOBEIE(0) |
+			  PS3_AUDIO_AX_IE_ASOBUIE(0));
+		/*
+		 * let SPDIF device re-lock with SPDIF signal,
+		 * start with some silence
+		 */
+		card->silent = snd_ps3_delay_to_bytes(substream,
+						      card->start_delay) /
+			(PS3_AUDIO_FIFO_STAGE_SIZE * 4); /* every 4 times */
+	}
+
+	/* restart ring buffer pointer */
+	spin_lock_irqsave(&card->dma_lock, irqsave);
+	{
+		card->dma_buffer_size = runtime->dma_bytes;
+
+		card->dma_last_transfer_vaddr[SND_PS3_CH_L] =
+			card->dma_next_transfer_vaddr[SND_PS3_CH_L] =
+			card->dma_start_vaddr[SND_PS3_CH_L] =
+			runtime->dma_area;
+		card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr;
+
+		card->dma_last_transfer_vaddr[SND_PS3_CH_R] =
+			card->dma_next_transfer_vaddr[SND_PS3_CH_R] =
+			card->dma_start_vaddr[SND_PS3_CH_R] =
+			runtime->dma_area + (runtime->dma_bytes / 2);
+		card->dma_start_bus_addr[SND_PS3_CH_R] =
+			runtime->dma_addr + (runtime->dma_bytes / 2);
+
+		pr_debug("%s: vaddr=%p bus=%#lx\n", __func__,
+			 card->dma_start_vaddr[SND_PS3_CH_L],
+			 card->dma_start_bus_addr[SND_PS3_CH_L]);
+
+	}
+	spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+	/* ensure the hardware sees the change */
+	mb();
+
+	return 0;
+};
+
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+			       int cmd)
+{
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* clear outstanding interrupts  */
+		update_reg(PS3_AUDIO_AX_IS, 0);
+
+		spin_lock(&card->dma_lock);
+		{
+			card->running = 1;
+		}
+		spin_unlock(&card->dma_lock);
+
+		snd_ps3_program_dma(card,
+				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+		snd_ps3_kick_dma(card);
+		while (read_reg(PS3_AUDIO_KICK(7)) &
+		       PS3_AUDIO_KICK_STATUS_MASK) {
+			udelay(1);
+		}
+		snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+		snd_ps3_kick_dma(card);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		spin_lock(&card->dma_lock);
+		{
+			card->running = 0;
+		}
+		spin_unlock(&card->dma_lock);
+		snd_ps3_wait_for_dma_stop(card);
+		break;
+	default:
+		break;
+
+	}
+
+	return ret;
+};
+
+/*
+ * report current pointer
+ */
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(
+	struct snd_pcm_substream *substream)
+{
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	size_t bytes;
+	snd_pcm_uframes_t ret;
+
+	spin_lock(&card->dma_lock);
+	{
+		bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
+				 card->dma_start_vaddr[SND_PS3_CH_L]);
+	}
+	spin_unlock(&card->dma_lock);
+
+	ret = bytes_to_frames(substream->runtime, bytes * 2);
+
+	return ret;
+};
+
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	int ret;
+	ret = snd_pcm_lib_free_pages(substream);
+	return ret;
+};
+
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+	/* mute on */
+	snd_ps3_mute(1);
+	return 0;
+};
+
+static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+	/*
+	 * avsetting driver seems to never change the followings
+	 * so, init them here once
+	 */
+
+	/* no dma interrupt needed */
+	write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+	/* use every 4 buffer empty interrupt */
+	update_mask_reg(PS3_AUDIO_AX_IC,
+			PS3_AUDIO_AX_IC_AASOIMD_MASK,
+			PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+	/* enable 3wire clocks */
+	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+			~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+			  PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+			0);
+	update_reg(PS3_AUDIO_AO_3WMCTRL,
+		   PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+	int ret, retries, i;
+	pr_debug("%s: start\n", __func__);
+
+	ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+				  card->avs.avs_audio_rate,
+				  card->avs.avs_audio_width,
+				  card->avs.avs_audio_format,
+				  card->avs.avs_audio_source);
+	/*
+	 * Reset the following unwanted settings:
+	 */
+
+	/* disable all 3wire buffers */
+	update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+			~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+			  PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+			0);
+	wmb(); 	/* ensure the hardware sees the change */
+	/* wait for actually stopped */
+	retries = 1000;
+	while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+		(PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+		 PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+	       --retries) {
+		udelay(1);
+	}
+
+	/* reset buffer pointer */
+	for (i = 0; i < 4; i++) {
+		update_reg(PS3_AUDIO_AO_3WCTRL(i),
+			   PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+		udelay(10);
+	}
+	wmb(); /* ensure the hardware actually start resetting */
+
+	/* enable 3wire#0 buffer */
+	update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+	/* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+	update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+			~PS3_AUDIO_AO_3WCTRL_ASODF,
+			PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+	update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+			~PS3_AUDIO_AO_SPDCTRL_SPODF,
+			PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+	/* ensure all the setting above is written back to register */
+	wmb();
+	/* avsetting driver altered AX_IE, caller must reset it if you want */
+	pr_debug("%s: end\n", __func__);
+	return ret;
+}
+
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+	int ret;
+	pr_debug("%s: start\n", __func__);
+	card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+	card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+	card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+	card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+	card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+
+	ret = snd_ps3_change_avsetting(card);
+
+	snd_ps3_audio_fixup(card);
+
+	/* to start to generate SPDIF signal, fill data */
+	snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+	snd_ps3_kick_dma(card);
+	pr_debug("%s: end\n", __func__);
+	return ret;
+}
+
+/*
+ *  set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+	struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+	struct snd_ps3_avsetting_info avs;
+
+	avs = card->avs;
+
+	pr_debug("%s: called freq=%d width=%d\n", __func__,
+		 substream->runtime->rate,
+		 snd_pcm_format_width(substream->runtime->format));
+
+	pr_debug("%s: before freq=%d width=%d\n", __func__,
+		 card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+	/* sample rate */
+	switch (substream->runtime->rate) {
+	case 44100:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+		break;
+	case 48000:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+		break;
+	case 88200:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+		break;
+	case 96000:
+		avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+		break;
+	default:
+		pr_info("%s: invalid rate %d\n", __func__,
+			substream->runtime->rate);
+		return 1;
+	}
+
+	/* width */
+	switch (snd_pcm_format_width(substream->runtime->format)) {
+	case 16:
+		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+		break;
+	case 24:
+		avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+		break;
+	default:
+		pr_info("%s: invalid width %d\n", __func__,
+			snd_pcm_format_width(substream->runtime->format));
+		return 1;
+	}
+
+	if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
+	    (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
+		card->avs = avs;
+		snd_ps3_change_avsetting(card);
+
+		pr_debug("%s: after freq=%d width=%d\n", __func__,
+			 card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+		return 0;
+	} else
+		return 1;
+}
+
+
+
+static int snd_ps3_map_mmio(void)
+{
+	the_card.mapped_mmio_vaddr =
+		ioremap(the_card.ps3_dev->m_region->bus_addr,
+			the_card.ps3_dev->m_region->len);
+
+	if (!the_card.mapped_mmio_vaddr) {
+		pr_info("%s: ioremap 0 failed p=%#lx l=%#lx \n",
+		       __func__, the_card.ps3_dev->m_region->lpar_addr,
+		       the_card.ps3_dev->m_region->len);
+		return -ENXIO;
+	}
+
+	return 0;
+};
+
+static void snd_ps3_unmap_mmio(void)
+{
+	iounmap(the_card.mapped_mmio_vaddr);
+	the_card.mapped_mmio_vaddr = NULL;
+}
+
+static int snd_ps3_allocate_irq(void)
+{
+	int ret;
+	u64 lpar_addr, lpar_size;
+	u64 __iomem *mapped;
+
+	/* FIXME: move this to device_init (H/W probe) */
+
+	/* get irq outlet */
+	ret = lv1_gpu_device_map(1, &lpar_addr, &lpar_size);
+	if (ret) {
+		pr_info("%s: device map 1 failed %d\n", __func__,
+			ret);
+		return -ENXIO;
+	}
+
+	mapped = ioremap(lpar_addr, lpar_size);
+	if (!mapped) {
+		pr_info("%s: ioremap 1 failed \n", __func__);
+		return -ENXIO;
+	}
+
+	the_card.audio_irq_outlet = in_be64(mapped);
+
+	iounmap(mapped);
+	ret = lv1_gpu_device_unmap(1);
+	if (ret)
+		pr_info("%s: unmap 1 failed\n", __func__);
+
+	/* irq */
+	ret = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY,
+				 the_card.audio_irq_outlet,
+				 &the_card.irq_no);
+	if (ret) {
+		pr_info("%s:ps3_alloc_irq failed (%d)\n", __func__, ret);
+		return ret;
+	}
+
+	ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
+			  SND_PS3_DRIVER_NAME, &the_card);
+	if (ret) {
+		pr_info("%s: request_irq failed (%d)\n", __func__, ret);
+		goto cleanup_irq;
+	}
+
+	return 0;
+
+ cleanup_irq:
+	ps3_irq_plug_destroy(the_card.irq_no);
+	return ret;
+};
+
+static void snd_ps3_free_irq(void)
+{
+	free_irq(the_card.irq_no, &the_card);
+	ps3_irq_plug_destroy(the_card.irq_no);
+}
+
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+{
+	uint64_t val;
+	int ret;
+
+	val = (ioaddr_start & (0x0fUL << 32)) >> (32 - 20) |
+		(0x03UL << 24) |
+		(0x0fUL << 12) |
+		(PS3_AUDIO_IOID);
+
+	ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+	if (ret)
+		pr_info("%s: gpu_attribute failed %d\n", __func__,
+			ret);
+}
+
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+{
+	int ret;
+	u64 lpar_addr, lpar_size;
+
+	BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
+	BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+
+	the_card.ps3_dev = dev;
+
+	ret = ps3_open_hv_device(dev);
+
+	if (ret)
+		return -ENXIO;
+
+	/* setup MMIO */
+	ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size);
+	if (ret) {
+		pr_info("%s: device map 2 failed %d\n", __func__, ret);
+		goto clean_open;
+	}
+	ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size,
+		PAGE_SHIFT);
+
+	ret = snd_ps3_map_mmio();
+	if (ret)
+		goto clean_dev_map;
+
+	/* setup DMA area */
+	ps3_dma_region_init(dev, dev->d_region,
+			    PAGE_SHIFT, /* use system page size */
+			    0, /* dma type; not used */
+			    NULL,
+			    _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE));
+	dev->d_region->ioid = PS3_AUDIO_IOID;
+
+	ret = ps3_dma_region_create(dev->d_region);
+	if (ret) {
+		pr_info("%s: region_create\n", __func__);
+		goto clean_mmio;
+	}
+
+	snd_ps3_audio_set_base_addr(dev->d_region->bus_addr);
+
+	/* CONFIG_SND_PS3_DEFAULT_START_DELAY */
+	the_card.start_delay = snd_ps3_start_delay;
+
+	/* irq */
+	if (snd_ps3_allocate_irq()) {
+		ret = -ENXIO;
+		goto clean_dma_region;
+	}
+
+	/* create card instance */
+	the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
+	if (!the_card.card) {
+		ret = -ENXIO;
+		goto clean_irq;
+	}
+
+	strcpy(the_card.card->driver, "PS3");
+	strcpy(the_card.card->shortname, "PS3");
+	strcpy(the_card.card->longname, "PS3 sound");
+	/* create PCM devices instance */
+	/* NOTE:this driver works assuming pcm:substream = 1:1 */
+	ret = snd_pcm_new(the_card.card,
+			  "SPDIF",
+			  0, /* instance index, will be stored pcm.device*/
+			  1, /* output substream */
+			  0, /* input substream */
+			  &(the_card.pcm));
+	if (ret)
+		goto clean_card;
+
+	the_card.pcm->private_data = &the_card;
+	strcpy(the_card.pcm->name, "SPDIF");
+
+	/* set pcm ops */
+	snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_ps3_pcm_spdif_ops);
+
+	the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED;
+	/* pre-alloc PCM DMA buffer*/
+	ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm,
+					SNDRV_DMA_TYPE_DEV,
+					&dev->core,
+					SND_PS3_PCM_PREALLOC_SIZE,
+					SND_PS3_PCM_PREALLOC_SIZE);
+	if (ret < 0) {
+		pr_info("%s: prealloc failed\n", __func__);
+		goto clean_card;
+	}
+
+	/*
+	 * allocate null buffer
+	 * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
+	 * PAGE_SIZE is enogh
+	 */
+	if (!(the_card.null_buffer_start_vaddr =
+	      dma_alloc_coherent(&the_card.ps3_dev->core,
+				 PAGE_SIZE,
+				 &the_card.null_buffer_start_dma_addr,
+				 GFP_KERNEL))) {
+		pr_info("%s: nullbuffer alloc failed\n", __func__);
+		goto clean_preallocate;
+	}
+	pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__,
+		 the_card.null_buffer_start_vaddr,
+		 the_card.null_buffer_start_dma_addr);
+	/* set default sample rate/word width */
+	snd_ps3_init_avsetting(&the_card);
+
+	/* register the card */
+	ret = snd_card_register(the_card.card);
+	if (ret < 0)
+		goto clean_dma_map;
+
+	pr_info("%s started. start_delay=%dms\n",
+		the_card.card->longname, the_card.start_delay);
+	return 0;
+
+clean_dma_map:
+	dma_free_coherent(&the_card.ps3_dev->core,
+			  PAGE_SIZE,
+			  the_card.null_buffer_start_vaddr,
+			  the_card.null_buffer_start_dma_addr);
+clean_preallocate:
+	snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
+clean_card:
+	snd_card_free(the_card.card);
+clean_irq:
+	snd_ps3_free_irq();
+clean_dma_region:
+	ps3_dma_region_free(dev->d_region);
+clean_mmio:
+	snd_ps3_unmap_mmio();
+clean_dev_map:
+	lv1_gpu_device_unmap(2);
+clean_open:
+	ps3_close_hv_device(dev);
+	/*
+	 * there is no destructor function to pcm.
+	 * midlayer automatically releases if the card removed
+	 */
+	return ret;
+}; /* snd_ps3_probe */
+
+/* called when module removal */
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev)
+{
+	int ret;
+	pr_info("%s:start id=%d\n", __func__,  dev->match_id);
+	if (dev->match_id != PS3_MATCH_ID_SOUND)
+		return -ENXIO;
+
+	/*
+	 * ctl and preallocate buffer will be freed in
+	 * snd_card_free
+	 */
+	ret = snd_card_free(the_card.card);
+	if (ret)
+		pr_info("%s: ctl freecard=%d\n", __func__, ret);
+
+	dma_free_coherent(&dev->core,
+			  PAGE_SIZE,
+			  the_card.null_buffer_start_vaddr,
+			  the_card.null_buffer_start_dma_addr);
+
+	ps3_dma_region_free(dev->d_region);
+
+	snd_ps3_free_irq();
+	snd_ps3_unmap_mmio();
+
+	lv1_gpu_device_unmap(2);
+	ps3_close_hv_device(dev);
+	pr_info("%s:end id=%d\n", __func__, dev->match_id);
+	return 0;
+} /* snd_ps3_remove */
+
+static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
+	.match_id = PS3_MATCH_ID_SOUND,
+	.probe = snd_ps3_driver_probe,
+	.remove = snd_ps3_driver_remove,
+	.shutdown = snd_ps3_driver_remove,
+	.core = {
+		.name = SND_PS3_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+	uint32_t port_intr;
+	int underflow_occured = 0;
+	struct snd_ps3_card_info *card = dev_id;
+
+	if (!card->running) {
+		update_reg(PS3_AUDIO_AX_IS, 0);
+		update_reg(PS3_AUDIO_INTR_0, 0);
+		return IRQ_HANDLED;
+	}
+
+	port_intr = read_reg(PS3_AUDIO_AX_IS);
+	/*
+	 *serial buffer empty detected (every 4 times),
+	 *program next dma and kick it
+	 */
+	if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+		if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+			write_reg(PS3_AUDIO_AX_IS, port_intr);
+			underflow_occured = 1;
+		}
+		if (card->silent) {
+			/* we are still in silent time */
+			snd_ps3_program_dma(card,
+				(underflow_occured) ?
+				SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+				SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+			snd_ps3_kick_dma(card);
+			card->silent --;
+		} else {
+			snd_ps3_program_dma(card,
+				(underflow_occured) ?
+				SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+				SND_PS3_DMA_FILLTYPE_RUNNING);
+			snd_ps3_kick_dma(card);
+			snd_pcm_period_elapsed(card->substream);
+		}
+	} else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+		/*
+		 * serial out underflow, but buffer empty not detected.
+		 * in this case, fill fifo with 0 to recover.  After
+		 * filling dummy data, serial automatically start to
+		 * consume them and then will generate normal buffer
+		 * empty interrupts.
+		 * If both buffer underflow and buffer empty are occured,
+		 * it is better to do nomal data transfer than empty one
+		 */
+		snd_ps3_program_dma(card,
+				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+		snd_ps3_kick_dma(card);
+		snd_ps3_program_dma(card,
+				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+		snd_ps3_kick_dma(card);
+	}
+	/* clear interrupt cause */
+	return IRQ_HANDLED;
+};
+
+/*
+ * module/subsystem initialize/terminate
+ */
+static int __init snd_ps3_init(void)
+{
+	int ret;
+
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ENXIO;
+
+	memset(&the_card, 0, sizeof(the_card));
+	spin_lock_init(&the_card.dma_lock);
+
+	/* register systembus DRIVER, this calls our probe() func */
+	ret = ps3_system_bus_driver_register(&snd_ps3_bus_driver_info);
+
+	return ret;
+}
+
+static void __exit snd_ps3_exit(void)
+{
+	ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
new file mode 100644
index 0000000..4b7e6fb
--- /dev/null
+++ b/sound/ppc/snd_ps3.h
@@ -0,0 +1,135 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony 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; version 2 of the Licence.
+ *
+ * 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
+ */
+
+#if !defined(_SND_PS3_H_)
+#define _SND_PS3_H_
+
+#include <linux/irqreturn.h>
+
+#define SND_PS3_DRIVER_NAME "snd_ps3"
+
+enum snd_ps3_out_channel {
+	SND_PS3_OUT_SPDIF_0,
+	SND_PS3_OUT_SPDIF_1,
+	SND_PS3_OUT_SERIAL_0,
+	SND_PS3_OUT_DEVS
+};
+
+enum snd_ps3_dma_filltype {
+	SND_PS3_DMA_FILLTYPE_FIRSTFILL,
+	SND_PS3_DMA_FILLTYPE_RUNNING,
+	SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL,
+	SND_PS3_DMA_FILLTYPE_SILENT_RUNNING
+};
+
+enum snd_ps3_ch {
+	SND_PS3_CH_L = 0,
+	SND_PS3_CH_R = 1,
+	SND_PS3_CH_MAX = 2
+};
+
+struct snd_ps3_avsetting_info {
+	uint32_t avs_audio_ch;     /* fixed */
+	uint32_t avs_audio_rate;
+	uint32_t avs_audio_width;
+	uint32_t avs_audio_format; /* fixed */
+	uint32_t avs_audio_source; /* fixed */
+};
+/*
+ * PS3 audio 'card' instance
+ * there should be only ONE hardware.
+ */
+struct snd_ps3_card_info {
+	struct ps3_system_bus_device *ps3_dev;
+	struct snd_card *card;
+
+	struct snd_pcm *pcm;
+	struct snd_pcm_substream *substream;
+
+	/* hvc info */
+	u64 audio_lpar_addr;
+	u64 audio_lpar_size;
+
+	/* registers */
+	void __iomem *mapped_mmio_vaddr;
+
+	/* irq */
+	u64 audio_irq_outlet;
+	unsigned int irq_no;
+
+	/* remember avsetting */
+	struct snd_ps3_avsetting_info avs;
+
+	/* dma buffer management */
+	spinlock_t dma_lock;
+		/* dma_lock start */
+		void * dma_start_vaddr[2]; /* 0 for L, 1 for R */
+		dma_addr_t dma_start_bus_addr[2];
+		size_t dma_buffer_size;
+		void * dma_last_transfer_vaddr[2];
+		void * dma_next_transfer_vaddr[2];
+		int    silent;
+		/* dma_lock end */
+
+	int running;
+
+	/* null buffer */
+	void *null_buffer_start_vaddr;
+	dma_addr_t null_buffer_start_dma_addr;
+
+	/* start delay */
+	unsigned int start_delay;
+
+};
+
+
+/* PS3 audio DMAC block size in bytes */
+#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
+/* one stage (stereo)  of audio FIFO in bytes */
+#define PS3_AUDIO_FIFO_STAGE_SIZE (256)
+/* how many stages the fifo have */
+#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
+/* fifo size 128 bytes * 8 stages * stereo (2ch) */
+#define PS3_AUDIO_FIFO_SIZE \
+	(PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
+
+/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
+#define PS3_AUDIO_DMAC_MAX_BLOCKS  (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
+
+#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
+#define PS3_AUDIO_NORMAL_DMA_COUNT    (8)
+#define PS3_AUDIO_NULL_DMA_START_CH \
+	(PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
+#define PS3_AUDIO_NULL_DMA_COUNT      (2)
+
+#define SND_PS3_MAX_VOL (0x0F)
+#define SND_PS3_MIN_VOL (0x00)
+#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
+#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
+
+#define SND_PS3_PCM_PREALLOC_SIZE \
+	(PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
+
+#define SND_PS3_DMA_REGION_SIZE \
+	(SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
+
+#define PS3_AUDIO_IOID       (1UL)
+
+#endif /* _SND_PS3_H_ */
diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h
new file mode 100644
index 0000000..03fdee4
--- /dev/null
+++ b/sound/ppc/snd_ps3_reg.h
@@ -0,0 +1,891 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ * All rights reserved.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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
+ */
+
+/*
+ * interrupt / configure registers
+ */
+
+#define PS3_AUDIO_INTR_0                 (0x00000100)
+#define PS3_AUDIO_INTR_EN_0              (0x00000140)
+#define PS3_AUDIO_CONFIG                 (0x00000200)
+
+/*
+ * DMAC registers
+ * n:0..9
+ */
+#define PS3_AUDIO_DMAC_REGBASE(x)         (0x0000210 + 0x20 * (x))
+
+#define PS3_AUDIO_KICK(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x00)
+#define PS3_AUDIO_SOURCE(n)               (PS3_AUDIO_DMAC_REGBASE(n) + 0x04)
+#define PS3_AUDIO_DEST(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x08)
+#define PS3_AUDIO_DMASIZE(n)              (PS3_AUDIO_DMAC_REGBASE(n) + 0x0C)
+
+/*
+ * mute control
+ */
+#define PS3_AUDIO_AX_MCTRL                (0x00004000)
+#define PS3_AUDIO_AX_ISBP                 (0x00004004)
+#define PS3_AUDIO_AX_AOBP                 (0x00004008)
+#define PS3_AUDIO_AX_IC                   (0x00004010)
+#define PS3_AUDIO_AX_IE                   (0x00004014)
+#define PS3_AUDIO_AX_IS                   (0x00004018)
+
+/*
+ * three wire serial
+ * n:0..3
+ */
+#define PS3_AUDIO_AO_MCTRL                (0x00006000)
+#define PS3_AUDIO_AO_3WMCTRL              (0x00006004)
+
+#define PS3_AUDIO_AO_3WCTRL(n)            (0x00006200 + 0x200 * (n))
+
+/*
+ * S/PDIF
+ * n:0..1
+ * x:0..11
+ * y:0..5
+ */
+#define PS3_AUDIO_AO_SPD_REGBASE(n)       (0x00007200 + 0x200 * (n))
+
+#define PS3_AUDIO_AO_SPDCTRL(n) \
+	(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x00)
+#define PS3_AUDIO_AO_SPDUB(n, x) \
+	(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x04 + 0x04 * (x))
+#define PS3_AUDIO_AO_SPDCS(n, y) \
+	(PS3_AUDIO_AO_SPD_REGBASE(n) + 0x34 + 0x04 * (y))
+
+
+/*
+  PS3_AUDIO_INTR_0 register tells an interrupt handler which audio
+  DMA channel triggered the interrupt.  The interrupt status for a channel
+  can be cleared by writing a '1' to the corresponding bit.  A new interrupt
+  cannot be generated until the previous interrupt has been cleared.
+
+  Note that the status reported by PS3_AUDIO_INTR_0 is independent of the
+  value of PS3_AUDIO_INTR_EN_0.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+#define PS3_AUDIO_INTR_0_CHAN(n)	(1 << ((n) * 2))
+#define PS3_AUDIO_INTR_0_CHAN9     PS3_AUDIO_INTR_0_CHAN(9)
+#define PS3_AUDIO_INTR_0_CHAN8     PS3_AUDIO_INTR_0_CHAN(8)
+#define PS3_AUDIO_INTR_0_CHAN7     PS3_AUDIO_INTR_0_CHAN(7)
+#define PS3_AUDIO_INTR_0_CHAN6     PS3_AUDIO_INTR_0_CHAN(6)
+#define PS3_AUDIO_INTR_0_CHAN5     PS3_AUDIO_INTR_0_CHAN(5)
+#define PS3_AUDIO_INTR_0_CHAN4     PS3_AUDIO_INTR_0_CHAN(4)
+#define PS3_AUDIO_INTR_0_CHAN3     PS3_AUDIO_INTR_0_CHAN(3)
+#define PS3_AUDIO_INTR_0_CHAN2     PS3_AUDIO_INTR_0_CHAN(2)
+#define PS3_AUDIO_INTR_0_CHAN1     PS3_AUDIO_INTR_0_CHAN(1)
+#define PS3_AUDIO_INTR_0_CHAN0     PS3_AUDIO_INTR_0_CHAN(0)
+
+/*
+  The PS3_AUDIO_INTR_EN_0 register specifies which DMA channels can generate
+  an interrupt to the PU.  Each bit of PS3_AUDIO_INTR_EN_0 is ANDed with the
+  corresponding bit in PS3_AUDIO_INTR_0.  The resulting bits are OR'd together
+  to generate the Audio interrupt.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_EN_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+  Bit assignments are same as PS3_AUDIO_INTR_0
+*/
+
+/*
+  PS3_AUDIO_CONFIG
+  31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 C|0 0 0 0 0 0 0 0| CONFIG
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/* The CLEAR field cancels all pending transfers, and stops any running DMA
+   transfers.  Any interrupts associated with the canceled transfers
+   will occur as if the transfer had finished.
+   Since this bit is designed to recover from DMA related issues
+   which are caused by unpredictable situations, it is prefered to wait
+   for normal DMA transfer end without using this bit.
+*/
+#define PS3_AUDIO_CONFIG_CLEAR          (1 << 8)  /* RWIVF */
+
+/*
+  PS3_AUDIO_AX_MCTRL: Audio Port Mute Control Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|A|A|0 0 0 0 0 0 0|S|S|A|A|A|A| AX_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/* 3 Wire Audio Serial Output Channel Mutes (0..3)  */
+#define PS3_AUDIO_AX_MCTRL_ASOMT(n)     (1 << (3 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO3MT       (1 << 0)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO2MT       (1 << 1)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO1MT       (1 << 2)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO0MT       (1 << 3)          /* RWIVF */
+
+/* S/PDIF mutes (0,1)*/
+#define PS3_AUDIO_AX_MCTRL_SPOMT(n)     (1 << (5 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO1MT       (1 << 4)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO0MT       (1 << 5)          /* RWIVF */
+
+/* All 3 Wire Serial Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AASOMT       (1 << 13)         /* RWIVF */
+
+/* All S/PDIF Mute */
+#define PS3_AUDIO_AX_MCTRL_ASPOMT       (1 << 14)         /* RWIVF */
+
+/* All Audio Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AAOMT        (1 << 15)         /* RWIVF */
+
+/*
+  S/PDIF Outputs Buffer Read/Write Pointer Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B| AX_ISBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+ S/PDIF Output Channel Read Buffer Numbers
+ Buffer number is  value of field.
+ Indicates current read access buffer ID from Audio Data
+ Transfer controller of S/PDIF Output
+*/
+
+#define PS3_AUDIO_AX_ISBP_SPOBRN_MASK(n) (0x7 << 4 * (1 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BRN_MASK		(0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BRN_MASK		(0x7 << 4) /* R-IUF */
+
+/*
+S/PDIF Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_ISBP_SPOBWN_MASK(n) (0x7 <<  4 * (5 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BWN_MASK		(0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BWN_MASK		(0x7 << 20) /* R-IUF */
+
+/*
+  3 Wire Audio Serial Outputs Buffer Read/Write
+  Pointer Register
+  Buffer number is  value of field
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B| AX_AOBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Read Numbers
+Indicates current read access buffer Id from Audio Data Transfer
+Controller of 3 Wire Audio Serial Output Channels
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBRN_MASK(n) (0x7 << 4 * (3 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BRN_MASK	(0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BRN_MASK	(0x7 << 4) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BRN_MASK	(0x7 << 8) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BRN_MASK	(0x7 << 12) /* R-IUF */
+
+/*
+3 Wire Audio Serial Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBWN_MASK(n) (0x7 << 4 * (7 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BWN_MASK        (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BWN_MASK        (0x7 << 20) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BWN_MASK        (0x7 << 24) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BWN_MASK        (0x7 << 28) /* R-IUF */
+
+
+
+/*
+Audio Port Interrupt Condition Register
+For the fields in this register, the following values apply:
+0 = Interrupt is generated every interrupt event.
+1 = Interrupt is generated every 2 interrupt events.
+2 = Interrupt is generated every 4 interrupt events.
+3 = Reserved
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0|SPO|0 0|SPO|0 0|AAS|0 0 0 0 0 0 0 0 0 0 0 0| AX_IC
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+All 3-Wire Audio Serial Outputs Interrupt Mode
+Configures the Interrupt and Signal Notification
+condition of all 3-wire Audio Serial Outputs.
+*/
+#define PS3_AUDIO_AX_IC_AASOIMD_MASK          (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY1        (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY2        (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY4        (0x2 << 12) /* RW--V */
+
+/*
+S/PDIF Output Channel Interrupt Modes
+Configures the Interrupt and signal Notification
+conditions of S/PDIF output channels.
+*/
+#define PS3_AUDIO_AX_IC_SPO1IMD_MASK          (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY1        (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY2        (0x1 << 16) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY4        (0x2 << 16) /* RW--V */
+
+#define PS3_AUDIO_AX_IC_SPO0IMD_MASK          (0x3 << 20) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY1        (0x0 << 20) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY2        (0x1 << 20) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY4        (0x2 << 20) /* RW--V */
+
+/*
+Audio Port interrupt Enable Register
+Configures whether to enable or disable each Interrupt Generation.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Underflow
+Interrupt Enables
+Select enable/disable of Buffer Underflow Interrupts for
+3-Wire Audio Serial Output Channels
+DISABLED=Interrupt generation disabled.
+*/
+#define PS3_AUDIO_AX_IE_ASOBUIE(n)      (1 << (3 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BUIE        (1 << 0) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BUIE        (1 << 1) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BUIE        (1 << 2) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BUIE        (1 << 3) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Underflow Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBUIE(n)      (1 << (7 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BUIE        (1 << 6) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BUIE        (1 << 7) /* RWIVF */
+
+/* S/PDIF Output Channel One Block Transfer Completion Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBTCIE(n)     (1 << (11 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BTCIE       (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BTCIE       (1 << 11) /* RWIVF */
+
+/* 3-Wire Audio Serial Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_ASOBEIE(n)      (1 << (19 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BEIE        (1 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BEIE        (1 << 17) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BEIE        (1 << 18) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BEIE        (1 << 19) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBEIE(n)      (1 << (23 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BEIE        (1 << 22) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BEIE        (1 << 23) /* RWIVF */
+
+/*
+Audio Port Interrupt Status Register
+Indicates Interrupt status, which interrupt has occured, and can clear
+each interrupt in this register.
+Writing 1b to a field containing 1b clears field and de-asserts interrupt.
+Writing 0b to a field has no effect.
+Field vaules are the following:
+0 - Interrupt hasn't occured.
+1 - Interrupt has occured.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+ Bit assignment are same as AX_IE
+*/
+
+/*
+Audio Output Master Control Register
+Configures Master Clock and other master Audio Output Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|SCKSE|0|SCKSE|  MR0  |  MR1  |MCL|MCL|0 0 0 0|0 0 0 0 0 0 0 0| AO_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+MCLK Output Control
+Controls mclko[1] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with scksel1 by mr1
+2 - Reserved
+3 - Reserved
+*/
+
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_MASK		(0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_DISABLED	(0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_ENABLED	(0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD2	(0x2 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD3	(0x3 << 12) /* RW--V */
+
+/*
+MCLK Output Control
+Controls mclko[0] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with SCKSEL0 by MR0
+2 - Reserved
+3 - Reserved
+*/
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_MASK		(0x3 << 14) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_DISABLED	(0x0 << 14) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_ENABLED	(0x1 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD2	(0x2 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD3	(0x3 << 14) /* RW--V */
+/*
+Master Clock Rate 1
+Sets the divide ration of Master Clock1 (clock output from
+mclko[1] for the input clock selected by scksel1.
+*/
+#define PS3_AUDIO_AO_MCTRL_MR1_MASK	(0xf << 16)
+#define PS3_AUDIO_AO_MCTRL_MR1_DEFAULT	(0x0 << 16) /* RWI-V */
+/*
+Master Clock Rate 0
+Sets the divide ratio of Master Clock0 (clock output from
+mclko[0] for the input clock selected by scksel0).
+*/
+#define PS3_AUDIO_AO_MCTRL_MR0_MASK	(0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MR0_DEFAULT	(0x0 << 20) /* RWI-V */
+/*
+System Clock Select 0/1
+Selects the system clock to be used as Master Clock 0/1
+Input the system clock that is appropriate for the sampling
+rate.
+*/
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_MASK		(0x7 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_DEFAULT	(0x2 << 24) /* RWI-V */
+
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_MASK		(0x7 << 28) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_DEFAULT	(0x2 << 28) /* RWI-V */
+
+
+/*
+3-Wire Audio Output Master Control Register
+Configures clock, 3-Wire Audio Serial Output Enable, and
+other 3-Wire Audio Serial Output Master Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |A|A|A|A|0 0 0|A| ASOSR |0 0 0 0|A|A|A|A|A|A|0|1|0 0 0 0 0 0 0 0| AO_3WMCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+/*
+LRCKO Polarity
+0 - Reserved
+1 - default
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK 		(1 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT	(1 << 8) /* RW--V */
+
+/* LRCK Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD		(1 << 10) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_ENABLED	(0 << 10) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED	(1 << 10) /* RWI-V */
+
+/* Bit Clock Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD		(1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_ENABLED	(0 << 11) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED	(1 << 11) /* RWI-V */
+
+/*
+3-Wire Audio Serial Output Channel 0-3 Operational
+Status.  Each bit becomes 1 after each 3-Wire Audio
+Serial Output Channel N is in action by setting 1 to
+asoen.
+Each bit becomes 0 after each 3-Wire Audio Serial Output
+Channel N is out of action by setting 0 to asoen.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN(n)		(1 << (15 - (n))) /* R-IVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(n)	(0 << (15 - (n))) /* R-I-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(n)	(1 << (15 - (n))) /* R---V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0		\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_STOPPED	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_RUNNING	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1		\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_STOPPED	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_RUNNING	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2		\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_STOPPED	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_RUNNING	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3		\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_STOPPED	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_RUNNING	\
+	PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(3)
+
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the 3-wire Audio Output Clock, whcih
+is applied to the master clock selected by mcksel.
+Data output is synchronized with this clock.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_MASK		(0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV2		(0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV4		(0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV8		(0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV12	(0x6 << 20) /* RW--V */
+
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL		(1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK0	(0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK1	(1 << 24) /* RW--V */
+
+/*
+Enables and disables 4ch 3-Wire Audio Serial Output
+operation.  Each Bit from 0 to 3 corresponds to an
+output channel, which means that each output channel
+can be enabled or disabled individually.  When
+multiple channels are enabled at the same time, output
+operations are performed in synchronization.
+Bit 0 - Output Channel 0 (SDOUT[0])
+Bit 1 - Output Channel 1 (SDOUT[1])
+Bit 2 - Output Channel 2 (SDOUT[2])
+Bit 3 - Output Channel 3 (SDOUT[3])
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN(n)		(1 << (31 - (n))) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(n)	(0 << (31 - (n))) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(n)	(1 << (31 - (n))) /* RW--V */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0 \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN(0) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_DISABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(0) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_ENABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(0) /* RW--V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0 \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN(1) /* RWIVF */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_DISABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(1) /* RWI-V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_ENABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(1) /* RW--V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0 \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN(2) /* RWIVF */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_DISABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(2) /* RWI-V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_ENABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(2) /* RW--V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0 \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN(3) /* RWIVF */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_DISABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(3) /* RWI-V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_ENABLED \
+	PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(3) /* RW--V */
+
+/*
+3-Wire Audio Serial output Channel 0-3 Control Register
+Configures settings for 3-Wire Serial Audio Output Channel 0-3
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|0 0 0 0|A|0|ASO|0 0 0|0|0|0|0|0| AO_3WCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+Data Bit Mode
+Specifies the number of data bits
+0 - 16 bits
+1 - reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODB_MASK	(0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_16BIT	(0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_RESVD	(0x1 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_20BIT	(0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_24BIT	(0x3 << 8) /* RW--V */
+/*
+Data Format Mode
+Specifies the data format where (LSB side or MSB) the data(in 20 bit
+or 24 bit resolution mode) is put in a 32 bit field.
+0 - Data put on LSB side
+1 - Data put on MSB side
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODF 	(1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_LSB	(0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_MSB	(1 << 11) /* RW--V */
+/*
+Buffer Reset
+Performs buffer reset.  Writing 1 to this bit initializes the
+corresponding 3-Wire Audio Output buffers(both L and R).
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST 		(1 << 16) /* CWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_IDLE	(0 << 16) /* -WI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET	(1 << 16) /* -W--T */
+
+/*
+S/PDIF Audio Output Channel 0/1 Control Register
+Configures settings for S/PDIF Audio Output Channel 0/1.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |S|0 0 0|S|0 0|S| SPOSR |0 0|SPO|0 0 0 0|S|0|SPO|0 0 0 0 0 0 0|S| AO_SPDCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+Buffer reset.  Writing 1 to this bit initializes the
+corresponding S/PDIF output buffer pointer.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST		(1 << 0) /* CWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_IDLE	(0 << 0) /* -WI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_RESET	(1 << 0) /* -W--T */
+
+/*
+Data Bit Mode
+Specifies number of data bits
+0 - 16 bits
+1 - Reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_MASK		(0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_16BIT	(0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_RESVD	(0x1 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_20BIT	(0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_24BIT	(0x3 << 8) /* RW--V */
+/*
+Data format Mode
+Specifies the data format, where (LSB side or MSB)
+the data(in 20 or 24 bit resolution) is put in the
+32 bit field.
+0 - LSB Side
+1 - MSB Side
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODF	(1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_LSB	(0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_MSB	(1 << 11) /* RW--V */
+/*
+Source Select
+Specifies the source of the S/PDIF output.  When 0, output
+operation is controlled by 3wen[0] of AO_3WMCTRL register.
+The SR must have the same setting as the a0_3wmctrl reg.
+0 - 3-Wire Audio OUT Ch0 Buffer
+1 - S/PDIF buffer
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_MASK		(0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_3WEN		(0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_SPDIF	(0x1 << 16) /* RW--V */
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the S/PDIF Output Clock, which
+is applied to the master clock selected by mcksel.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR		(0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV2		(0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV4		(0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV8		(0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV12	(0x6 << 20) /* RW--V */
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL		(1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK0	(0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK1	(1 << 24) /* RW--V */
+
+/*
+S/PDIF Output Channel Operational Status
+This bit becomes 1 after S/PDIF Output Channel is in
+action by setting 1 to spoen.  This bit becomes 0
+after S/PDIF Output Channel is out of action by setting
+0 to spoen.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN		(1 << 27) /* R-IVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_STOPPED	(0 << 27) /* R-I-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_RUNNING	(1 << 27) /* R---V */
+
+/*
+S/PDIF Audio Output Channel Output Enable
+Enables and disables output operation.  This bit is used
+only when sposs = 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN		(1 << 31) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_DISABLED	(0 << 31) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_ENABLED	(1 << 31) /* RW--V */
+
+/*
+S/PDIF Audio Output Channel Channel Status
+Setting Registers.
+Configures channel status bit settings for each block
+(192 bits).
+Output is performed from the MSB(AO_SPDCS0 register bit 31).
+The same value is added for subframes within the same frame.
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOCS                             | AO_SPDCS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+S/PDIF Audio Output Channel User Bit Setting
+Configures user bit settings for each block (384 bits).
+Output is performed from the MSB(ao_spdub0 register bit 31).
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOUB                             | AO_SPDUB
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*****************************************************************************
+ *
+ * DMAC register
+ *
+ *****************************************************************************/
+/*
+The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor
+its status
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0|STATU|0 0 0|  EVENT  |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT
+occurs.
+It will return to the DONE state when the request is completed.
+The registers for a DMA channel should only be written if REQUEST is IDLE.
+*/
+
+#define PS3_AUDIO_KICK_REQUEST                (1 << 0) /* RWIVF */
+#define PS3_AUDIO_KICK_REQUEST_IDLE           (0 << 0) /* RWI-V */
+#define PS3_AUDIO_KICK_REQUEST_ACTIVE         (1 << 0) /* -W--T */
+
+/*
+ *The EVENT field is used to set the event in which
+ *the DMA request becomes active.
+ */
+#define PS3_AUDIO_KICK_EVENT_MASK             (0x1f << 16) /* RWIVF */
+#define PS3_AUDIO_KICK_EVENT_ALWAYS           (0x00 << 16) /* RWI-V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY (0x01 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW	(0x02 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY		(0x03 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW	(0x04 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY		(0x05 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW	(0x06 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY		(0x07 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW	(0x08 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE \
+	(0x09 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW		(0x0A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY		(0x0B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE \
+	(0x0C << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW		(0x0D << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY		(0x0E << 16) /* RW--V */
+
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n) \
+	((0x13 + (n)) << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0         (0x13 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1         (0x14 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2         (0x15 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3         (0x16 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4         (0x17 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5         (0x18 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6         (0x19 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7         (0x1A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8         (0x1B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9         (0x1C << 16) /* RW--V */
+
+/*
+The STATUS field can be used to monitor the progress of a DMA request.
+DONE indicates the previous request has completed.
+EVENT indicates that the DMA engine is waiting for the EVENT to occur.
+PENDING indicates that the DMA engine has not started processing this
+request, but the EVENT has occured.
+DMA indicates that the data transfer is in progress.
+NOTIFY indicates that the notifier signalling end of transfer is being written.
+CLEAR indicated that the previous transfer was cleared.
+ERROR indicates the previous transfer requested an unsupported
+source/destination combination.
+*/
+
+#define PS3_AUDIO_KICK_STATUS_MASK	(0x7 << 24) /* R-IVF */
+#define PS3_AUDIO_KICK_STATUS_DONE	(0x0 << 24) /* R-I-V */
+#define PS3_AUDIO_KICK_STATUS_EVENT	(0x1 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_PENDING	(0x2 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_DMA	(0x3 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_NOTIFY	(0x4 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_CLEAR	(0x5 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_ERROR	(0x6 << 24) /* R---V */
+
+/*
+The PS3_AUDIO_SOURCE register specifies the source address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| SOURCE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_SOURCE_START_MASK	(0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the source address.
+*/
+
+#define PS3_AUDIO_SOURCE_TARGET_MASK 		(3 << 0) /* RWIVF */
+#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY	(2 << 0) /* RW--V */
+
+/*
+The PS3_AUDIO_DEST register specifies the destination address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| DEST
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_DEST_START_MASK	(0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the destination address
+AUDIOFIFO = Audio WriteData FIFO,
+*/
+
+#define PS3_AUDIO_DEST_TARGET_MASK		(3 << 0) /* RWIVF */
+#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO		(1 << 0) /* RW--V */
+
+/*
+PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
+So a value of 0 means 128-bytes will get transfered.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|   BLOCKS    | DMASIZE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+#define PS3_AUDIO_DMASIZE_BLOCKS_MASK 	(0x7f << 0) /* RWIUF */
+
+/*
+ * source/destination address for internal fifos
+ */
+#define PS3_AUDIO_AO_3W_LDATA(n)	(0x1000 + (0x100 * (n)))
+#define PS3_AUDIO_AO_3W_RDATA(n)	(0x1080 + (0x100 * (n)))
+
+#define PS3_AUDIO_AO_SPD_DATA(n)	(0x2000 + (0x400 * (n)))
+
+
+/*
+ * field attiribute
+ *
+ *	Read
+ *	  ' ' = Other Information
+ *	  '-' = Field is part of a write-only register
+ *	  'C' = Value read is always the same, constant value line follows (C)
+ *	  'R' = Value is read
+ *
+ *	Write
+ *	  ' ' = Other Information
+ *	  '-' = Must not be written (D), value ignored when written (R,A,F)
+ *	  'W' = Can be written
+ *
+ *	Internal State
+ *	  ' ' = Other Information
+ *	  '-' = No internal state
+ *	  'X' = Internal state, initial value is unknown
+ *	  'I' = Internal state, initial value is known and follows (I)
+ *
+ *	Declaration/Size
+ *	  ' ' = Other Information
+ *	  '-' = Does Not Apply
+ *	  'V' = Type is void
+ *	  'U' = Type is unsigned integer
+ *	  'S' = Type is signed integer
+ *	  'F' = Type is IEEE floating point
+ *	  '1' = Byte size (008)
+ *	  '2' = Short size (016)
+ *	  '3' = Three byte size (024)
+ *	  '4' = Word size (032)
+ *	  '8' = Double size (064)
+ *
+ *	Define Indicator
+ *	  ' ' = Other Information
+ *	  'D' = Device
+ *	  'M' = Memory
+ *	  'R' = Register
+ *	  'A' = Array of Registers
+ *	  'F' = Field
+ *	  'V' = Value
+ *	  'T' = Task
+ */
+
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
new file mode 100644
index 0000000..b7e08ef
--- /dev/null
+++ b/sound/sh/Kconfig
@@ -0,0 +1,14 @@
+# ALSA SH drivers
+
+menu "SUPERH devices"
+	depends on SND!=n && SUPERH
+
+config SND_AICA
+	tristate "Dreamcast Yamaha AICA sound"
+	depends on SH_DREAMCAST && SND
+	select SND_PCM
+	help
+	  ALSA Sound driver for the SEGA Dreamcast console.
+
+endmenu
+
diff --git a/sound/sh/Makefile b/sound/sh/Makefile
new file mode 100644
index 0000000..8fdcb6e
--- /dev/null
+++ b/sound/sh/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-aica-objs := aica.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AICA) += snd-aica.o
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
new file mode 100644
index 0000000..7397865
--- /dev/null
+++ b/sound/sh/aica.c
@@ -0,0 +1,665 @@
+/*
+* This code is licenced under 
+* the General Public Licence
+* version 2
+*
+* Copyright Adrian McMenamin 2005, 2006, 2007
+* <adrian@mcmen.demon.co.uk>
+* Requires firmware (BSD licenced) available from:
+* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
+* or the maintainer
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+*/
+
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/dreamcast/sysasic.h>
+#include "aica.h"
+
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
+
+/* module parameters */
+#define CARD_NAME "AICA"
+static int index = -1;
+static char *id;
+static int enable = 1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+/* Use workqueue */
+static struct workqueue_struct *aica_queue;
+
+/* Simple platform device */
+static struct platform_device *pd;
+static struct resource aica_memory_space[2] = {
+	{
+	 .name = "AICA ARM CONTROL",
+	 .start = ARM_RESET_REGISTER,
+	 .flags = IORESOURCE_MEM,
+	 .end = ARM_RESET_REGISTER + 3,
+	 },
+	{
+	 .name = "AICA Sound RAM",
+	 .start = SPU_MEMORY_BASE,
+	 .flags = IORESOURCE_MEM,
+	 .end = SPU_MEMORY_BASE + 0x200000 - 1,
+	 },
+};
+
+/* SPU specific functions */
+/* spu_write_wait - wait for G2-SH FIFO to clear */
+static void spu_write_wait(void)
+{
+	int time_count;
+	time_count = 0;
+	while (1) {
+		if (!(readl(G2_FIFO) & 0x11))
+			break;
+		/* To ensure hardware failure doesn't wedge kernel */
+		time_count++;
+		if (time_count > 0x10000) {
+			snd_printk
+			    ("WARNING: G2 FIFO appears to be blocked.\n");
+			break;
+		}
+	}
+}
+
+/* spu_memset - write to memory in SPU address space */
+static void spu_memset(u32 toi, u32 what, int length)
+{
+	int i;
+	snd_assert(length % 4 == 0, return);
+	for (i = 0; i < length; i++) {
+		if (!(i % 8))
+			spu_write_wait();
+		writel(what, toi + SPU_MEMORY_BASE);
+		toi++;
+	}
+}
+
+/* spu_memload - write to SPU address space */
+static void spu_memload(u32 toi, void *from, int length)
+{
+	u32 *froml = from;
+	u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
+	int i;
+	u32 val;
+	length = DIV_ROUND_UP(length, 4);
+	spu_write_wait();
+	for (i = 0; i < length; i++) {
+		if (!(i % 8))
+			spu_write_wait();
+		val = *froml;
+		writel(val, to);
+		froml++;
+		to++;
+	}
+}
+
+/* spu_disable - set spu registers to stop sound output */
+static void spu_disable(void)
+{
+	int i;
+	u32 regval;
+	spu_write_wait();
+	regval = readl(ARM_RESET_REGISTER);
+	regval |= 1;
+	spu_write_wait();
+	writel(regval, ARM_RESET_REGISTER);
+	for (i = 0; i < 64; i++) {
+		spu_write_wait();
+		regval = readl(SPU_REGISTER_BASE + (i * 0x80));
+		regval = (regval & ~0x4000) | 0x8000;
+		spu_write_wait();
+		writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+	}
+}
+
+/* spu_enable - set spu registers to enable sound output */
+static void spu_enable(void)
+{
+	u32 regval = readl(ARM_RESET_REGISTER);
+	regval &= ~1;
+	spu_write_wait();
+	writel(regval, ARM_RESET_REGISTER);
+}
+
+/* 
+ * Halt the sound processor, clear the memory,
+ * load some default ARM7 code, and then restart ARM7
+*/
+static void spu_reset(void)
+{
+	spu_disable();
+	spu_memset(0, 0, 0x200000 / 4);
+	/* Put ARM7 in endless loop */
+	ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+	spu_enable();
+}
+
+/* aica_chn_start - write to spu to start playback */
+static void aica_chn_start(void)
+{
+	spu_write_wait();
+	writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* aica_chn_halt - write to spu to halt playback */
+static void aica_chn_halt(void)
+{
+	spu_write_wait();
+	writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* ALSA code below */
+static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
+	.info = (SNDRV_PCM_INFO_NONINTERLEAVED),
+	.formats =
+	    (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+	     SNDRV_PCM_FMTBIT_IMA_ADPCM),
+	.rates = SNDRV_PCM_RATE_8000_48000,
+	.rate_min = 8000,
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = AICA_BUFFER_SIZE,
+	.period_bytes_min = AICA_PERIOD_SIZE,
+	.period_bytes_max = AICA_PERIOD_SIZE,
+	.periods_min = AICA_PERIOD_NUMBER,
+	.periods_max = AICA_PERIOD_NUMBER,
+};
+
+static int aica_dma_transfer(int channels, int buffer_size,
+			     struct snd_pcm_substream *substream)
+{
+	int q, err, period_offset;
+	struct snd_card_aica *dreamcastcard;
+	struct snd_pcm_runtime *runtime;
+	err = 0;
+	dreamcastcard = substream->pcm->private_data;
+	period_offset = dreamcastcard->clicks;
+	period_offset %= (AICA_PERIOD_NUMBER / channels);
+	runtime = substream->runtime;
+	for (q = 0; q < channels; q++) {
+		err = dma_xfer(AICA_DMA_CHANNEL,
+			       (unsigned long) (runtime->dma_area +
+						(AICA_BUFFER_SIZE * q) /
+						channels +
+						AICA_PERIOD_SIZE *
+						period_offset),
+			       AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
+			       AICA_PERIOD_SIZE * period_offset,
+			       buffer_size / channels, AICA_DMA_MODE);
+		if (unlikely(err < 0))
+			break;
+		dma_wait_for_completion(AICA_DMA_CHANNEL);
+	}
+	return err;
+}
+
+static void startup_aica(struct snd_card_aica *dreamcastcard)
+{
+	spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+		    dreamcastcard->channel, sizeof(struct aica_channel));
+	aica_chn_start();
+}
+
+static void run_spu_dma(struct work_struct *work)
+{
+	int buffer_size;
+	struct snd_pcm_runtime *runtime;
+	struct snd_card_aica *dreamcastcard;
+	dreamcastcard =
+	    container_of(work, struct snd_card_aica, spu_dma_work);
+	runtime = dreamcastcard->substream->runtime;
+	if (unlikely(dreamcastcard->dma_check == 0)) {
+		buffer_size =
+		    frames_to_bytes(runtime, runtime->buffer_size);
+		if (runtime->channels > 1)
+			dreamcastcard->channel->flags |= 0x01;
+		aica_dma_transfer(runtime->channels, buffer_size,
+				  dreamcastcard->substream);
+		startup_aica(dreamcastcard);
+		dreamcastcard->clicks =
+		    buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
+		return;
+	} else {
+		aica_dma_transfer(runtime->channels,
+				  AICA_PERIOD_SIZE * runtime->channels,
+				  dreamcastcard->substream);
+		snd_pcm_period_elapsed(dreamcastcard->substream);
+		dreamcastcard->clicks++;
+		if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
+			dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+		mod_timer(&dreamcastcard->timer, jiffies + 1);
+	}
+}
+
+static void aica_period_elapsed(unsigned long timer_var)
+{
+	/*timer function - so cannot sleep */
+	int play_period;
+	struct snd_pcm_runtime *runtime;
+	struct snd_pcm_substream *substream;
+	struct snd_card_aica *dreamcastcard;
+	substream = (struct snd_pcm_substream *) timer_var;
+	runtime = substream->runtime;
+	dreamcastcard = substream->pcm->private_data;
+	/* Have we played out an additional period? */
+	play_period =
+	    frames_to_bytes(runtime,
+			    readl
+			    (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
+	    AICA_PERIOD_SIZE;
+	if (play_period == dreamcastcard->current_period) {
+		/* reschedule the timer */
+		mod_timer(&(dreamcastcard->timer), jiffies + 1);
+		return;
+	}
+	if (runtime->channels > 1)
+		dreamcastcard->current_period = play_period;
+	if (unlikely(dreamcastcard->dma_check == 0))
+		dreamcastcard->dma_check = 1;
+	queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+}
+
+static void spu_begin_dma(struct snd_pcm_substream *substream)
+{
+	struct snd_card_aica *dreamcastcard;
+	struct snd_pcm_runtime *runtime;
+	runtime = substream->runtime;
+	dreamcastcard = substream->pcm->private_data;
+	/*get the queue to do the work */
+	queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+	/* Timer may already be running */
+	if (unlikely(dreamcastcard->timer.data)) {
+		mod_timer(&dreamcastcard->timer, jiffies + 4);
+		return;
+	}
+	init_timer(&(dreamcastcard->timer));
+	dreamcastcard->timer.data = (unsigned long) substream;
+	dreamcastcard->timer.function = aica_period_elapsed;
+	dreamcastcard->timer.expires = jiffies + 4;
+	add_timer(&(dreamcastcard->timer));
+}
+
+static int snd_aicapcm_pcm_open(struct snd_pcm_substream
+				*substream)
+{
+	struct snd_pcm_runtime *runtime;
+	struct aica_channel *channel;
+	struct snd_card_aica *dreamcastcard;
+	if (!enable)
+		return -ENOENT;
+	dreamcastcard = substream->pcm->private_data;
+	channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
+	if (!channel)
+		return -ENOMEM;
+	/* set defaults for channel */
+	channel->sfmt = SM_8BIT;
+	channel->cmd = AICA_CMD_START;
+	channel->vol = dreamcastcard->master_volume;
+	channel->pan = 0x80;
+	channel->pos = 0;
+	channel->flags = 0;	/* default to mono */
+	dreamcastcard->channel = channel;
+	runtime = substream->runtime;
+	runtime->hw = snd_pcm_aica_playback_hw;
+	spu_enable();
+	dreamcastcard->clicks = 0;
+	dreamcastcard->current_period = 0;
+	dreamcastcard->dma_check = 0;
+	return 0;
+}
+
+static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+				 *substream)
+{
+	struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+	flush_workqueue(aica_queue);
+	if (dreamcastcard->timer.data)
+		del_timer(&dreamcastcard->timer);
+	kfree(dreamcastcard->channel);
+	spu_disable();
+	return 0;
+}
+
+static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
+				   *substream)
+{
+	/* Free the DMA buffer */
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
+				     *substream, struct snd_pcm_hw_params
+				     *hw_params)
+{
+	/* Allocate a DMA buffer using ALSA built-ins */
+	return
+	    snd_pcm_lib_malloc_pages(substream,
+				     params_buffer_bytes(hw_params));
+}
+
+static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
+				   *substream)
+{
+	struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+	if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
+		dreamcastcard->channel->sfmt = SM_16BIT;
+	dreamcastcard->channel->freq = substream->runtime->rate;
+	dreamcastcard->substream = substream;
+	return 0;
+}
+
+static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
+				   *substream, int cmd)
+{
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		spu_begin_dma(substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		aica_chn_halt();
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
+					     *substream)
+{
+	return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
+}
+
+static struct snd_pcm_ops snd_aicapcm_playback_ops = {
+	.open = snd_aicapcm_pcm_open,
+	.close = snd_aicapcm_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_aicapcm_pcm_hw_params,
+	.hw_free = snd_aicapcm_pcm_hw_free,
+	.prepare = snd_aicapcm_pcm_prepare,
+	.trigger = snd_aicapcm_pcm_trigger,
+	.pointer = snd_aicapcm_pcm_pointer,
+};
+
+/* TO DO: set up to handle more than one pcm instance */
+static int __init snd_aicapcmchip(struct snd_card_aica
+				  *dreamcastcard, int pcm_index)
+{
+	struct snd_pcm *pcm;
+	int err;
+	/* AICA has no capture ability */
+	err =
+	    snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
+			&pcm);
+	if (unlikely(err < 0))
+		return err;
+	pcm->private_data = dreamcastcard;
+	strcpy(pcm->name, "AICA PCM");
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_aicapcm_playback_ops);
+	/* Allocate the DMA buffers */
+	err =
+	    snd_pcm_lib_preallocate_pages_for_all(pcm,
+						  SNDRV_DMA_TYPE_CONTINUOUS,
+						  snd_dma_continuous_data
+						  (GFP_KERNEL),
+						  AICA_BUFFER_SIZE,
+						  AICA_BUFFER_SIZE);
+	return err;
+}
+
+/* Mixer controls */
+static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 1;	/* TO DO: Fix me */
+	return 0;
+}
+
+static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	if (ucontrol->value.integer.value[0] == 1)
+		return 0;	/* TO DO: Fix me */
+	else
+		aica_chn_halt();
+	return 0;
+}
+
+static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFF;
+	return 0;
+}
+
+static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_card_aica *dreamcastcard;
+	dreamcastcard = kcontrol->private_data;
+	if (unlikely(!dreamcastcard->channel))
+		return -ETXTBSY;	/* we've not yet been set up */
+	ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
+	return 0;
+}
+
+static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_card_aica *dreamcastcard;
+	dreamcastcard = kcontrol->private_data;
+	if (unlikely(!dreamcastcard->channel))
+		return -ETXTBSY;
+	if (unlikely(dreamcastcard->channel->vol ==
+		     ucontrol->value.integer.value[0]))
+		return 0;
+	dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
+	dreamcastcard->master_volume = ucontrol->value.integer.value[0];
+	spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+		    dreamcastcard->channel, sizeof(struct aica_channel));
+	return 1;
+}
+
+static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "PCM Playback Switch",
+	.index = 0,
+	.info = aica_pcmswitch_info,
+	.get = aica_pcmswitch_get,
+	.put = aica_pcmswitch_put
+};
+
+static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "PCM Playback Volume",
+	.index = 0,
+	.info = aica_pcmvolume_info,
+	.get = aica_pcmvolume_get,
+	.put = aica_pcmvolume_put
+};
+
+static int load_aica_firmware(void)
+{
+	int err;
+	const struct firmware *fw_entry;
+	spu_reset();
+	err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
+	if (unlikely(err))
+		return err;
+	/* write firware into memory */
+	spu_disable();
+	spu_memload(0, fw_entry->data, fw_entry->size);
+	spu_enable();
+	release_firmware(fw_entry);
+	return err;
+}
+
+static int __devinit add_aicamixer_controls(struct snd_card_aica
+					    *dreamcastcard)
+{
+	int err;
+	err = snd_ctl_add
+	    (dreamcastcard->card,
+	     snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
+	if (unlikely(err < 0))
+		return err;
+	err = snd_ctl_add
+	    (dreamcastcard->card,
+	     snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
+	if (unlikely(err < 0))
+		return err;
+	return 0;
+}
+
+static int snd_aica_remove(struct platform_device *devptr)
+{
+	struct snd_card_aica *dreamcastcard;
+	dreamcastcard = platform_get_drvdata(devptr);
+	if (unlikely(!dreamcastcard))
+		return -ENODEV;
+	snd_card_free(dreamcastcard->card);
+	kfree(dreamcastcard);
+	platform_set_drvdata(devptr, NULL);
+	return 0;
+}
+
+static int __init snd_aica_probe(struct platform_device *devptr)
+{
+	int err;
+	struct snd_card_aica *dreamcastcard;
+	dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
+	if (unlikely(!dreamcastcard))
+		return -ENOMEM;
+	dreamcastcard->card =
+	    snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
+	if (unlikely(!dreamcastcard->card)) {
+		kfree(dreamcastcard);
+		return -ENODEV;
+	}
+	strcpy(dreamcastcard->card->driver, "snd_aica");
+	strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+	strcpy(dreamcastcard->card->longname,
+	       "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+	/* Prepare to use the queue */
+	INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
+	/* Load the PCM 'chip' */
+	err = snd_aicapcmchip(dreamcastcard, 0);
+	if (unlikely(err < 0))
+		goto freedreamcast;
+	snd_card_set_dev(dreamcastcard->card, &devptr->dev);
+	dreamcastcard->timer.data = 0;
+	dreamcastcard->channel = NULL;
+	/* Add basic controls */
+	err = add_aicamixer_controls(dreamcastcard);
+	if (unlikely(err < 0))
+		goto freedreamcast;
+	/* Register the card with ALSA subsystem */
+	err = snd_card_register(dreamcastcard->card);
+	if (unlikely(err < 0))
+		goto freedreamcast;
+	platform_set_drvdata(devptr, dreamcastcard);
+	aica_queue = create_workqueue(CARD_NAME);
+	if (unlikely(!aica_queue))
+		goto freedreamcast;
+	snd_printk
+	    ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+	return 0;
+      freedreamcast:
+	snd_card_free(dreamcastcard->card);
+	kfree(dreamcastcard);
+	return err;
+}
+
+static struct platform_driver snd_aica_driver = {
+	.probe = snd_aica_probe,
+	.remove = snd_aica_remove,
+	.driver = {
+		   .name = SND_AICA_DRIVER},
+};
+
+static int __init aica_init(void)
+{
+	int err;
+	err = platform_driver_register(&snd_aica_driver);
+	if (unlikely(err < 0))
+		return err;
+	pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
+					     aica_memory_space, 2);
+	if (unlikely(IS_ERR(pd))) {
+		platform_driver_unregister(&snd_aica_driver);
+		return PTR_ERR(pd);
+	}
+	/* Load the firmware */
+	return load_aica_firmware();
+}
+
+static void __exit aica_exit(void)
+{
+	/* Destroy the aica kernel thread            *
+	 * being extra cautious to check if it exists*/
+	if (likely(aica_queue))
+		destroy_workqueue(aica_queue);
+	platform_device_unregister(pd);
+	platform_driver_unregister(&snd_aica_driver);
+	/* Kill any sound still playing and reset ARM7 to safe state */
+	spu_reset();
+}
+
+module_init(aica_init);
+module_exit(aica_exit);
diff --git a/sound/sh/aica.h b/sound/sh/aica.h
new file mode 100644
index 0000000..8c11e3d
--- /dev/null
+++ b/sound/sh/aica.h
@@ -0,0 +1,81 @@
+/* aica.h
+ * Header file for ALSA driver for
+ * Sega Dreamcast Yamaha AICA sound
+ * Copyright Adrian McMenamin
+ * <adrian@mcmen.demon.co.uk>
+ * 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* SPU memory and register constants etc */
+#define G2_FIFO 0xa05f688c
+#define SPU_MEMORY_BASE 0xA0800000
+#define ARM_RESET_REGISTER 0xA0702C00
+#define SPU_REGISTER_BASE 0xA0700000
+
+/* AICA channels stuff */
+#define AICA_CONTROL_POINT 0xA0810000
+#define AICA_CONTROL_CHANNEL_SAMPLE_NUMBER 0xA0810008
+#define AICA_CHANNEL0_CONTROL_OFFSET 0x10004
+
+/* Command values */
+#define AICA_CMD_KICK 0x80000000
+#define AICA_CMD_NONE 0
+#define AICA_CMD_START 1
+#define AICA_CMD_STOP 2
+#define AICA_CMD_VOL 3
+
+/* Sound modes */
+#define SM_8BIT		1
+#define SM_16BIT	0
+#define SM_ADPCM	2
+
+/* Buffer and period size */
+#define AICA_BUFFER_SIZE 0x8000
+#define AICA_PERIOD_SIZE 0x800
+#define AICA_PERIOD_NUMBER 16
+
+#define AICA_CHANNEL0_OFFSET 0x11000
+#define AICA_CHANNEL1_OFFSET 0x21000
+#define CHANNEL_OFFSET 0x10000
+
+#define AICA_DMA_CHANNEL 0
+#define AICA_DMA_MODE 5
+
+#define SND_AICA_DRIVER "AICA"
+
+struct aica_channel {
+	uint32_t cmd;		/* Command ID           */
+	uint32_t pos;		/* Sample position      */
+	uint32_t length;	/* Sample length        */
+	uint32_t freq;		/* Frequency            */
+	uint32_t vol;		/* Volume 0-255         */
+	uint32_t pan;		/* Pan 0-255            */
+	uint32_t sfmt;		/* Sound format         */
+	uint32_t flags;		/* Bit flags            */
+};
+
+struct snd_card_aica {
+	struct work_struct spu_dma_work;
+	struct snd_card *card;
+	struct aica_channel *channel;
+	struct snd_pcm_substream *substream;
+	int clicks;
+	int current_period;
+	struct timer_list timer;
+	int master_volume;
+	int dma_check;
+};
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 10cffc0..97b2552 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -27,6 +27,7 @@
 source "sound/soc/at91/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/sh/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0ae2e49..3041403 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
-obj-$(CONFIG_SND_SOC)	+= codecs/ at91/ pxa/ s3c24xx/
+obj-$(CONFIG_SND_SOC)	+= codecs/ at91/ pxa/ s3c24xx/ sh/
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 044a371..e97c683 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,6 +1,7 @@
 config SND_S3C24XX_SOC
 	tristate "SoC Audio for the Samsung S3C24XX chips"
 	depends on ARCH_S3C2410 && SND_SOC
+	select SND_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the S3C24XX AC97, I2S or SSP interface. You will also need
@@ -8,3 +9,29 @@
 
 config SND_S3C24XX_SOC_I2S
 	tristate
+
+config SND_S3C2443_SOC_AC97
+	tristate
+	select AC97_BUS
+	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
+	
+config SND_S3C24XX_SOC_NEO1973_WM8753
+	tristate "SoC I2S Audio support for NEO1973 - WM8753"
+	depends on SND_S3C24XX_SOC && MACH_GTA01
+	select SND_S3C24XX_SOC_I2S
+	select SND_SOC_WM8753
+	help
+	  Say Y if you want to add support for SoC audio on smdk2440
+	  with the WM8753.
+
+config SND_S3C24XX_SOC_SMDK2443_WM9710
+	tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+	depends on SND_S3C24XX_SOC && MACH_SMDK2443
+	select SND_S3C2443_SOC_AC97
+	select SND_SOC_AC97_CODEC
+	help
+	  Say Y if you want to add support for SoC audio on smdk2443
+	  with the WM9710.
+
+
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 6f0fffc..13c92f0 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,6 +1,15 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := s3c24xx-pcm.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+
+# S3C24XX Machine Support
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+
+obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
new file mode 100644
index 0000000..0cf5b70
--- /dev/null
+++ b/sound/soc/s3c24xx/lm4857.h
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ *  Revision history
+ *    18th Jun 2007   Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
new file mode 100644
index 0000000..d5a8fc2
--- /dev/null
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -0,0 +1,670 @@
+/*
+ * neo1973_wm8753.c  --  SoC audio for Neo1973
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ *  Revision history
+ *    20th Jan 2007   Initial version.
+ *    05th Feb 2007   Rename all to Neo1973
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF			0
+#define NEO_GSM_CALL_AUDIO_HANDSET	1
+#define NEO_GSM_CALL_AUDIO_HEADSET	2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH	3
+#define NEO_STEREO_TO_SPEAKERS		4
+#define NEO_STEREO_TO_HEADPHONES	5
+#define NEO_CAPTURE_HANDSET		6
+#define NEO_CAPTURE_HEADSET		7
+#define NEO_CAPTURE_BLUETOOTH		8
+
+static struct snd_soc_machine neo1973;
+static struct i2c_client *i2c;
+
+static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+	unsigned int pll_out = 0, bclk = 0;
+	int ret = 0;
+	unsigned long iis_clkrate;
+
+	iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+		pll_out = 12288000;
+		break;
+	case 48000:
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 12288000;
+		break;
+	case 96000:
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 12288000;
+		break;
+	case 11025:
+		bclk = WM8753_BCLK_DIV_16;
+		pll_out = 11289600;
+		break;
+	case 22050:
+		bclk = WM8753_BCLK_DIV_8;
+		pll_out = 11289600;
+		break;
+	case 44100:
+		bclk = WM8753_BCLK_DIV_4;
+		pll_out = 11289600;
+		break;
+	case 88200:
+		bclk = WM8753_BCLK_DIV_2;
+		pll_out = 11289600;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set MCLK division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+		S3C2410_IISMOD_32FS );
+	if (ret < 0)
+		return ret;
+
+	/* set codec BCLK division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+	if (ret < 0)
+		return ret;
+
+	/* set prescaler division for sample rate */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+		S3C24XX_PRESCALE(4,4));
+	if (ret < 0)
+		return ret;
+
+	/* codec PLL input is PCLK/4 */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1,
+		iis_clkrate / 4, pll_out);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+	.hw_params = neo1973_hifi_hw_params,
+	.hw_free = neo1973_hifi_hw_free,
+};
+
+static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+	unsigned int pcmdiv = 0;
+	int ret = 0;
+	unsigned long iis_clkrate;
+
+	iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+	if (params_rate(params) != 8000)
+		return -EINVAL;
+	if (params_channels(params) != 1)
+		return -EINVAL;
+
+	pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+	/* todo: gg check mode (DSP_B) against CSR datasheet */
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the codec system clock for DAC and ADC */
+	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set codec PCM division for sample rate */
+	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+	if (ret < 0)
+		return ret;
+
+	/* configue and enable PLL for 12.288MHz output */
+	ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
+		iis_clkrate / 4, 12288000);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+	/* disable the PLL */
+	return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+	.hw_params = neo1973_voice_hw_params,
+	.hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario = 0;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = neo1973_scenario;
+	return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+	switch(neo1973_scenario) {
+	case NEO_AUDIO_OFF:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_GSM_CALL_AUDIO_HANDSET:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+		break;
+	case NEO_GSM_CALL_AUDIO_HEADSET:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_GSM_CALL_AUDIO_BLUETOOTH:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_STEREO_TO_SPEAKERS:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_STEREO_TO_HEADPHONES:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_CAPTURE_HANDSET:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+		break;
+	case NEO_CAPTURE_HEADSET:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	case NEO_CAPTURE_BLUETOOTH:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+		break;
+	default:
+		snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+		snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+		snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+		snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+
+	return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (neo1973_scenario == ucontrol->value.integer.value[0])
+		return 0;
+
+	neo1973_scenario = ucontrol->value.integer.value[0];
+	set_scenario_endpoints(codec, neo1973_scenario);
+	return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+	if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+		printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int reg=kcontrol->private_value & 0xFF;
+	int shift = (kcontrol->private_value >> 8) & 0x0F;
+	int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+	ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+	return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	int reg = kcontrol->private_value & 0xFF;
+	int shift = (kcontrol->private_value >> 8) & 0x0F;
+	int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+	if (((lm4857_regs[reg] >> shift ) & mask) ==
+		ucontrol->value.integer.value[0])
+		return 0;
+
+	lm4857_regs[reg] &= ~ (mask << shift);
+	lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+	lm4857_write_regs();
+	return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+	if (value)
+		value -= 5;
+
+	ucontrol->value.integer.value[0] = value;
+	return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	u8 value = ucontrol->value.integer.value[0];
+
+	if (value)
+		value += 5;
+
+	if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+		return 0;
+
+	lm4857_regs[LM4857_CTRL] &= 0xF0;
+	lm4857_regs[LM4857_CTRL] |= value;
+	lm4857_write_regs();
+	return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Audio Out", NULL),
+	SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+	SND_SOC_DAPM_LINE("GSM Line In", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+	/* Connections to the lm4857 amp */
+	{"Audio Out", NULL, "LOUT1"},
+	{"Audio Out", NULL, "ROUT1"},
+
+	/* Connections to the GSM Module */
+	{"GSM Line Out", NULL, "MONO1"},
+	{"GSM Line Out", NULL, "MONO2"},
+	{"RXP", NULL, "GSM Line In"},
+	{"RXN", NULL, "GSM Line In"},
+
+	/* Connections to Headset */
+	{"MIC1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Headset Mic"},
+
+	/* Call Mic */
+	{"MIC2", NULL, "Mic Bias"},
+	{"MIC2N", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Call Mic"},
+
+	/* Connect the ALC pins */
+	{"ACIN", NULL, "ACOP"},
+
+	{NULL, NULL, NULL},
+};
+
+static const char *lm4857_mode[] = {
+	"Off",
+	"Call Speaker",
+	"Stereo Speakers",
+	"Stereo Speakers + Headphones",
+	"Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+	"Off",
+	"GSM Handset",
+	"GSM Headset",
+	"GSM Bluetooth",
+	"Speakers",
+	"Headphones",
+	"Capture Handset",
+	"Capture Headset",
+	"Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios),neo_scenarios),
+};
+
+static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
+	SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+		lm4857_get_mode, lm4857_set_mode),
+	SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+		neo1973_get_scenario, neo1973_set_scenario),
+	SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+		lm4857_get_reg, lm4857_set_reg),
+	SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+		lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+{
+	int i, err;
+
+	/* set up NC codec pins */
+	snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
+	snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
+	snd_soc_dapm_set_endpoint(codec, "OUT3",  0);
+	snd_soc_dapm_set_endpoint(codec, "OUT4",  0);
+	snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
+	snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
+
+
+	/* set endpoints to default mode */
+	set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
+	/* Add neo1973 specific widgets */
+	for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
+		snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
+
+	/* add neo1973 specific controls */
+	for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
+		err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8753_neo1973_controls[i],
+				codec, NULL));
+		if (err < 0)
+			return err;
+	}
+
+	/* set up neo1973 specific audio path audio_mapnects */
+	for (i = 0; audio_map[i][0] != NULL; i++) {
+		snd_soc_dapm_connect_input(codec, audio_map[i][0],
+			audio_map[i][1], audio_map[i][2]);
+	}
+
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_cpu_dai bt_dai =
+{	.name = "Bluetooth",
+	.id = 0,
+	.type = SND_SOC_DAI_PCM,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+	.name = "WM8753",
+	.stream_name = "WM8753 HiFi",
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+	.init = neo1973_wm8753_init,
+	.ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+	.name = "Bluetooth",
+	.stream_name = "Voice",
+	.cpu_dai = &bt_dai,
+	.codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+	.ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_machine neo1973 = {
+	.name = "neo1973",
+	.dai_link = neo1973_dai,
+	.num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static struct wm8753_setup_data neo1973_wm8753_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device neo1973_snd_devdata = {
+	.machine = &neo1973,
+	.platform = &s3c24xx_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8753,
+	.codec_data = &neo1973_wm8753_setup,
+};
+
+static struct i2c_client client_template;
+
+static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+	int ret;
+
+	client_template.adapter = adap;
+	client_template.addr = addr;
+
+	i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+	if (i2c == NULL)
+		return -ENOMEM;
+
+	ret = i2c_attach_client(i2c);
+	if (ret < 0) {
+		printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
+		goto exit_err;
+	}
+
+	lm4857_write_regs();
+	return ret;
+
+exit_err:
+	kfree(i2c);
+	return ret;
+}
+
+static int lm4857_i2c_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+	kfree(client);
+	return 0;
+}
+
+static int lm4857_i2c_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver lm4857_i2c_driver = {
+	.driver = {
+		.name = "LM4857 I2C Amp",
+		.owner = THIS_MODULE,
+	},
+	.id =             I2C_DRIVERID_LM4857,
+	.attach_adapter = lm4857_i2c_attach,
+	.detach_client =  lm4857_i2c_detach,
+	.command =        NULL,
+};
+
+static struct i2c_client client_template = {
+	.name =   "LM4857",
+	.driver = &lm4857_i2c_driver,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+	int ret;
+
+	neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!neo1973_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
+	neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+	ret = platform_device_add(neo1973_snd_device);
+
+	if (ret)
+		platform_device_put(neo1973_snd_device);
+
+	ret = i2c_add_driver(&lm4857_i2c_driver);
+	if (ret != 0)
+		printk(KERN_ERR "can't add i2c driver");
+
+	return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+	platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
new file mode 100644
index 0000000..75acf7e
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -0,0 +1,401 @@
+/*
+ * s3c2443-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
+ *  All rights reserved.
+ *
+ *  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.
+ *
+ *  Revision history
+ *	21st Mar 2007   Initial Version
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/audio.h>
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+struct s3c24xx_ac97_info {
+	void __iomem	*regs;
+	struct clk	*ac97_clk;
+};
+static struct s3c24xx_ac97_info s3c24xx_ac97;
+
+DECLARE_COMPLETION(ac97_completion);
+static u32 codec_ready;
+static DECLARE_MUTEX(ac97_mutex);
+
+static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
+	unsigned short reg)
+{
+	u32 ac_glbctrl;
+	u32 ac_codec_cmd;
+	u32 stat, addr, data;
+
+	down(&ac97_mutex);
+
+	codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+	ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+	ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+	writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+	udelay(50);
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+	wait_for_completion(&ac97_completion);
+
+	stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
+	addr = (stat >> 16) & 0x7f;
+	data = (stat & 0xffff);
+
+	if (addr != reg)
+		printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
+				" rep addr = %02x\n", reg, addr);
+
+	up(&ac97_mutex);
+
+	return (unsigned short)data;
+}
+
+static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+	unsigned short val)
+{
+	u32 ac_glbctrl;
+	u32 ac_codec_cmd;
+
+	down(&ac97_mutex);
+
+	codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+	ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+	ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+	writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+	udelay(50);
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+	wait_for_completion(&ac97_completion);
+
+	ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+	ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+	writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+	up(&ac97_mutex);
+
+}
+
+static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	u32 ac_glbctrl;
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl = 0;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+}
+
+static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	u32 ac_glbctrl;
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl = 0;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
+		S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+}
+
+static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
+{
+	int status;
+	u32 ac_glbctrl;
+
+	status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
+
+	if (status) {
+		ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+		ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+		writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+		complete(&ac97_completion);
+	}
+	return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read	= s3c2443_ac97_read,
+	.write	= s3c2443_ac97_write,
+	.warm_reset	= s3c2443_ac97_warm_reset,
+	.reset	= s3c2443_ac97_cold_reset,
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_out = {
+	.name = "AC97 PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_in = {
+	.name = "AC97 PCM Stereo in"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_micin = {
+	.name = "AC97 Mic Mono in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+	.client		= &s3c2443_dma_client_out,
+	.channel	= DMACH_PCM_OUT,
+	.dma_addr	= S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+	.dma_size	= 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+	.client		= &s3c2443_dma_client_in,
+	.channel	= DMACH_PCM_IN,
+	.dma_addr	= S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+	.dma_size	= 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+	.client		= &s3c2443_dma_client_micin,
+	.channel	= DMACH_MIC_IN,
+	.dma_addr	= S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+	.dma_size	= 4,
+};
+
+static int s3c2443_ac97_probe(struct platform_device *pdev)
+{
+	int ret;
+	u32 ac_glbctrl;
+
+	s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
+	if (s3c24xx_ac97.regs == NULL)
+		return -ENXIO;
+
+	s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+	if (s3c24xx_ac97.ac97_clk == NULL) {
+		printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
+		iounmap(s3c24xx_ac97.regs);
+		return -ENODEV;
+	}
+	clk_enable(s3c24xx_ac97.ac97_clk);
+
+	s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
+	s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
+	s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
+	s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
+	s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl = 0;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	msleep(1);
+
+	ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+	ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq,
+		IRQF_DISABLED, "AC97", NULL);
+	if (ret < 0) {
+		printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
+		clk_disable(s3c24xx_ac97.ac97_clk);
+		clk_put(s3c24xx_ac97.ac97_clk);
+		iounmap(s3c24xx_ac97.regs);
+	}
+	return ret;
+}
+
+static void s3c2443_ac97_remove(struct platform_device *pdev)
+{
+	free_irq(IRQ_S3C2443_AC97, NULL);
+	clk_disable(s3c24xx_ac97.ac97_clk);
+	clk_put(s3c24xx_ac97.ac97_clk);
+	iounmap(s3c24xx_ac97.regs);
+}
+
+static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
+	else
+		cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
+
+	return 0;
+}
+
+static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	u32 ac_glbctrl;
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	switch(cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+		else
+			ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+		else
+			ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+		break;
+	}
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+	return 0;
+}
+
+static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+	else
+		cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
+
+	return 0;
+}
+
+static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
+	int cmd)
+{
+	u32 ac_glbctrl;
+
+	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+	switch(cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+	}
+	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+	return 0;
+}
+
+#define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai s3c2443_ac97_dai[] = {
+{
+	.name = "s3c2443-ac97",
+	.id = 0,
+	.type = SND_SOC_DAI_AC97,
+	.probe = s3c2443_ac97_probe,
+	.remove = s3c2443_ac97_remove,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = s3c2443_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = s3c2443_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.hw_params = s3c2443_ac97_hw_params,
+		.trigger = s3c2443_ac97_trigger},
+},
+{
+	.name = "pxa2xx-ac97-mic",
+	.id = 1,
+	.type = SND_SOC_DAI_AC97,
+	.capture = {
+		.stream_name = "AC97 Mic Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = s3c2443_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = {
+		.hw_params = s3c2443_ac97_hw_mic_params,
+		.trigger = s3c2443_ac97_mic_trigger,},
+},
+};
+
+EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
new file mode 100644
index 0000000..2b835e8
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c24xx-ac97.h
@@ -0,0 +1,25 @@
+/*
+ * s3c24xx-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ *  Revision history
+ *    10th Nov 2006   Initial version.
+ */
+
+#ifndef S3C24XXAC97_H_
+#define S3C24XXAC97_H_
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
+
+#endif /*S3C24XXAC97_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 8ca314d..39f0246 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -344,11 +344,11 @@
 	DBG("Entered %s\n", __FUNCTION__);
 
 	switch (div_id) {
-	case S3C24XX_DIV_MCLK:
+	case S3C24XX_DIV_BCLK:
 		reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
 		writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
 		break;
-	case S3C24XX_DIV_BCLK:
+	case S3C24XX_DIV_MCLK:
 		reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
 		writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
 		break;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
new file mode 100644
index 0000000..d46cd81
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -0,0 +1,85 @@
+/*
+ * smdk2443_wm9710.c  --  SoC audio for smdk2443
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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.
+ *
+ *  Revision history
+ *    8th Mar 2007   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+static struct snd_soc_machine smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &s3c2443_ac97_dai[0],
+	.codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine smdk2443 = {
+	.name = "SMDK2443",
+	.dai_link = smdk2443_dai,
+	.num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct snd_soc_device smdk2443_snd_ac97_devdata = {
+	.machine = &smdk2443,
+	.platform = &s3c24xx_soc_platform,
+	.codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+	int ret;
+
+	smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!smdk2443_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(smdk2443_snd_ac97_device,
+				&smdk2443_snd_ac97_devdata);
+	smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+	ret = platform_device_add(smdk2443_snd_ac97_device);
+
+	if (ret)
+		platform_device_put(smdk2443_snd_ac97_device);
+
+	return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+	platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
new file mode 100644
index 0000000..f03220d2
--- /dev/null
+++ b/sound/soc/sh/Kconfig
@@ -0,0 +1,38 @@
+menu "SoC Audio support for SuperH"
+
+config SND_SOC_PCM_SH7760
+	tristate "SoC Audio support for Renesas SH7760"
+	depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG
+	help
+	  Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+	select AC97_BUS
+	select SND_SOC_AC97_BUS
+	select SND_AC97_CODEC
+	tristate
+
+config SND_SOC_SH4_SSI
+	tristate
+
+
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+	tristate "SH7760 AC97 sound support"
+	depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+	select SND_SOC_SH4_HAC
+	select SND_SOC_AC97_CODEC
+	help
+	  This option enables generic sound support for the first
+	  AC97 unit of the SH7760.
+
+endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
new file mode 100644
index 0000000..a8e8ab8
--- /dev/null
+++ b/sound/soc/sh/Makefile
@@ -0,0 +1,14 @@
+## DMA engines
+snd-soc-dma-sh7760-objs	:= dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760)	+= snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-objs	:= hac.o
+snd-soc-ssi-objs	:= ssi.o
+obj-$(CONFIG_SND_SOC_SH4_HAC)	+= snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI)	+= snd-soc-ssi.o
+
+## boards
+snd-soc-sh7760-ac97-objs	:= sh7760-ac97.o
+
+obj-$(CONFIG_SND_SH7760_AC97)	+= snd-soc-sh7760-ac97.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
new file mode 100644
index 0000000..cdee374
--- /dev/null
+++ b/sound/soc/sh/dma-sh7760.c
@@ -0,0 +1,354 @@
+/*
+ * SH7760 ("camelot") DMABRG audio DMA unit support
+ *
+ * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+ * trigger an interrupt when one half of the programmed transfer size
+ * has been xmitted.
+ *
+ * FIXME: little-endian only for now
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR	0x00
+#define BRGARXDAR	0x04
+#define BRGATXTCR	0x08
+#define BRGARXTCR	0x0C
+#define BRGACR		0x10
+#define BRGATXTCNT	0x14
+#define BRGARXTCNT	0x18
+
+#define ACR_RAR		(1 << 18)
+#define ACR_RDS		(1 << 17)
+#define ACR_RDE		(1 << 16)
+#define ACR_TAR		(1 << 2)
+#define ACR_TDS		(1 << 1)
+#define ACR_TDE		(1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE	(0 << 24)
+#define ACR_RAM_4BYTE	(1 << 24)
+#define ACR_RAM_2WORD	(2 << 24)
+#define ACR_TAM_NONE	(0 << 8)
+#define ACR_TAM_4BYTE	(1 << 8)
+#define ACR_TAM_2WORD	(2 << 8)
+
+
+struct camelot_pcm {
+	unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
+	unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
+
+	struct snd_pcm_substream *tx_ss;
+	unsigned long tx_period_size;
+	unsigned int  tx_period;
+
+	struct snd_pcm_substream *rx_ss;
+	unsigned long rx_period_size;
+	unsigned int  rx_period;
+
+} cam_pcm_data[2] = {
+	{
+		.mmio	=	0xFE3C0040,
+		.txid	=	DMABRGIRQ_A0TXF,
+	},
+	{
+		.mmio	=	0xFE3C0060,
+		.txid	=	DMABRGIRQ_A1TXF,
+	},
+};
+
+#define BRGREG(x)	(*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active).  The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN		16 * 1024
+#define DMABRG_PERIOD_MAX		0x03fffffc
+#define DMABRG_PREALLOC_BUFFER		32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX	32 * 1024
+
+/* support everything the SSI supports */
+#define DMABRG_RATES	\
+	SNDRV_PCM_RATE_8000_192000
+
+#define DMABRG_FMTS	\
+	(SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |	\
+	 SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |	\
+	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |	\
+	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |	\
+	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_pcm_hardware camelot_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =	DMABRG_FMTS,
+	.rates =	DMABRG_RATES,
+	.rate_min =		8000,
+	.rate_max =		192000,
+	.channels_min =		2,
+	.channels_max =		8,		/* max of the SSI */
+	.buffer_bytes_max =	DMABRG_PERIOD_MAX,
+	.period_bytes_min =	DMABRG_PERIOD_MIN,
+	.period_bytes_max =	DMABRG_PERIOD_MAX / 2,
+	.periods_min =		2,
+	.periods_max =		2,
+	.fifo_size =		128,
+};
+
+static void camelot_txdma(void *data)
+{
+	struct camelot_pcm *cam = data;
+	cam->tx_period ^= 1;
+	snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+	struct camelot_pcm *cam = data;
+	cam->rx_period ^= 1;
+	snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+	int ret, dmairq;
+
+	snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+	/* DMABRG buffer half/full events */
+	dmairq = (recv) ? cam->txid + 2 : cam->txid;
+	if (recv) {
+		cam->rx_ss = substream;
+		ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+		if (unlikely(ret)) {
+			pr_debug("audio unit %d irqs already taken!\n",
+			     rtd->dai->cpu_dai->id);
+			return -EBUSY;
+		}
+		(void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+	} else {
+		cam->tx_ss = substream;
+		ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+		if (unlikely(ret)) {
+			pr_debug("audio unit %d irqs already taken!\n",
+			     rtd->dai->cpu_dai->id);
+			return -EBUSY;
+		}
+		(void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+	}
+	return 0;
+}
+
+static int camelot_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+	int dmairq;
+
+	dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+	if (recv)
+		cam->rx_ss = NULL;
+	else
+		cam->tx_ss = NULL;
+
+	dmabrg_free_irq(dmairq + 1);
+	dmabrg_free_irq(dmairq);
+
+	return 0;
+}
+
+static int camelot_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+	int ret;
+
+	ret = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+	if (ret < 0)
+		return ret;
+
+	if (recv) {
+		cam->rx_period_size = params_period_bytes(hw_params);
+		cam->rx_period = 0;
+	} else {
+		cam->tx_period_size = params_period_bytes(hw_params);
+		cam->tx_period = 0;
+	}
+	return 0;
+}
+
+static int camelot_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int camelot_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+
+	pr_debug("PCM data: addr 0x%08ulx len %d\n",
+		 (u32)runtime->dma_addr, runtime->dma_bytes);
+ 
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+		BRGREG(BRGATXTCR) = runtime->dma_bytes;
+	} else {
+		BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+		BRGREG(BRGARXTCR) = runtime->dma_bytes;
+	}
+
+	return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+	/* start DMABRG engine: XFER start, auto-addr-reload */
+	BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+	/* forcibly terminate data transmission */
+	BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+	/* start DMABRG engine: recv start, auto-reload */
+	BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+	/* forcibly terminate data receiver */
+	BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (recv)
+			dmabrg_rec_dma_start(cam);
+		else
+			dmabrg_play_dma_start(cam);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (recv)
+			dmabrg_rec_dma_stop(cam);
+		else
+			dmabrg_play_dma_stop(cam);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+	unsigned long pos;
+
+	/* cannot use the DMABRG pointer register: under load, by the
+	 * time ALSA comes around to read the register, it is already
+	 * far ahead (or worse, already done with the fragment) of the
+	 * position at the time the IRQ was triggered, which results in
+	 * fast-playback sound in my test application (ScummVM)
+	 */
+	if (recv)
+		pos = cam->rx_period ? cam->rx_period_size : 0;
+	else
+		pos = cam->tx_period ? cam->tx_period_size : 0;
+
+	return bytes_to_frames(runtime, pos);
+}
+
+static struct snd_pcm_ops camelot_pcm_ops = {
+	.open		= camelot_pcm_open,
+	.close		= camelot_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= camelot_hw_params,
+	.hw_free	= camelot_hw_free,
+	.prepare	= camelot_prepare,
+	.trigger	= camelot_trigger,
+	.pointer	= camelot_pos,
+};
+
+static void camelot_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int camelot_pcm_new(struct snd_card *card,
+			   struct snd_soc_codec_dai *dai,
+			   struct snd_pcm *pcm)
+{
+	/* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+	 * in MMAP mode (i.e. aplay -M)
+	 */
+	snd_pcm_lib_preallocate_pages_for_all(pcm,
+		SNDRV_DMA_TYPE_CONTINUOUS,
+		snd_dma_continuous_data(GFP_KERNEL),
+		DMABRG_PREALLOC_BUFFER,	DMABRG_PREALLOC_BUFFER_MAX);
+
+	return 0;
+}
+
+struct snd_soc_platform sh7760_soc_platform = {
+	.name		= "sh7760-pcm",
+	.pcm_ops 	= &camelot_pcm_ops,
+	.pcm_new	= camelot_pcm_new,
+	.pcm_free	= camelot_pcm_free,
+};
+EXPORT_SYMBOL_GPL(sh7760_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
new file mode 100644
index 0000000..8e3f039
--- /dev/null
+++ b/sound/soc/sh/hac.c
@@ -0,0 +1,322 @@
+/*
+ * Hitachi Audio Controller (AC97) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable HAC output pins!
+ */
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use.  You'll have
+ * to edit the code a bit to use the other AC97 unit.		--mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR		0x08
+#define HACCSAR		0x20
+#define HACCSDR		0x24
+#define HACPCML		0x28
+#define HACPCMR		0x2C
+#define HACTIER		0x50
+#define	HACTSR		0x54
+#define HACRIER		0x58
+#define HACRSR		0x5C
+#define HACACR		0x60
+
+#define CR_CR		(1 << 15)	/* "codec-ready" indicator */
+#define CR_CDRT		(1 << 11)	/* cold reset */
+#define CR_WMRT		(1 << 10)	/* warm reset */
+#define CR_B9		(1 << 9)	/* the mysterious "bit 9" */
+#define CR_ST		(1 << 5)	/* AC97 link start bit */
+
+#define CSAR_RD		(1 << 19)	/* AC97 data read bit */
+#define CSAR_WR		(0)
+
+#define TSR_CMDAMT	(1 << 31)
+#define TSR_CMDDMT	(1 << 30)
+
+#define RSR_STARY	(1 << 22)
+#define RSR_STDRY	(1 << 21)
+
+#define ACR_DMARX16	(1 << 30)
+#define ACR_DMATX16	(1 << 29)
+#define ACR_TX12ATOM	(1 << 26)
+#define ACR_DMARX20	((1 << 24) | (1 << 22))
+#define ACR_DMATX20	((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT	4
+#define CSDR_MASK	(0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT	12
+#define CSAR_MASK	(0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY	1
+#define AC97_READ_RETRY		5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1	500	/* 21 < E1 < 1000 */
+#define TMO_E2	13	/* 13 < E2 */
+#define TMO_E3	21	/* 21 < E3 */
+#define TMO_E4	500	/* 21 < E4 < 1000 */
+
+struct hac_priv {
+	unsigned long mmio;	/* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+	{
+		.mmio	= 0xFE240000,
+	},
+	{
+		.mmio	= 0xFE250000,
+	},
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+	{
+		.mmio	= 0xFFE40000,
+	},
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg)	(*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+			      unsigned short *v)
+{
+	unsigned int to1, to2, i;
+	unsigned short adr;
+
+	for (i = 0; i < AC97_READ_RETRY; ++i) {
+		*v = 0;
+		/* wait for HAC to receive something from the codec */
+		for (to1 = TMO_E4;
+		     to1 && !(HACREG(HACRSR) & RSR_STARY);
+		     --to1)
+			udelay(1);
+		for (to2 = TMO_E4; 
+		     to2 && !(HACREG(HACRSR) & RSR_STDRY);
+		     --to2)
+			udelay(1);
+
+		if (!to1 && !to2)
+			return 0;	/* codec comm is down */
+
+		adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+		*v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+		HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+		if (r == adr)
+			break;
+
+		/* manual says: wait at least 21 usec before retrying */
+		udelay(21);
+	}
+	HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+	return (i < AC97_READ_RETRY);
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+					 unsigned short reg)
+{
+	unsigned short val;
+	unsigned int i, to;
+
+	for (i = 0; i < AC97_READ_RETRY; i++) {
+		/* send_read_request */
+		local_irq_disable();
+		HACREG(HACTSR) &= ~(TSR_CMDAMT);
+		HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+		local_irq_enable();
+
+		for (to = TMO_E3;
+		     to && !(HACREG(HACTSR) & TSR_CMDAMT);
+		     --to)
+			udelay(1);
+
+		HACREG(HACTSR) &= ~TSR_CMDAMT;
+		val = 0;
+		if (hac_get_codec_data(hac, reg, &val) != 0)
+			break;
+	}
+
+	if (i == AC97_READ_RETRY)
+		return ~0;
+
+	return val;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+			   unsigned short val)
+{
+	int unit_id = 0 /* ac97->private_data */;
+	struct hac_priv *hac = &hac_cpu_data[unit_id];
+	unsigned int i, to;
+	/* write_codec_aux */
+	for (i = 0; i < AC97_WRITE_RETRY; i++) {
+		/* send_write_request */
+		local_irq_disable();
+		HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+		HACREG(HACCSDR) = (val << CSDR_SHIFT);
+		HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+		local_irq_enable();
+
+		/* poll-wait for CMDAMT and CMDDMT */
+		for (to = TMO_E1;
+		     to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+		     --to)
+			udelay(1);
+
+		HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+		if (to)
+			break;
+		/* timeout, try again */
+	}
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+				    unsigned short reg)
+{
+	int unit_id = 0 /* ac97->private_data */;
+	struct hac_priv *hac = &hac_cpu_data[unit_id];
+	return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+	int unit_id = 0 /* ac97->private_data */;
+	struct hac_priv *hac = &hac_cpu_data[unit_id];
+	unsigned int tmo;
+
+	HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+	msleep(10);
+	HACREG(HACCR) = CR_ST | CR_B9;
+	for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+		udelay(1);
+
+	if (!tmo)
+		printk(KERN_INFO "hac: reset: AC97 link down!\n");
+	/* settings this bit lets us have a conversation with codec */
+	HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+	int unit_id = 0 /* ac97->private_data */;
+	struct hac_priv *hac;
+	hac = &hac_cpu_data[unit_id];
+
+	HACREG(HACCR) = 0;
+	HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+	msleep(10);
+	hac_ac97_warmrst(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read	= hac_ac97_read,
+	.write	= hac_ac97_write,
+	.reset	= hac_ac97_coldrst,
+	.warm_reset = hac_ac97_warmrst,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+	int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+	switch (params->msbits) {
+	case 16:
+		HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
+		HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+		break;
+	case 20:
+		HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+		HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
+		break;
+	default:
+		pr_debug("hac: invalid depth %d bit\n", params->msbits);
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+#define AC97_RATES	\
+	SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS	\
+	SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_cpu_dai sh4_hac_dai[] = {
+{
+	.name			= "HAC0",
+	.id			= 0,
+	.type			= SND_SOC_DAI_AC97,
+	.playback = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.ops = {
+		.hw_params	= hac_hw_params,
+	},
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+	.name			= "HAC1",
+	.id			= 1,
+	.type			= SND_SOC_DAI_AC97,
+	.playback = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.ops = {
+		.hw_params	= hac_hw_params,
+	},
+
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_hac_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
new file mode 100644
index 0000000..5563f14
--- /dev/null
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -0,0 +1,92 @@
+/*
+ * Generic AC97 sound support for SH7760
+ *
+ * (c) 2007 Manuel Lauss
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+
+#include "../codecs/ac97.h"
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+
+static int machine_init(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_sync_endpoints(codec);
+	return 0;
+}
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &sh4_hac_dai[0],	/* HAC0 */
+	.codec_dai = &ac97_dai,
+	.init = machine_init,
+	.ops = NULL,
+};
+
+static struct snd_soc_machine sh7760_ac97_soc_machine  = {
+	.name = "SH7760 AC97",
+	.dai_link = &sh7760_ac97_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device sh7760_ac97_snd_devdata = {
+	.machine = &sh7760_ac97_soc_machine,
+	.platform = &sh7760_soc_platform,
+	.codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+	int ret;
+	unsigned short ipsel;
+
+	/* enable both AC97 controllers in pinmux reg */
+	ipsel = ctrl_inw(IPSEL);
+	ctrl_outw(ipsel | (3 << 10), IPSEL);
+
+	ret = -ENOMEM;
+	sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!sh7760_ac97_snd_device)
+		goto out;
+
+	platform_set_drvdata(sh7760_ac97_snd_device,
+			     &sh7760_ac97_snd_devdata);
+	sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+	ret = platform_device_add(sh7760_ac97_snd_device);
+
+	if (ret)
+		platform_device_put(sh7760_ac97_snd_device);
+
+out:
+	return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+	platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
new file mode 100644
index 0000000..b72bc31
--- /dev/null
+++ b/sound/soc/sh/ssi.c
@@ -0,0 +1,400 @@
+/*
+ * Serial Sound Interface (I2S) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable SSI output pins!
+ */
+
+/*
+ * LIMITATIONS:
+ *	The SSI unit has only one physical data line, so full duplex is
+ *	impossible.  This can be remedied  on the  SH7760 by  using the
+ *	other SSI unit for recording; however the SH7780 has only 1 SSI
+ *	unit, and its pins are shared with the AC97 unit,  among others.
+ *
+ * FEATURES:
+ *	The SSI features "compressed mode": in this mode it continuously
+ *	streams PCM data over the I2S lines and uses LRCK as a handshake
+ *	signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
+ *	The number of bits sent over the wire in a frame can be adjusted
+ *	and can be independent from the actual sample bit depth. This is
+ *	useful to support TDM mode codecs like the AD1939 which have a
+ *	fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR	0x00
+#define SSISR	0x04
+
+#define CR_DMAEN	(1 << 28)
+#define CR_CHNL_SHIFT	22
+#define CR_CHNL_MASK	(3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT	19
+#define CR_DWL_MASK	(7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT	16
+#define CR_SWL_MASK	(7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER	(1 << 15)	/* bitclock master bit */
+#define CR_SWS_MASTER	(1 << 14)	/* wordselect master bit */
+#define CR_SCKP		(1 << 13)	/* I2Sclock polarity */
+#define CR_SWSP		(1 << 12)	/* LRCK polarity */
+#define CR_SPDP		(1 << 11)
+#define CR_SDTA		(1 << 10)	/* i2s alignment (msb/lsb) */
+#define CR_PDTA		(1 << 9)	/* fifo data alignment */
+#define CR_DEL		(1 << 8)	/* delay data by 1 i2sclk */
+#define CR_BREN		(1 << 7)	/* clock gating in burst mode */
+#define CR_CKDIV_SHIFT	4
+#define CR_CKDIV_MASK	(7 << CR_CKDIV_SHIFT)	/* bitclock divider */
+#define CR_MUTE		(1 << 3)	/* SSI mute */
+#define CR_CPEN		(1 << 2)	/* compressed mode */
+#define CR_TRMD		(1 << 1)	/* transmit/receive select */
+#define CR_EN		(1 << 0)	/* enable SSI */
+
+#define SSIREG(reg)	(*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+	unsigned long mmio;
+	unsigned long sysclk;
+	int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+	{
+		.mmio	= 0xFE680000,
+	},
+	{
+		.mmio	= 0xFE690000,
+	},
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+	{
+		.mmio	= 0xFFE70000,
+	},
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+	if (ssi->inuse) {
+		pr_debug("ssi: already in use!\n");
+		return -EBUSY;
+	} else
+		ssi->inuse = 1;
+	return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+	ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+	unsigned long ssicr = SSIREG(SSICR);
+	unsigned int bits, channels, swl, recv, i;
+
+	channels = params_channels(params);
+	bits = params->msbits;
+	recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+	pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
+	pr_debug("bits: %d channels: %d\n", bits, channels);
+
+	ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+		   CR_SWL_MASK);
+
+	/* direction (send/receive) */
+	if (!recv)
+		ssicr |= CR_TRMD;	/* transmit */
+
+	/* channels */
+	if ((channels < 2) || (channels > 8) || (channels & 1)) {
+		pr_debug("ssi: invalid number of channels\n");
+		return -EINVAL;
+	}
+	ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+	/* DATA WORD LENGTH (DWL): databits in audio sample */
+	i = 0;
+	switch (bits) {
+	case 32: ++i;
+	case 24: ++i;
+	case 22: ++i;
+	case 20: ++i;
+	case 18: ++i;
+	case 16: ++i;
+		 ssicr |= i << CR_DWL_SHIFT;
+	case 8:	 break;
+	default:
+		pr_debug("ssi: invalid sample width\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+	 * wires. This is usually bits_per_sample x channels/2;  i.e. in
+	 * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
+	 * product of (channels_per_slot x samplebits), e.g.  for codecs
+	 * like the AD1939 which  only accept 32bit wide TDM slots.  For
+	 * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+	 * Waiting for ASoC to get TDM support ;-)
+	 */
+	if ((bits > 16) && (bits <= 24)) {
+		bits = 24;	/* these are padded by the SSI */
+		/*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+	}
+	i = 0;
+	swl = (bits * channels) / 2;
+	switch (swl) {
+	case 256: ++i;
+	case 128: ++i;
+	case 64:  ++i;
+	case 48:  ++i;
+	case 32:  ++i;
+	case 16:  ++i;
+		  ssicr |= i << CR_SWL_SHIFT;
+	case 8:   break;
+	default:
+		pr_debug("ssi: invalid system word length computed\n");
+		return -EINVAL;
+	}
+
+	SSIREG(SSICR) = ssicr;
+
+	pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+	return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+			  unsigned int freq, int dir)
+{
+	struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+	ssi->sysclk = freq;
+
+	return 0;
+}
+
+/*
+ * This divider is used to generate the SSI_SCK (I2S bitclock) from the
+ * clock at the HAC_BIT_CLK ("oversampling clock") pin.
+ */
+static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
+{
+	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+	unsigned long ssicr;
+	int i;
+
+	i = 0;
+	ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+	switch (div) {
+	case 16: ++i;
+	case 8:  ++i;
+	case 4:  ++i;
+	case 2:  ++i;
+		 SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+	case 1:  break;
+	default:
+		pr_debug("ssi: invalid sck divider %d\n", div);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+{
+	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+	unsigned long ssicr = SSIREG(SSICR);
+
+	pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
+
+	ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+		   CR_SWS_MASTER | CR_SCK_MASTER);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		ssicr |= CR_DEL | CR_PDTA;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		ssicr |= CR_DEL;
+		break;
+	default:
+		pr_debug("ssi: unsupported format\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+	case SND_SOC_DAIFMT_CONT:
+		break;
+	case SND_SOC_DAIFMT_GATED:
+		ssicr |= CR_BREN;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		ssicr |= CR_SCKP;	/* sample data at low clkedge */
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		ssicr |= CR_SCKP | CR_SWSP;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		ssicr |= CR_SWSP;	/* word select starts low */
+		break;
+	default:
+		pr_debug("ssi: invalid inversion\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		ssicr |= CR_SCK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		ssicr |= CR_SWS_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+		break;
+	default:
+		pr_debug("ssi: invalid master/slave configuration\n");
+		return -EINVAL;
+	}
+
+	SSIREG(SSICR) = ssicr;
+	pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+	return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode,  so really this is board specific;  the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES	\
+	SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS	\
+	(SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |	\
+	 SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |	\
+	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |	\
+	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |	\
+	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+struct snd_soc_cpu_dai sh4_ssi_dai[] = {
+{
+	.name			= "SSI0",
+	.id			= 0,
+	.type			= SND_SOC_DAI_I2S,
+	.playback = {
+		.rates		= SSI_RATES,
+		.formats	= SSI_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 8,
+	},
+	.capture = {
+		.rates		= SSI_RATES,
+		.formats	= SSI_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 8,
+	},
+	.ops = {
+		.startup	= ssi_startup,
+		.shutdown	= ssi_shutdown,
+		.trigger	= ssi_trigger,
+		.hw_params	= ssi_hw_params,
+	},
+	.dai_ops = {
+		.set_sysclk	= ssi_set_sysclk,
+		.set_clkdiv	= ssi_set_clkdiv,
+		.set_fmt	= ssi_set_fmt,
+	},
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+	.name			= "SSI1",
+	.id			= 1,
+	.type			= SND_SOC_DAI_I2S,
+	.playback = {
+		.rates		= SSI_RATES,
+		.formats	= SSI_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 8,
+	},
+	.capture = {
+		.rates		= SSI_RATES,
+		.formats	= SSI_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 8,
+	},
+	.ops = {
+		.startup	= ssi_startup,
+		.shutdown	= ssi_shutdown,
+		.trigger	= ssi_trigger,
+		.hw_params	= ssi_hw_params,
+	},
+	.dai_ops = {
+		.set_sysclk	= ssi_set_sysclk,
+		.set_clkdiv	= ssi_set_clkdiv,
+		.set_fmt	= ssi_set_fmt,
+	},
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_ssi_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 8ebc1ad..7bd5852 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2350,7 +2350,9 @@
 			return 1;
 		break;
 	case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-		return 1;
+		if (device_setup[chip->index] == 0x00 ||
+		    fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+			return 1;
 	}
 	return 0;
 }
@@ -2530,7 +2532,18 @@
 		 *        but we give normal PCM format to get the existing
 		 *        apps working...
 		 */
-		pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+		switch (chip->usb_id) {
+
+		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+			if (device_setup[chip->index] == 0x00 && 
+			    fp->altsetting == 6)
+				pcm_format = SNDRV_PCM_FORMAT_S16_BE;
+			else
+				pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+			break;
+		default:
+			pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+		}
 	} else {
 		pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
 		if (pcm_format < 0)
@@ -3251,6 +3264,11 @@
 static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
 					 int iface, int altno)
 {
+	/* Reset ALL ifaces to 0 altsetting.
+	 * Call it for every possible altsetting of every interface.
+	 */
+	usb_set_interface(chip->dev, iface, 0);
+
 	if (device_setup[chip->index] & AUDIOPHILE_SET) {
 		if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
 		    && altno != 6)
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 374fbf6..5a2f518 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -57,6 +57,24 @@
 		       USB_DEVICE_ID_MATCH_INT_CLASS |
 		       USB_DEVICE_ID_MATCH_INT_SUBCLASS,
 	.idVendor = 0x046d,
+	.idProduct = 0x08ae,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+		       USB_DEVICE_ID_MATCH_INT_CLASS |
+		       USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+	.idVendor = 0x046d,
+	.idProduct = 0x08c6,
+	.bInterfaceClass = USB_CLASS_AUDIO,
+	.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+		       USB_DEVICE_ID_MATCH_INT_CLASS |
+		       USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+	.idVendor = 0x046d,
 	.idProduct = 0x08f0,
 	.bInterfaceClass = USB_CLASS_AUDIO,
 	.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
@@ -1051,7 +1069,15 @@
 		.type = QUIRK_MIDI_STANDARD_INTERFACE
 	}
 },
-	/* TODO: add Roland EXR support */
+{
+	USB_DEVICE(0x0582, 0x0060),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "EXR Series",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_STANDARD_INTERFACE
+	}
+},
 {
 	/* has ID 0x0067 when not in "Advanced Driver" mode */
 	USB_DEVICE(0x0582, 0x0065),
@@ -1094,6 +1120,19 @@
 		}
 	}
 },
+{
+	USB_DEVICE(0x582, 0x00a6),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "Juno-G",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
 {	/*
 	 * This quirk is for the "Advanced" modes of the Edirol UA-25.
 	 * If the switch is not in an advanced setting, the UA-25 has
@@ -1230,6 +1269,37 @@
 	}
 },
 	/* TODO: add Edirol MD-P1 support */
+{
+	/* Roland SH-201 */
+	USB_DEVICE(0x0582, 0x00ad),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "SH-201",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = (const struct snd_usb_audio_quirk[]) {
+			{
+				.ifnum = 0,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_MIDI_FIXED_ENDPOINT,
+				.data = & (const struct snd_usb_midi_endpoint_info) {
+					.out_cables = 0x0001,
+					.in_cables  = 0x0001
+				}
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
 
 /* Guillemot devices */
 {
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 0a352e4..48e9aa3 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -935,10 +935,9 @@
  */
 static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream)
 {
-	if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {
-		kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
-		usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
-	}
+	kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
+	usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
+
 	kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);
 	usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;
 }